I am developing a simple real time audio library. Where the programmer can make calls to methods that can play audio in real-time. In addition, the programmer can call methods that can play a sine wave at specific frequency and duration in real-time. The audio format that is being played in realtime is WAV. The problem is when I call playSineWave it throws an inner exception saying the PlayerSound.Play cannot play the sound since it has a corrupt header. So at first I believed that I by accident wrote the header wrong. But I saved the actual bytes of the wav file including the header of course and it played in iTunes without error and it sounds like a sine wave at the correct frequency. So what am I doing wrong since the exception that is being thrown is misleading.
Here is the code that is causing the problem:
public void playSineWave(int frequency, int totalSampleLength)
{
if (frequency <= 0)
{
throw new InvalidDataException("frequency cannot be zero or negative.");
}
List<byte> data = new List<byte>();
byte[] header = getWavHeader(totalSampleLength);
data.AddRange(header);
for(int x = 0; x < (totalSampleLength); x++)
{
data.Add((byte)(127 * Math.Sin(2 * (Math.PI / sampleRate) * frequency * (x / 2))));
}
using(MemoryStream stream = new MemoryStream())
{
using (SoundPlayer player = new SoundPlayer(stream))
{
stream.Write(data.ToArray(), 0, data.Count);
player.Play();
}
}
}
public int secondsToSampleLength(int seconds)
{
/*
* x sample 2 byte 60 second
* -------- * -------- * --------------- = total in samples
* 1 second 1 second 1 second
*/
return sampleRate * seconds * 2;
}
private byte[] getWavHeader(int totalSamples)
{
MemoryStream stream = new MemoryStream();
byte[] wavHeader;
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.BigEndianUnicode))
{
writer.Write(new byte[] { 0x52, 0x49, 0x46, 0x46 }); // 4
int bitsPerSample = 16;
writer.Write(36 + (totalSamples * numberOfChannels * (bitsPerSample / 8))); // 4
writer.Write(new byte[] { 0x57, 0x41, 0x56, 0x45 }); // 4
writer.Write(new byte[] { 0x66, 0x6d, 0x74, 0x20 }); // 4
writer.Write(16); // 4
writer.Write((short)1); // 2
writer.Write((short)numberOfChannels); // 2
writer.Write(sampleRate); // 4
writer.Write(sampleRate * numberOfChannels * (bitsPerSample / 8)); // 4
writer.Write((short)(numberOfChannels * (bitsPerSample / 8))); // 2
writer.Write((short)(bitsPerSample)); // 2
writer.Write(new byte[] { 0x64, 0x61, 0x74, 0x61 }); // 4
writer.Write((totalSamples * numberOfChannels * (bitsPerSample / 8))); // 4
wavHeader = stream.ToArray();
}
return wavHeader;
}
Would I have to use methods from the Windows API that can play the WAV file? Any suggestion would also be helpful. Thanks in advanced. Please do not suggest NAudio I want to write WAV files from scratch and I am aware of that great library.
Forgot to mention that if I set the positon to zero after writing then it gives this exception below:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.