Convert Float32Array to Uint8Array while preserving IEEE 754 representation
I have a float32Array method from decodeAudioData that I want to convert to Uint8Array and store the audio data float32 IEEE 754 .
So far I've tried
var length = float32Array.length;
var emptyBuffer = new ArrayBuffer(length * 4);
var view = new DataView(emptyBuffer);
for (var i = 0; i < length; i++) {
view.setFloat32(i * 4, float32Array[i], true);
}
var outputArray = new Uint8Array(length);
for (var j = 0; j < length; j++) {
outputArray[j] = view.getUint8(j * 4);
}
return outputArray;
Edit:
I just need to keep the binary representation the same as in this answer.
var output = new Uint8Array(float32Array.length);
for (var i = 0; i < float32Array.length; i++) {
var tmp = Math.max(-1, Math.min(1, float32Array[i]));
tmp = tmp < 0 ? (tmp * 0x8000) : (tmp * 0x7FFF);
tmp = tmp / 256;
output[i] = tmp + 128;
}
return output;
Anyone who has doubts about it can easily check it with Audacity Import Raw Data.
- Download the raw data sample that I decoded from the video file using the Web Audio Api decodeAudioData method.
-
Convert a Float32Array in which raw data samples are filled with a Uint8Array using the method above (or use your own method, for example
new Uint8Array(float32Array.buffer)
, to hear corrupted audio) and load the uint8 pcm file.forceDownload(new Blob([output], { type: 'application/octet-binary' }));
-
Encode the loaded data in Audacity with File-> Import -> Raw Data ... Encoding should be set to Unsigned 8-bit PCM and the sampling rate should be 16000 Hz since the original decoded audio file was at 16000 Hz.
It is not very clear what you are asking; or rather, what you seem to be asking for is a thing that doesn't make any sense.
A Float32Array
instance is a buffer representation of "raw" byte values, like all typed arrays. Each element in the array represents 4 of these raw bytes. Retrieving a value using a simple array lookup:
var n = float32array[1];
implicitly interprets these 4 bytes as a 32-bit IEEE floating point value, and then this value is converted to a standard JavaScript number. JavaScript numbers are always 64-bit IEEE floating point values.
Likewise, a Uint8Array
is a buffer representation and each element gives an unsigned integer of one byte. I.e
var n = uint8array[1];
accesses this element, interprets it as an unsigned single-byte integer, and converts it to a JavaScript number.
So: if you want to view a list of 32-bit floating point values ββas the raw integer value of each byte, you can create Uint8Array
one that "shares" the same buffer as Float32Array
:
var uintShared = new Uint8Array(float32array.buffer);
The numbers you see when you view the values Uint8Array
will have nothing to do with the amount you get from viewing the items Float32Array
, as you would expect.
On the other hand, if you want to create a new one Uint8Array
to store the visible values ββfrom Float32Array
, you can simply create a new array with the same length and copy each value:
var uintCopy = new Uint8Array(float32array.length);
for (let i = 0; i < float32array.length; ++i)
uintCopy[i] = float32array[i]; // deeply problematic; see below
Now this won't work too well, in general, because the numeric range of values ββin is Float32Array
significantly larger than the number of values ββin Uint8Array
. On the one hand, 32-bit floating point values ββcan be negative. What's more, even if you know that floating point values ββare integers between 0 and 255, you definitely won't get the same bit patterns in Uint8Array
for the simple reason that a 32-bit floating point number is simply not the same. that's an 8-bit unsigned integer. "Save IEEE-754 representation" doesn't make sense.
So, the reality of the situation. If you could explain why you think you want to somehow insert all 32 bits of an IEEE 32-bit float into an 8-bit unsigned integer, a more convenient answer could be provided.