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.
source to share
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.
source to share
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.
source to share