Function writeWAVFile
Writes an audio data array to a WAV file on disk.
void writeWAVFile(T)
(
string filePath,
const T[] audioData,
uint sampleRate,
ushort numChannels
)
if (is(T == ubyte) || is(T == byte) || is(T == short) || is(T == int) || is(T == float));
This function generates a WAV file format byte array using toWAVFile()
and
writes it to a specified file path.
Parameters
Name | Description |
---|---|
filePath | The path where the WAV file should be written. |
audioData | The raw audio data to be written. |
sampleRate | The sampling rate of the audio data. |
numChannels | The number of audio channels (1 for mono, 2 for stereo). |
Example
Unit tests for the WAV audio module.
import std .array : array;
import std .stdio : writefln;
import std .file : remove;
/// RIFF (little-endian) data, WAVE audio, IEEE Float, mono 44100 Hz
enum string reffile_32f = "tests/wav_audio_ref_32f.wav";
/// RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 44100 Hz
enum string reffile_s16pcm = "tests/wav_audio_ref_s16pcm.wav";
/// RIFF (little-endian) data, WAVE audio, Microsoft PCM, 32 bit, mono 44100 Hz
enum string reffile_s32pcm = "tests/wav_audio_ref_s32pcm.wav";
/// RIFF (little-endian) data, WAVE audio, Microsoft PCM, 8 bit, mono 44100 Hz
enum string reffile_u8pcm = "tests/wav_audio_ref_u8pcm.wav";
enum string testfile_32f = "tests/tmp/wav_audio_32f.wav";
enum string testfile_s16pcm = "tests/tmp/wav_audio_s16pcm.wav";
enum string testfile_s32pcm = "tests/tmp/wav_audio_s32pcm.wav";
enum string testfile_u8pcm = "tests/tmp/wav_audio_u8pcm.wav";
enum testFreq = 441; // This does evenly divide the samplerate, eases the test
enum sampleRate = 44_100;
enum Duration cycleDur = dur!"hnsecs"(10 ^^ 7 / testFreq);
// pragma(msg, cycleDur);
// writeln(cycleDur);
ubyte[] readFileAsUbyte(string filePath) {
import std .file : read;
return cast(ubyte[]) read(filePath);
}
void dumpDiff(ubyte[] testWAV, ubyte[] expectedWAV) {
if (testWAV != expectedWAV) {
write(toRawDataDiff(testWAV, expectedWAV, "TEST:\n", "EXPECT:\n"));
}
}
// writeln("START OF byte DUMP:");
{
byte[] audioData = generateSinus!byte(testFreq .to!float, 1.0, cycleDur, sampleRate);
assert(audioData .length == 100, "One cycle of 441Hz at 44100kHz is 100 bytes.");
writeWAVFile(testfile_u8pcm, audioData, sampleRate, 1);
ubyte[] testWAV = readFileAsUbyte(testfile_u8pcm);
ubyte[] expectedWAV = readFileAsUbyte(reffile_u8pcm);
dumpDiff(testWAV, expectedWAV);
assert(testWAV == expectedWAV, "The written WAV file does not match the expected data.");
}
// writeln("START OF short DUMP:");
{
short[] audioData = generateSinus!short(testFreq .to!float, 1.0, cycleDur, sampleRate);
assert(audioData .length == 100, "One cycle of 441Hz at 44100kHz is 100 bytes.");
writeWAVFile(testfile_s16pcm, audioData, sampleRate, 1);
ubyte[] testWAV = readFileAsUbyte(testfile_s16pcm);
ubyte[] expectedWAV = readFileAsUbyte(reffile_s16pcm);
dumpDiff(testWAV, expectedWAV);
assert(testWAV == expectedWAV, "The written WAV file does not match the expected data.");
}
// writeln("START OF int DUMP:");
{
int[] audioData = generateSinus!int(testFreq .to!float, 1.0, cycleDur, sampleRate);
assert(audioData .length == 100, "One cycle of 441Hz at 44100kHz is 100 bytes.");
writeWAVFile(testfile_s32pcm, audioData, sampleRate, 1);
ubyte[] testWAV = readFileAsUbyte(testfile_s32pcm);
ubyte[] expectedWAV = readFileAsUbyte(reffile_s32pcm);
dumpDiff(testWAV, expectedWAV);
assert(testWAV == expectedWAV, "The written WAV file does not match the expected data.");
}
// writeln("START OF float DUMP:");
{
float[] audioData = generateSinus!float(testFreq .to!float, 1.0, cycleDur, sampleRate);
assert(audioData .length == 100, "One cycle of 441Hz at 44100kHz is 100 bytes.");
writeWAVFile(testfile_32f, audioData, sampleRate, 1);
ubyte[] testWAV = readFileAsUbyte(testfile_32f);
ubyte[] expectedWAV = readFileAsUbyte(reffile_32f);
testWAV[0x3c .. 0x40] = 0; // This is seconds since epoche - it is dynamically updated by tools, so we set it to 0 for compare.
expectedWAV[0x3c .. 0x40] = 0;
version (DigitalMars) {
writefln("CAUTION: DMD gives different binary results here. @0x%x test:%s != expect:%s",
0x118, testWAV[0x118..0x120], expectedWAV[0x118..0x120]);
float tval = *(cast(float*)&testWAV[0x118]);
float eval = *(cast(float*)&expectedWAV[0x118]);
writefln("CAUTION: This binaries represent 'IEEE 754 float' test:%f and expect:%f", tval, eval);
testWAV[0x118 .. 0x120] = expectedWAV[0x118 .. 0x120];
}
dumpDiff(testWAV, expectedWAV);
assert(testWAV == expectedWAV, "The written WAV file does not match the expected data.");
}