3

I've spent too many hours on this, and at this point I think I need some help from the experts.

I have a const uint8_t* buffer, an integer data type (say, uint16_t), and I know that the buffer contains packed samples m bits each where m is not divisible by 8 (say, m=12 bits). Knowing that buffer holds N samples, I need to return an std::vector<uint16_t> containing the values of these N samples expanded to uint16_t.

So, each three bytes (24 bits) of the buffer contain two 12-bits samples I need to process. I want to implement a generalized function

template <typename OutputType, int BitsPerSample>
std::vector<OutputType> unpack(const uint8_t* data, const size_t numSamplesToUnpack);

Assume the data is big endian and OutputType is some integer type that can hold the sample value without truncating it.

I understand bit manipulation. I understand how this can be implemented, in principle. But I don't understand how to implement it elegantly and concisely. Got any ideas?

Also, is there a special name or term for this problem?

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • 2
    Did you check `boost::transform_width` ? – Slava Jun 05 '18 at 20:46
  • This could be related https://stackoverflow.com/questions/7053538/how-do-i-encode-a-string-to-base64-using-only-boost – Slava Jun 05 '18 at 20:47
  • @Slava: not before you pointed it out (I don't have `boost` in this project, nor do I want to pull it in). That's... a lot of code. Kinda looks like what I would write naively, except it's even more generalized and abstracted. – Violet Giraffe Jun 05 '18 at 20:48
  • 3
    Asking for "implement it elegantly and concisely. Got any ideas?" makes this "opinion-based". Also,first thing that cames to my mind is, "what have you tried"? If you've spent X hours,surely you have some moreorless broken pieces of code. Maybe show them and fix them here? Also,is your goal just to solve it,or to take the excercise and implement it yourself? Also, how complex do you want it to have? what OutputTypes do you want to support and how they can be constructed and/or filled? Also,is `data` BigEndian, LittleEndian? Far too many unknowns and it all impacts elegancy/verbosity.. – quetzalcoatl Jun 05 '18 at 20:50
  • @quetzalcoatl: I will expand the question. Note that while you're not wrong about it being opinion-based, I'm not asking for complete implementation, just for approaches I could try (but eventually I just need it to work, it's not an exercise, it's a real-world problem). – Violet Giraffe Jun 05 '18 at 20:53
  • @quetzalcoatl: as for what I have tried - nothing I finished because it's becoming too many lines of code too quickly, and I've already spent ungodly amount of time without even getting a debuggable implementation. I strongly suspect there are simpler ways than the one I saw. – Violet Giraffe Jun 05 '18 at 20:56
  • Depending on your actual requirements, `numberOfSamplesToUnpack` may be a run-time, not compile-time decision. –  Jun 05 '18 at 20:58
  • @Arkadiy: fair enough, that's an unnecessary restriction, let me edit the question. – Violet Giraffe Jun 05 '18 at 20:59

2 Answers2

0

Maybe you can try reading single bits at a time, and keep a running counter of how many bits you have processed. When you consume 8 bits, you can increment your buffer pointer.

This doesn't mean you have finished unpacking that sample, so you'll need to also keep a "bits_left" counter in case you need to shift the buffer pointer before you are done unpacking a sample.

MPops
  • 355
  • 3
  • 8
  • Hmm, I didn't consider literally reading single bits rather than chunks. – Violet Giraffe Jun 05 '18 at 21:36
  • 1
    I mean, for the sake of speed, you can optimize it to actually read in chunks, but then you need to make sure you deal with remainder bits left over. (say a 9 bit sample, you can read in a byte followed by 1 bit). This might not be possible if the sample size is smaller than a byte, so... – MPops Jun 05 '18 at 22:08
0

Use a 32-bit word as a buffer. If it has less than 12 bits, read another byte. Otherwise, output a 12-bit word.

Falk Hüffner
  • 4,942
  • 19
  • 25