Created
December 23, 2016 16:45
-
-
Save cliftonm/0052163d701db8d37393216353bf6dba to your computer and use it in GitHub Desktop.
A Simple C# WinForm Sound Player Demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Drawing; | |
using System.IO; | |
using System.Windows.Forms; | |
using System.Media; | |
class BeepSample | |
{ | |
static Form form; | |
static Button btnPlay; | |
static TrackBar tbFreq; | |
static bool playing; | |
static SoundPlayer player = new SoundPlayer(); | |
static void Main() | |
{ | |
Application.EnableVisualStyles(); | |
Application.SetCompatibleTextRenderingDefault(false); | |
CreateUI(); | |
WireUpButtonEvent(); | |
WireUpTrackbarEvent(); | |
form.ShowDialog(); | |
player.Stop(); | |
} | |
public static void CreateUI() | |
{ | |
form = new Form(); | |
form.Size = new Size(320, 150); | |
btnPlay = new Button(); | |
btnPlay.Location = new Point(form.ClientSize.Width / 2 - 50, 70); | |
btnPlay.Size = new Size(100, 25); | |
btnPlay.Text = "Play"; | |
tbFreq = new TrackBar(); | |
tbFreq.Location = new Point(10, 10); | |
tbFreq.Size = new Size(form.ClientSize.Width - 20, 30); | |
tbFreq.Minimum = 250; | |
tbFreq.Maximum = 3000; | |
form.Controls.Add(tbFreq); | |
form.Controls.Add(btnPlay); | |
} | |
public static void WireUpButtonEvent() | |
{ | |
btnPlay.Click += (sndr, args) => | |
{ | |
if (!playing) | |
{ | |
MemoryStream stream = Play(player, tbFreq.Value); | |
player.Stream = stream; | |
player.PlayLooping(); | |
stream.Close(); | |
btnPlay.Text = "Stop"; | |
playing = true; | |
} | |
else | |
{ | |
player.Stop(); | |
btnPlay.Text = "Play"; | |
playing = false; | |
} | |
}; | |
} | |
public static void WireUpTrackbarEvent() | |
{ | |
tbFreq.ValueChanged += (sndr, args) => | |
{ | |
if (playing) | |
{ | |
player.Stop(); | |
MemoryStream stream = Play(player, tbFreq.Value); | |
player.Stream = stream; | |
player.PlayLooping(); | |
stream.Close(); | |
} | |
}; | |
} | |
// Original code from http://stackoverflow.com/questions/12611982/generate-audio-tone-to-sound-card-in-c-or-c-sharp | |
public static MemoryStream Play(SoundPlayer player, int frequency, int msDuration = 1000) | |
{ | |
var soundStream = new MemoryStream(); | |
BinaryWriter writer = new BinaryWriter(soundStream); | |
int samplesPerSecond = 44100; | |
int samples = (int)((decimal)samplesPerSecond * msDuration / 1000); | |
WriteWavHeader(writer, msDuration, samplesPerSecond); | |
GenerateWaveform(writer, frequency, samples, samplesPerSecond); | |
soundStream.Seek(0, SeekOrigin.Begin); | |
return soundStream; | |
} | |
private static void WriteWavHeader(BinaryWriter writer, int msDuration, int samplesPerSecond) | |
{ | |
int formatChunkSize = 16; | |
int headerSize = 8; | |
short formatType = 1; | |
short tracks = 1; | |
short bitsPerSample = 16; | |
short frameSize = (short)(tracks * ((bitsPerSample + 7) / 8)); | |
int bytesPerSecond = samplesPerSecond * frameSize; | |
int waveSize = 4; | |
int samples = (int)((decimal)samplesPerSecond * msDuration / 1000); | |
int dataChunkSize = samples * frameSize; | |
int fileSize = waveSize + headerSize + formatChunkSize + headerSize + dataChunkSize; | |
writer.Write(0x46464952); // = encoding.GetBytes("RIFF") | |
writer.Write(fileSize); | |
writer.Write(0x45564157); // = encoding.GetBytes("WAVE") | |
writer.Write(0x20746D66); // = encoding.GetBytes("fmt ") | |
writer.Write(formatChunkSize); | |
writer.Write(formatType); | |
writer.Write(tracks); | |
writer.Write(samplesPerSecond); | |
writer.Write(bytesPerSecond); | |
writer.Write(frameSize); | |
writer.Write(bitsPerSample); | |
writer.Write(0x61746164); // = encoding.GetBytes("data") | |
writer.Write(dataChunkSize); | |
} | |
private static void GenerateWaveform(BinaryWriter writer, int frequency, int samples, int samplesPerSecond, int volume = 16383) | |
{ | |
const double TAU = 2 * Math.PI; | |
double theta = frequency * TAU / (double)samplesPerSecond; | |
// 'volume' is UInt16 with range 0 thru Uint16.MaxValue ( = 65 535) | |
// we need 'amp' to have the range of 0 thru Int16.MaxValue ( = 32 767) | |
double amp = volume >> 2; // so we simply set amp = volume / 2 | |
for (int step = 0; step < samples; step++) | |
{ | |
short s = (short)(amp * Math.Sin(theta * (double)step)); | |
writer.Write(s); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment