As an excuse to learn C#, I have been trying to code a simple project: creating audio files. To start, I want to make sure that I can write files that meet the WAVE format. I have researched the format online (for example, here), but whenever I try to play back a file, it won't open correctly. Here is my code. Is something missing or incorrect?
uint numsamples = 44100;
ushort numchannels = 1;
ushort samplelength = 1; // in bytes
uint samplerate = 22050;
FileStream f = new FileStream("a.wav", FileMode.Create);
BinaryWriter wr = new BinaryWriter(f);
wr.Write("RIFF");
wr.Write(36 + numsamples * numchannels * samplelength);
wr.Write("WAVEfmt ");
wr.Write(16);
wr.Write((ushort)1);
wr.Write(numchannels);
wr.Write(samplerate);
wr.Write(samplerate * samplelength * numchannels);
wr.Write(samplelength * numchannels);
wr.Write((ushort)(8 * samplelength));
wr.Write("data");
wr.Write(numsamples * samplelength);
// for now, just a square wave
Waveform a = new Waveform(440, 50);
double t = 0.0;
for (int i = 0; i < numsamples; i++, t += 1.0 / samplerate)
{
wr.Write((byte)((a.sample(t) + (samplelength == 1 ? 128 : 0)) & 0xff));
}
The major problem is:
BinaryWriter.Write(string)
writes a string that is prefixed with it's length for BinaryReader
to read it back. It is not intended to be used like your case. You need to write the bytes directly instead of using BinaryWriter.Write(string)
.
What you should do:
Convert the string into bytes and then write the bytes directly.
byte[] data = System.Text.Encoding.ASCII.GetBytes("RIFF");
binaryWriter.Write(data);
or make it one line:
binaryWriter.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));
There may also be other problems, like the integers you are writing may not be of the same size as required. You should check them carefully.
As for endianess, the link you put states that data are in little-endian and BinaryWriter
uses little-endian, so this should not be a problem.