encodeWav function

Uint8List encodeWav(
  1. PcmAudio audio
)

Encodes audio as a canonical 16-bit PCM WAV (RIFF) file.

The result is a standard little-endian WAV with a 44-byte header and the interleaved samples, playable by any audio tool and a convenient bridge to the rest of the ecosystem. This is a pure-Dart writer; it never calls into native code.

final pcm = decodeMp3(await File('clip.mp3').readAsBytes());
await File('clip.wav').writeAsBytes(encodeWav(pcm));

Implementation

Uint8List encodeWav(PcmAudio audio) {
  const headerSize = 44;
  const bitsPerSample = 16;
  const bytesPerSample = bitsPerSample ~/ 8;
  final channels = audio.channels;
  final sampleRate = audio.sampleRate;
  final dataLength = audio.samples.length * bytesPerSample;
  final byteRate = sampleRate * channels * bytesPerSample;
  final blockAlign = channels * bytesPerSample;

  final bytes = Uint8List(headerSize + dataLength);
  final view = ByteData.sublistView(bytes);

  // RIFF chunk descriptor.
  _writeAscii(bytes, 0, 'RIFF');
  view.setUint32(4, 36 + dataLength, Endian.little);
  _writeAscii(bytes, 8, 'WAVE');

  // fmt sub-chunk.
  _writeAscii(bytes, 12, 'fmt ');
  view.setUint32(16, 16, Endian.little); // PCM fmt chunk size
  view.setUint16(20, 1, Endian.little); // audio format 1 = PCM
  view.setUint16(22, channels, Endian.little);
  view.setUint32(24, sampleRate, Endian.little);
  view.setUint32(28, byteRate, Endian.little);
  view.setUint16(32, blockAlign, Endian.little);
  view.setUint16(34, bitsPerSample, Endian.little);

  // data sub-chunk.
  _writeAscii(bytes, 36, 'data');
  view.setUint32(40, dataLength, Endian.little);
  for (var i = 0; i < audio.samples.length; i++) {
    view.setInt16(
      headerSize + i * bytesPerSample,
      audio.samples[i],
      Endian.little,
    );
  }
  return bytes;
}