JavaScript - AudioBuffer to Wav

發文於 2024-10-08 由 JTH


async function audioBufferToWav2(audioBuffer) {
  
  const numChannels = audioBuffer.numberOfChannels;
  const sampleRate = audioBuffer.sampleRate;
  const numSamples = audioBuffer.length;

  // 計算 WAV 檔案的總字節長度
  const byteLength = 44 + numSamples * numChannels * 2; // 44 bytes for header and 16-bit samples
  const buffer = new ArrayBuffer(byteLength);
  const view = new DataView(buffer);

  // 寫入 WAV 頭部
  writeString(view, 0, "RIFF");
  view.setUint32(4, byteLength - 8, true); // 4 bytes for 'RIFF' + file size
  writeString(view, 8, "WAVE");
  writeString(view, 12, "fmt ");
  view.setUint32(16, 16, true); // Subchunk1Size for PCM
  view.setUint16(20, 1, true); // AudioFormat (PCM)
  view.setUint16(22, numChannels, true); // Number of Channels
  view.setUint32(24, sampleRate, true); // SampleRate
  view.setUint32(28, sampleRate * numChannels * 2, true); // ByteRate
  view.setUint16(32, numChannels * 2, true); // BlockAlign
  view.setUint16(34, 16, true); // BitsPerSample
  writeString(view, 36, "data");
  view.setUint32(40, numSamples * numChannels * 2, true); // Subchunk2Size

  // 寫入音頻數據
  for (let i = 0; i < numChannels; i++) {
      const channelData = audioBuffer.getChannelData(i);
      for (let j = 0; j < numSamples; j++) {
          // 格式轉換:將浮點值(-1.0 到 1.0)轉換為 16 位整數
          view.setInt16(44 + j * numChannels * 2 + i * 2, channelData[j] * 0x7fff, true);
      }
  }

  return new Blob([view], { type: 'audio/wav' });
}