Hi,
I need to read and write an 80 bit IEEE extended precision float from
and to AIFF files.
I cant get it to work.
Anyone done this and like to share examples?
Pure ruby preferred. I’d like it to work on both MRI and JRuby.
/Anton
Hi,
I need to read and write an 80 bit IEEE extended precision float from
and to AIFF files.
I cant get it to work.
Anyone done this and like to share examples?
Pure ruby preferred. I’d like it to work on both MRI and JRuby.
/Anton
On Jul 6, 2012, at 6:34 AM, Anton H. [email protected]
wrote:
/Anton
–
Posted via http://www.ruby-forum.com/.
Can you show us what you have tried so far?
Sure.
First, to be more specific, what I’d like is to convert a 80 bit
extended precision float stored in a 10 byte string to and from a ruby
Float. In fact it’s okay if I can convert it to and from a ruby Integer
as I don’t need any decimals. Sample rate of AIFF sound file is stored
as an 80 bit extended precision float. I don’t know why because mostly
this is an integer value and I’d be happy with an Integer.
I’ve tried to convert the read_ieee_extended and write_ieee_extended
methods of the following java class:
http://www.docjar.com/html/api/com/sun/media/sound/AiffFileReader.java.html
I’ve changed float input and output to integer.
Method read_ieee_extended seem to work fine. I’ve tried it with two
different AIF files.
def read_ieee_extended(str)
arr = str.unpack(“n5”)
exponent = arr[0]
hi_mantissa = arr[1] << 16 | arr[2]
lo_mantissa = arr[3] << 16 | arr[4]
if exponent == 0 and hi_mantissa == 0 and lo_mantissa == 0
0
else
if exponent == 0x7FFF
3.40282346638528860e+38
else
exponent -= 16383
exponent -= 31
f = hi_mantissa * (2exponent)
exponent -= 32
f += lo_mantissa * (2exponent)
f
end
end.to_i
end
Method write_ieee_extended has errors:
def write_ieee_extended(i)
unsigned_short_max = 0b1111111111111111
unsigned_int_max = 0b11111111111111111111111111111111
lo_mantissa = 0
exponent = 16398
hi_mantissa = i
while hi_mantissa < 44000
hi_mantissa *= 2
exponent -= 1
end
hi_mantissa = ((hi_mantissa & unsigned_int_max) << 16) &
unsigned_int_max
arr = [exponent, hi_mantissa >> 16, hi_mantissa & unsigned_short_max,
lo_mantissa >> 16, lo_mantissa & unsigned_short_max]
arr.pack(“n5”)
end
These are quick ugly hacks. Any help is appreciated, thanks. ![]()
/Anton
Anton H. wrote in post #1067670:
I need to read and write an 80 bit IEEE extended precision float from
and to AIFF files.
What do you want to read it into? A ruby Float is just a double, you
will lose precision. Is that acceptable, or do you want to read into a
BigDecimal, or something else?
here also are example usages of the methods above…
irb>a = “@\016\254D\000\000\000\000\000\000” # = 44100
irb>b = “@\017\200\000\000\000\000\000\000\000” # = 65536
irb>read_ieee_extended a
=> 44100
(ok)
irb>read_ieee_extended b
=> 65536
(ok)
irb>write_ieee_extended 44100
=> “@\016\254D\000\000\000\000\000\000”
(ok)
irb>write_ieee_extended 65536
=> “@\016\000\000\000\000\000\000\000\000”
(error)
/Anton
On 07.07.2012 09:11, Anton H. wrote:
I guess this is quite simple. I just cant get my head around the
description in the wikipedia page. Yet.
Maybe GitHub - tadman/raiff: Ruby AIFF Parsing Library can give you an idea …?
HTH
Brian C. wrote in post #1067753:
What do you want to read it into? A ruby Float is just a double, you
will lose precision. Is that acceptable, or do you want to read into a
BigDecimal, or something else?
See my second post. It’s okay to lose precision. In fact, a ruby Integer
value is fine. Sample rates of sound files are typically integers. I
cant understand why a 80 bit float value is used for AIF. The common WAV
file format uses integers for sample rate.
I guess this is quite simple. I just cant get my head around the
description in the wikipedia page. Yet.
/Anton
And for 44100, my C program gives
00 00 00 00 00 00 44 ac 0e 40 00 00 00 00 00 00
(this looks to be the opposite byte ordering of your example)
str="\x00\x00\x00\x00\x00\x00\x44\xac\x0e\x40"
mant, exp = str.unpack(“QS”)
mant * 2.0 ** (exp-16446)
=> 44100.0
Anton H. wrote in post #1067775:
I guess this is quite simple. I just cant get my head around the
description in the wikipedia page. Yet.
“The standard specifies the minimum requirements for an extended format
but does not specify an encoding.[5] The encoding is the implementor’s
choice.”
So it’s undefined. Do you have some sample values, and know what they
translate to?
As a test, let’s see what GCC gives.
#include <stdio.h>
int main(void)
{
long double foo = 12.5;
unsigned char *p = (unsigned char *)&foo;
int i;
for (i=0; i<sizeof(foo); i++) {
printf(“%02x “, p[i]);
}
printf(”\n”);
return 0;
}
This gives me a value padded to 16 bytes. Taking the first 10 bytes:
str = “\x00\x00\x00\x00\x00\x00\x00\xc8\x02\x40”
mant, exp = str.unpack(“QS”)
=> [14411518807585587200, 16386]
“%064b” % mant
=> “1100100000000000000000000000000000000000000000000000000000000000”
“%016b” % exp
=> “0100000000000010”
(i.e. zero sign, exponent = 16384+2)
The value we want is:
mant / (2.063) * 2.0(exp-16383)
=> 12.5
or equivalently:
mant * 2.0 ** (exp-16446)
=> 12.5
Note that unpack(“Q”) depends on the endianness of the system running
the code, so this isn’t portable to big-endian processors.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.
Sponsor our Newsletter | Privacy Policy | Terms of Service | Remote Ruby Jobs