AIFF's 80-bit sample rate value
Hi everyone,
Using Javascript's File functions I'm trying to extract the sample rate from the AIFF file COMM chunk. Looking at the AIFF specification (http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/Docs/AIFF-1.3.pdf) this value is stored as an extended 80-bit float. Having done some digging around on the subject I have found that this value is formatted with the first 16-bits representing the exponent and the remaining 64-bits representing the mantissa (as documented here: http://www.cs.trinity.edu/About/The_Courses/cs2321/ieee-fp.html).
Using the readfloat16() and readfloat64() functions I can get the two values. But how do I combine them into one float? And, staying in the JS environment, is there a simpler method?
Thanks,
Adam Jansch
Just an update...
I should be reading the values in as ints, not floats. But of course Javascript doesn't work with 64-bit ints at this point (hence the lack of a readint64() function), and so even reading the 64-bit significand value in as two 32-values and adding while bitshifting won't get me out of this one so easily.
I found a slightly better source regarding these 80-bit monsters, here it is for posterity: http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
Adam Jansch
It has been over a month and I finally figured out how to do this (let it be noted that I haven't spent the whole month working on this problem!). I am posting my solution for anyone mad enough to want to do the same.
Using info from here (http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/) I figured out that the first 16-bit block of the 80 represents the bit depth of the second 16-bit block... a little bit of explanation required:
For 44100Hz and 48000Hz files the first 16-bits is always 16398. When 16382 is subtracted from this the result is the bit length of the value that holds the sample rate - in this case 16. For 96000Hz this value is 16399 and for 192000Hz it is 16400.
The next 16-bit value of the 80 represents the base sample rate. As an unsigned 16-bit int it would be 44100 for 44100, 88200 and 176400Hz files, and 48000 for 48000, 96000 and 192000Hz files. This value must be read in via the readbytes() command and reconstructed in Javascript using bit shifting (as readint16() only reads in as signed values).
This is the interesting part... you use the first value retrieved to create a lowest-significant-bit pad for the second value, thus allowing it scale up into the higher sample rates: subtracting 16398 from the first value creates the number of bits of the pad, the bit shift (to the left) the second value by the first and you have the correct file sample rate!
A quick example: for a 96000Hz file the first 16-bit value is 16399. Subtract 16398 from this to get your LSB pad, in this case 1.
Read the second 16-bit as 2 bytes (readbytes(2)), in this case the values 187 and 128. Bit shift 187 left by 8 bits (187 << 8 = 47872) and add the 128 (48000).
Then bit shift that value using the LSB pad, so 48000 << 1 = 96000.
The code for this is attached.
wow this is convoluted... I think there is an interesting historical coding study to do here, to find the motivation of such a convoluted way of doing things...
in all case, bravo!
pa
Hi there, you said in your case above that the "code is attached", but I don't see it here. Is there any way you could share it ?
Either way, extremely helpful work, thank you so much.
Maybe this helps: http://www.onicos.com/staff/iz/formats/ieee.c
Thanks for this nice piece of valuable information. By working with aiff files with low samplerates, I found out something more: subtracting 16398 from the first value you might get a negative value, e.g. -2.
In this case you need to right shift the second value (frequency base) instead of left shifting it.
Example: 44100 >> abs(-2) = 11025 Hz.
With a positive value of 2 you have instead to proceed like this:
44100 << 2 = 176400 Hz.
Thanks!