How to convert Float32Array PCM data into Uint8Array?

60 Views Asked by At

I have a AudioBuffer from AudioContext, and I get Float32Array from AudioBuffer.getChannelData,It's in range -1 to 1, and I dont know how to convert the data into Uint8Array, then I can encode it into base64 string.

  const sampleRate = 16000
  const sampleBit = 16
  const context = new AudioContext({
    sampleRate: sampleRate
  })
  const audioSliceMs = 160
  let streamEnd = false
  const audioSliceByte = sampleRate * sampleBit / 8 / 1000 * audioSliceMs
  const recorderScriptNode = context.createScriptProcessor(1024, 1, 1);
  let bufferOffset = 0
  let bufferFloat32Array = new Float32Array(audioSliceByte)
  recorderScriptNode.onaudioprocess = function (audioProcessingEvent) {
    // Float32Array  -1.0 to 1.0 
    const float32Array = audioProcessingEvent.inputBuffer.getChannelData(0)
    // convert here ...
  }

expecting convert code snipet

1

There are 1 best solutions below

3
Lang Yu On BEST ANSWER

To convert the Float32Array data (which is in the range of -1.0 to 1.0) to Uint8Array and then encode it into a base64 string, you need to follow these steps:

  1. Normalize and Scale: The Float32Array values range from -1.0 to 1.0. You need to normalize these values to the range of a 16-bit integer (which is what sampleBit = 16 suggests). This is because the Uint8Array does not directly support 16-bit values. The range for 16-bit integers is -32768 to 32767.
  2. Convert to Int16Array: After scaling, convert these values to Int16Array. This is an intermediate step before converting to Uint8Array.
  3. Convert to Uint8Array: Since each Int16 value is 2 bytes, you need to split each 16-bit integer into two 8-bit integers to store them in a Uint8Array.
  4. Base64 Encoding: Finally, convert the Uint8Array to a base64 string.

Here's a code snippet that demonstrates these steps:

const sampleRate = 16000;
const sampleBit = 16;
const context = new AudioContext({
  sampleRate: sampleRate
});
const audioSliceMs = 160;
let streamEnd = false;
const audioSliceByte = sampleRate * sampleBit / 8 / 1000 * audioSliceMs;
const recorderScriptNode = context.createScriptProcessor(1024, 1, 1);
let bufferOffset = 0;
let bufferFloat32Array = new Float32Array(audioSliceByte);
recorderScriptNode.onaudioprocess = function (audioProcessingEvent) {
  // Get the Float32Array
  const float32Array = audioProcessingEvent.inputBuffer.getChannelData(0);

  // Convert Float32Array to Int16Array
  const int16Array = new Int16Array(float32Array.length);
  for (let i = 0; i < float32Array.length; i++) {
    int16Array[i] = float32Array[i] < 0 ? float32Array[i] * 32768 : float32Array[i] * 32767;
  }

  // Convert Int16Array to Uint8Array
  const uint8Array = new Uint8Array(int16Array.length * 2);
  int16Array.forEach((value, index) => {
    uint8Array[index * 2] = value & 0xff;
    uint8Array[index * 2 + 1] = (value >> 8) & 0xff;
  });

  // Encode to Base64
  const base64String = btoa(String.fromCharCode.apply(null, uint8Array));

  // Convert here ...
  console.log(base64String);
};