encodeWav function
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;
}