Is it possible to correctly convert Float32Array to Int32Array without testing each float?

90 Views Asked by At

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 a Float32Array with values between -1.0 and 1.0. lamejs expects values between -32768 and 32767, 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?

1

There are 1 best solutions below

2
guest271314 On

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!

# Int to Float Float to Int* Transparency Used By
0) ((integer + .5)/(0x7FFF+.5) float*(0x7FFF+.5)-.5 Up to at least 24-bit DC DAC Modeled
1) (integer / 0x8000) float * 0x8000 Up to at least 24-bit Apple (Core Audio)1, ALSA2, MatLab2, sndlib2
2) (integer / 0x7FFF) float * 0x7FFF Up to at least 24-bit Pulse Audio2
3) (integer / 0x8000) float * 0x7FFF Non-transparent PortAudio1,2, Jack2, libsndfile1,3
4) (integer>0?integer/0x7FFF:integer/0x8000) float>0?float*0x7FFF:float*0x8000 Up to at least 24-bit At least one high end DSP and A/D/A manufacturer.2,4 XO Wave 1.0.3.
5) Unknown float*(0x7FFF+.49999) Unknown ASIO2

*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