[C#] Loading WAV formatted beep to MemoryStream & played by system audio

AceInfinity

Emeritus, Contributor
Joined
Feb 21, 2012
Posts
1,728
Location
Canada
Here's a little snippet to write a beep in WAV format to a MemoryStream to be played by the system. Easily enough done with the kernel32.dll's internal function 'Beep' although here's a way to do it manually.

Code:
using System;
using System.Windows.Forms;
using System.IO;
using System.Media;
using System.Linq;

public class Sound
{
	public static void CreateBeep(int amp, int freq, int dur)
	{
		int smp = 441 * dur / 10;
		int bytes = smp * 4;
		int[] h = { 0X46464952, 0x24 + bytes, 0X45564157, 0X20746D66, 0x10, 0X20001, 0xAC44, 0x2B110, 0X100004, 0X61746164, bytes };

		using (MemoryStream ms = new MemoryStream(44 + bytes))
		{
			using (BinaryWriter bw = new BinaryWriter(ms))
			{
				Array.ForEach(Enumerable.Range(0, h.Length).ToArray(), i => bw.Write(h[i]));

				for (int i = 0; i < smp; i++)
				{
					Int16 s = Convert.ToInt16((((amp * (Math.Pow(2, 15))) / 1000) - 1) * Math.Sin((2 * Math.PI * freq / 44100.0) * i));
					Array.ForEach(Enumerable.Range(1, 2).ToArray(), n => bw.Write(s));
				}

				bw.Flush();
				ms.Seek(0, SeekOrigin.Begin);
				using (SoundPlayer SP = new SoundPlayer(ms)) { SP.PlaySync(); }
			}
		}
	}
}

And to test, i've created a little Twinkle Twinkle little star melody for you guys :)

Code:
new Thread(new ThreadStart(
	(MethodInvoker)delegate
			{
				int[] freqs = { 
									  131, 131, 196, 196, 220, 220, 196, 0,
									  175, 175, 165, 165, 147, 147, 131, 0,
									  196, 196, 175, 175, 165, 165, 147, 0,
									  196, 196, 175, 175, 165, 165, 147, 0,
									  131, 131, 196, 196, 220, 220, 196, 0,
									  175, 175, 165, 165, 147, 147, 131, 0
								  };
				Array.ForEach(freqs, f => Sound.CreateBeep(1000, f, 400));
			}
)).Start();

We use a BinaryWriter to write to a MemoryStream, so that we can load that data (bytes) using a System.Media.SoundPlayer. What needs to happen first though is that we write the WAV file header to the MemoryStream, then, we can start writing out the samples using a formulated value. Flush the rest of the data out of the BinaryWriter, and reset the start position of the MemoryStream back to the beginning for our SoundPlayer to use the data in the MemoryStream to be played. If you use the Play() method instead of PlaySound() you get a really cool distorted sound effect :)

To do that, look into the class and change:
Code:
using (SoundPlayer SP = new SoundPlayer(ms)) { SP.PlaySync(); }

To:
Code:
using (SoundPlayer SP = new SoundPlayer(ms)) { SP.Play(); }

Just one of the things I noticed while doing this.

I got the idea from here: http://paste.blixt.org/543

Highest amplitude you'll want would be 1000, if you want to provide handling for that, you can probably check that parameter and throw an exception if it's too high:
Code:
if (amp > 1000) throw new Exception("Amplitude too high");
 
Last edited:
I like system sounds; hence the reason only IE is used here.

You're coding up a storm! :thumbsup2:
 
Browsers could be created to make system sounds based on the defaults if they wanted to, I think they get annoying though lol. I wish more people would be in these parts of the forum though :)
 

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top