EDN Admin
Well-known member
I am developing a c# library that can play sound in real-time. In other words this library has methods that can play a sine wave for x amount of seconds at a specified frequency. There are methods to play samples that are in the form of a byte array.
I know how to write WAV headers from scratch based on information giving like sample rate, bits per sample, and number of channels (mono or stereo). The problem is that I cannot play WAVsamples in real-time because of this exception below:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
<br/>
The funny thing is if I play a sound that has a duration less than 0.2 seconds it will play but if I play again after it has stopped playing it throws the same exception above. I decided to use pointers but it doesnt make a difference if I use managed type
like string or byte[]. Here is the code below:
Library Code:<br/>
<pre class="prettyprint using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Media;
using System.IO;
using System.Runtime.InteropServices;
namespace Real_Time_Sound_Library
{
public unsafe class RealTimeWAVPlayer
{
private int sampleRate;
private int numberOfChannels;
public RealTimeWAVPlayer(int sampleRate, int numberOfChannels)
{
this.sampleRate = sampleRate;
this.numberOfChannels = numberOfChannels;
}
/// <summary>
/// plays audio samples in real-time.
/// </summary>
/// <param name="samples The actual audio samples do not include the wav header it is provided.</param>
public void play(byte[] samples)
{
List<byte> data = new List<byte>();
byte[] header = getWavHeader(samples.Length);
data.AddRange(header);
data.AddRange(samples);
try
{
fixed (byte* ptr = data.ToArray())
{
UnManagedSoundPlayer.Play(ptr);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.Write("Error:t" + e.Message);
}
finally
{
}
}
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))));
}
try
{
fixed (byte* ptr = data.ToArray())
{
UnManagedSoundPlayer.Play(ptr);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.Write("Error:t" + e.Message);
}
finally
{
}
}
public int secondsToSampleLength(float seconds)
{
/*
* x sample 2 byte 60 second
* -------- * -------- * --------------- = total in samples
* 1 second 1 second 1 second
*/
return (int)(sampleRate * seconds * 2);
}
private byte[] getWavHeader(int totalSamples)
{
byte[] wavHeader;
using (MemoryStream stream = new MemoryStream())
{
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;
}
}
unsafe class UnManagedSoundPlayer
{
[DllImport("WinMM.dll")]
public static extern bool PlaySound(byte* data, int Mod, int flag);
public const int SND_ASYNC = 0x0001;
public const int SND_FILENAME = 0x00020000;
public const int SND_PURGE = 0x0040;
public const int SND_NODEFAULT = 0x00002;
public const int SND_SYNC = 0x00000;
public const int SND_MEMORY = 0x00004;
public static bool Play(byte* data, int SoundFlags = (SND_MEMORY | SND_SYNC))
{
return PlaySound(data, 0, SoundFlags);
}
public static void StopPlay()
{
PlaySound(null, 0, SND_PURGE);
}
}
}[/code]
<br/>
Usage Code:
<pre class="prettyprint RealTimeWAVPlayer wavPlayer = new RealTimeWAVPlayer(44100, 1);
wavPlayer.playSineWave(440, wavPlayer.secondsToSampleLength(0.2f));[/code]
<br/>
<br/>
<br/>
<br/>
<
http://monsterhunter445.no-ip.org/
<br/>
View the full article
I know how to write WAV headers from scratch based on information giving like sample rate, bits per sample, and number of channels (mono or stereo). The problem is that I cannot play WAVsamples in real-time because of this exception below:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
<br/>
The funny thing is if I play a sound that has a duration less than 0.2 seconds it will play but if I play again after it has stopped playing it throws the same exception above. I decided to use pointers but it doesnt make a difference if I use managed type
like string or byte[]. Here is the code below:
Library Code:<br/>
<pre class="prettyprint using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Media;
using System.IO;
using System.Runtime.InteropServices;
namespace Real_Time_Sound_Library
{
public unsafe class RealTimeWAVPlayer
{
private int sampleRate;
private int numberOfChannels;
public RealTimeWAVPlayer(int sampleRate, int numberOfChannels)
{
this.sampleRate = sampleRate;
this.numberOfChannels = numberOfChannels;
}
/// <summary>
/// plays audio samples in real-time.
/// </summary>
/// <param name="samples The actual audio samples do not include the wav header it is provided.</param>
public void play(byte[] samples)
{
List<byte> data = new List<byte>();
byte[] header = getWavHeader(samples.Length);
data.AddRange(header);
data.AddRange(samples);
try
{
fixed (byte* ptr = data.ToArray())
{
UnManagedSoundPlayer.Play(ptr);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.Write("Error:t" + e.Message);
}
finally
{
}
}
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))));
}
try
{
fixed (byte* ptr = data.ToArray())
{
UnManagedSoundPlayer.Play(ptr);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.Write("Error:t" + e.Message);
}
finally
{
}
}
public int secondsToSampleLength(float seconds)
{
/*
* x sample 2 byte 60 second
* -------- * -------- * --------------- = total in samples
* 1 second 1 second 1 second
*/
return (int)(sampleRate * seconds * 2);
}
private byte[] getWavHeader(int totalSamples)
{
byte[] wavHeader;
using (MemoryStream stream = new MemoryStream())
{
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;
}
}
unsafe class UnManagedSoundPlayer
{
[DllImport("WinMM.dll")]
public static extern bool PlaySound(byte* data, int Mod, int flag);
public const int SND_ASYNC = 0x0001;
public const int SND_FILENAME = 0x00020000;
public const int SND_PURGE = 0x0040;
public const int SND_NODEFAULT = 0x00002;
public const int SND_SYNC = 0x00000;
public const int SND_MEMORY = 0x00004;
public static bool Play(byte* data, int SoundFlags = (SND_MEMORY | SND_SYNC))
{
return PlaySound(data, 0, SoundFlags);
}
public static void StopPlay()
{
PlaySound(null, 0, SND_PURGE);
}
}
}[/code]
<br/>
Usage Code:
<pre class="prettyprint RealTimeWAVPlayer wavPlayer = new RealTimeWAVPlayer(44100, 1);
wavPlayer.playSineWave(440, wavPlayer.secondsToSampleLength(0.2f));[/code]
<br/>
<br/>
<br/>
<br/>
<
http://monsterhunter445.no-ip.org/
<br/>
View the full article