Jump to content
  • Advertisement
Sign in to follow this  
DrTwox

Reading 1 bit?

This topic is 3701 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, newbie C programmer here with a request for help. I'm attempting to write a very simple ogg vorbis comments extractor in C, but I've run into a problem. So far, I can read in the ogg container header (http://xiph.org/ogg/doc/framing.html), then the vorbis common header (http://xiph.org/vorbis/doc/Vorbis_I_spec.html#vorbis-spec-codec), but I'm stuck at the end of the identification header. The above document describes the header like so: 1) [vorbis_version] = read 32 bits as unsigned integer 2) [audio_channels] = read 8 bit integer as unsigned 3) [audio_sample_rate] = read 32 bits as unsigned integer 4) [bitrate_maximum] = read 32 bits as signed integer 5) [bitrate_nominal] = read 32 bits as signed integer 6) [bitrate_minimum] = read 32 bits as signed integer 7) [blocksize_0] = 2 exponent (read 4 bits as unsigned integer) 8) [blocksize_1] = 2 exponent (read 4 bits as unsigned integer) 9) [framing_flag] = read one bit I can fread parts 1-6 into a struct, which prints the relevent information correctly, but how on earth does one read 7-9? I'm guessing that blocksize_0 and blocksize_1 are read into a single unsigned int and I'm supposed to use bit twiddling to get the relevant information? What about 9, the one bit framing_flag. How can you read 1 bit when the smallest size is an 8bit char? Note: I know I could use libogg and libvorbis to do this properly, but this is more of a learning exercise. I don't want to decode the audio, just read the headers. I also know I could just skip to the comments header and start reading from there, but that would be too easy! ;)

Share this post


Link to post
Share on other sites
Advertisement
Yeah, for the 4-bit values, just read in a byte, b, then get your values out of it.
blocksize0 = (b & 0xF0) >> 4;
blocksize1 = (b & 0x0F);

For the other one, I guess you can read the next byte and get the bit...
onebit = b >> 7;

I guess endianness could be a factor also. I'm not thinking clearly right now. :-)

Share this post


Link to post
Share on other sites
Quote:
Original post by DrTwox
I can fread parts 1-6 into a struct, which prints the relevent information correctly, but how on earth does one read 7-9? I'm guessing that blocksize_0 and blocksize_1 are read into a single unsigned int and I'm supposed to use bit twiddling to get the relevant information?

Indeed. You mask the information you want, and then shift it downwards by the appropriate amount.

Quote:
What about 9, the one bit framing_flag. How can you read 1 bit when the smallest size is an 8bit char?

Again, just masking and shifting. However in the case of a single bit (typically a boolean flag), you don't need to do the shift, since after masking you'll either be left with a single 1 bit (which produces a non-zero value), or no 1 bits, which is zero.

Share this post


Link to post
Share on other sites
You could also create a structure for the entire header, with a bitfield at the end. Than you would be able to read in the entire structure with one call to fread.

Share this post


Link to post
Share on other sites
Quote:
Original post by caseyd
You could also create a structure for the entire header, with a bitfield at the end. Than you would be able to read in the entire structure with one call to fread.


This wont work due to the fact that bit fields are downright useless in C and C++.

"The packing order, and whether or not a bitfield may cross a storage unit boundary, are implementation defined."

That is to say that the fields in a bit field may not necessarily be tightly packed (eg. may contain gaps) in addition to fields being stored in a different order than you specified in the struct definition.

Share this post


Link to post
Share on other sites
I believe MSVC supports pragma pack

#pragma pack(push,1) // push one byte packing
struct OggHeader
{
unsigned int vorbis_version;
unsigned char audio_channels;
unsigned int audio_sample_rate;
unsigned int bitrate_maximum;
unsigned int bitrate_nominal;
unsigned int bitrate_minimum;
unsigned char blocksize_0 : 4;
unsigned char blocksize_1 : 4;
unsigned char framing_flag : 1;
// should be 23 bytes (int * 5 + char*3)
};
#pragma pack(pop)

int main(int argc, char* argv[])
{
// prints "23, 23"
printf ("%d, %d\n", sizeof (unsigned int) * 5 + sizeof(unsigned char)*3, sizeof (OggHeader));
system ("pause");
return 0;
}

?

Share this post


Link to post
Share on other sites
I'd avoid trying to wrap a structure round that data, mostly because it's not very flexible (and is highly platform and compiler dependant). Here's a couple of functions that let you read arbitrary numbers of bits from an array. Note that I've not done any error checking for going off the end of the data (and I've not tested it, so there may be some bugs but the idea should be clear):


unsigned char *pData;
unsigned int nByte = 0;
unsigned int nBit = 0;

// Read the next bit from the array. Returns either 0 or 1
int ReadBit(void)
{
int result = (pData[nByte] >> nBit) & 1;

nBit++;

// This is a branchless version of: if (nBit > 7) { nByte++; nBit = 0; }
nByte += nBit >> 3;
nBit &= 7;

return result;
}

// Read a multi-bit value and return it in a signed integer
int ReadValue(int NumBits)
{
int result = 0;
for (int i=0; i < NumBits; i++)
{
result |= ReadBit() << i;
}
return result;
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!