I'm currently using the following code to convert a Float32Array to an Int32Array for audio processing.
const int32 = new Int32Array(
[...new Float32Array(buffer)].map((float) => {
return float < 0 ? float * 32768 : float * 32767
})
Notice the ternary which checks if the float is less than 0, if true multiplies the float by 32768, else if false multiples the float by 32767.
There are different vaersions of that code in the wild, e.g., the above is the way I wound up writing this https://github.com/zhuker/lamejs/commit/e18447fefc4b581e33a89bd6a51a4fbf1b3e1660
# Usage with Float32Array / AudioBuffer
Some libraries (such as
AudioBuffer.getChannelData()from the WebAudio API) provide audio data as aFloat32Arraywith values between-1.0and1.0. lamejs expects values between-32768and32767, so the values have to be mapped:var floatSamples = new Float32Array(44100); // Float sample from an external source var samples = new Int32Array(floatSamples.length); for (var i = 0; i < floatSamples.length; i++) { samples[i] = floatSamples[i] < 0 ? floatSamples[i] * 32768 : floatSamples[i] * 32767; }
See also this post which converts Float32Array to Int16Array https://github.com/zhuker/lamejs/issues/55#issuecomment-1959182758
// Interpolate to -32768 to 32767, which is signed int16
const interpolated = leftChannel.map((n) =>
Math.max(-32768, Math.min(32768, n * (n < 0 ? 32768 : 32767)))
);
What I'm trying to do is find out the shortest code, in characters, to achieve the expected result.
Is there are way to perform this conversion correctly without checking each individual float in the Float32Array?
Doesn't look like there is a way to directly convert floats to integers or integers to floats - correctly - without iterating over all values in a
TypedArray.Neil was kind enough to locate and share this blog post which contains a few conversion algorithms used by applications that deal with sound Int->Float->Int: It's a jungle out there!
((integer + .5)/(0x7FFF+.5)float*(0x7FFF+.5)-.5(integer / 0x8000)float * 0x8000(integer / 0x7FFF)float * 0x7FFF(integer / 0x8000)float * 0x7FFF(integer>0?integer/0x7FFF:integer/0x8000)float>0?float*0x7FFF:float*0x8000float*(0x7FFF+.49999)*obviously, rounding or dithering may be required here.
Note that in the case of IO APIs, drivers are often responsible for conversions. The conversions listed here are provided by the API.
Edited December 6, 2009: Fixed Method 3. (0x8000 and 0x7FFF were backwards)
Sources:
1 Mailing list
2 Perusing the source code (this, of course, is subject to mistakes due to following old, conditional or optional code)
3 libsndfile FAQ goes into detail about this.
4 Personal communication.
Posted by Bjorn Roche at 1:51 PM