-
Logical Problems
I am trying to read a flac file, and the format specifies that the sample rate is stored as a 20 bit number.
I have found the 3 bytes that this pertains to: 0x0A 0xC4 0x42
Now from online calculators, I have tested my AND operation to strip off the last 4 bits, because these are 8 bit bytes.
0x0AC442(hex) & 0xFFFFF0(hex) = 705600(dec), however, there are still 4 bits of 0 in there
705600(dec) = 10101100010001000000(bin)
I'm actually looking for it with those trimmed off
1010110001000100(bin) = 44100(dec)
So the sample rate I'm looking for is 44100 Hz or 44.1 kHz.
I'm having a really hard time doing this in C. Endianness and other factors are confusing the hell out of me.
Here is how I am trying it:
Code:
char num[9] = {0};
unsigned long sample_rate = 0; //sizeof on my system = 4
...
memcpy(&num, &data[pos], 3);//this copies the next 3 bytes of my buffer into a byte array
sample_rate = num[0] << 16 | num[1] << 8 | num[2]; //num[0] = 0x0A, num[1] = 0xC4, num[2] = 0x42
sample_rate = sample_rate & 0xFFFFF0
printf("Sample Rate = %lu\n", sample_rate);
This is giving me the result of "Sample Rate = 16761920", so I'm obviously doing something wrong.
Thanks for any help you guys can provide!
-
Code:
sample_rate = sample_rate & 0xFFFFF0
Right shift by 4 is what you need to do here.
-
You're missing a shift right by four bits (705600 / 16.0 = 44100), and you also happen to be missing some required brackets to get the precedence right.
An easier way to do it would be:
Code:
sample_rate = (num[0] << 12) | (num[1] << 4) | (num[2] >> 4);
No masking required.
Although you should make sure you declare num as unsigned char to ensure that always works.
-
Thanks for both of your input. It was a stupid little error like I thought.
iMalc: That is really clever, I'm going to have to revise some other parts of my program as well.
-
Hey I've got another quick question. I got a little curious with bitshifting tricks and was trying to do it on the next part, but have failed. I could AND my calculations, but I want to get a firm grasp on bit shifting.
The next bit of information is the bits/sample, which is a number that only has 5 bits that span through these two bytes:
0x42 = 01000010
0xF0 = 11110000
The number consists of the last bit (furthest right) of 0x42 and the first 4 bits of 0xF0.
So the bits/sample should be 0x0F = 00001111. (the bold will always be 0 due to specs, only 5 bit sized number)
I seem to do well with shifting with 4-8-12 bit shifts, but for some reason I can't get this one. I feel like I need to shift 0x42 left 7, or with 0xF0 shifted left 6, and then shift all right 6.
Code:
bps = ((0x42 << 7) | (0xF0 >> 4)) >> 6
But that seems to be wrong and I just need a little explanation.
-
So, what you want to do is put the lowest bit of 0x42 into the highest of an
intermediary, unsigned byte. Put the top half of 0xF0 into the next four bits. And as the
five right-most bits make up the bps, you'll need to shift right by three.
Code:
bps = ((0x42 << 7) | (0xF0 >> 1)) >> 3
-
Also, you need to watch signed vs. unsigned when doing shifts. If you do a right shift on a signed value, and the MSB is 1, it will result in 1's being pushed on the left side instead of 0's. This is meant to preserve the number's sign.