Tuesday, August 9, 2011
Playing .wav files using C#
Introduction
To achieve some things in the .NET Framework, one must make platform invocation calls to the underlying OS, or use one of the thinly-wrapped COM objects exposed as a class library. This example shows how to play .WAV sounds from a file picker, or play a user-defined sound by enumerating the Windows registry. Since Microsoft did not include a method for playing sounds in the Framework, we must make a PInvoke call to the PlaySound() function located in the Winmm.dll library. The PlaySound function is extremely simple to use as you'll see below.
The PlaySound function
Collapse | Copy Code
bool PlaySound(
LPCSTR pszSound, // filename
HMODULE hmod, // handle to resource file
DWORD fdwSound) // sound flags
For this example, we play a sound directly from a filename, therefore we need only specify values for pszSound and fdwSound; The hmod parameter must be set to NULL unless playing a sound from a resource.
Partial Source
Collapse | Copy Code
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices; // for PInvoke
using Microsoft.Win32; // RegistryKey
namespace PlaySound
{
public class Form1 : System.Windows.Forms.Form
{
...
private RegistryKey key1;
private RegistryKey key2;
// collection of user-defined sound events
private PropertyCollection events;
// PlaySound()
[DllImport("winmm.dll", SetLastError=true,
CallingConvention=CallingConvention.Winapi)]
static extern bool PlaySound(
string pszSound,
IntPtr hMod,
SoundFlags sf );
// Flags for playing sounds. For this example, we are reading
// the sound from a filename, so we need only specify
// SND_FILENAME | SND_ASYNC
[Flags]
public enum SoundFlags : int
{
SND_SYNC = 0x0000, // play synchronously (default)
SND_ASYNC = 0x0001, // play asynchronously
SND_NODEFAULT = 0x0002, // silence (!default) if sound not found
SND_MEMORY = 0x0004, // pszSound points to a memory file
SND_LOOP = 0x0008, // loop the sound until next sndPlaySound
SND_NOSTOP = 0x0010, // don't stop any currently playing sound
SND_NOWAIT = 0x00002000, // don't wait if the driver is busy
SND_ALIAS = 0x00010000, // name is a registry alias
SND_ALIAS_ID = 0x00110000, // alias is a predefined ID
SND_FILENAME = 0x00020000, // name is file name
SND_RESOURCE = 0x00040004 // name is resource name or atom
}
...
private void buttonPlay_Click(object sender, System.EventArgs e)
{
int err = 0; // last error
try
{
// play the sound from the selected filename
if (!PlaySound( tbFileName.Text, IntPtr.Zero,
SoundFlags.SND_FILENAME | SoundFlags.SND_ASYNC ))
MessageBox.Show(this,
"Unable to find specified sound file or " +
"default Windows sound");
}
catch
{
// grab the underlying Win32 error code
err = Marshal.GetLastWin32Error();
if (err != 0)
MessageBox.Show( this,
"Error " + err.ToString(),
"PlaySound() failed",
MessageBoxButtons.OK,
MessageBoxIcon.Error );
}
}
// browse button handler
private void buttonBrowse_Click(object sender, System.EventArgs e)
{
string sysRoot = System.Environment.SystemDirectory;
OpenFileDialog dlg = new OpenFileDialog();
dlg.AddExtension = true;
dlg.Filter = "Wave files (*.wav)|*.wav|All files (*.*)|*.*" ;
// start in media folder
dlg.InitialDirectory = sysRoot + @"\..\Media";
// open dialog
if(dlg.ShowDialog(this) == DialogResult.OK)
{
tbFileName.Text = dlg.FileName;
}
}
...
// fill combobox with user-defined sounds
private void PopulateDropDown()
{
// fill our PropertyCollection object
events = GetUserDefinedSounds();
// disable if no sound events
if (events.Keys.Count == 0)
cbUserSound.Enabled = false;
else
{
foreach (string key in events.Keys)
{
cbUserSound.Items.Add(key);
}
}
}
// Retrieves the user-defined sounds from the registry
private PropertyCollection GetUserDefinedSounds()
{
string rootKey = "AppEvents\\Schemes\\Apps\\.Default";
PropertyCollection coll = new PropertyCollection();
try
{
// open root key
key1 = Registry.CurrentUser.OpenSubKey(rootKey, false);
// go through each subkey
foreach (string subKey in key1.GetSubKeyNames())
{
// open subkey
key2 = key1.OpenSubKey(subKey + "\\.Current", false);
// get filename, if any
if (key2 != null)
if (key2.GetValue(null).ToString().Length > 0)
coll.Add(subKey, key2.GetValue(null).ToString());
}
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Yikes!",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
// close keys
key1.Close();
key2.Close();
}
return coll;
}
...
}
}
You probably noticed the SetLastError=true parameter in the DllImport call. This simply states that the runtime marshaler calls GetLastError for us in the event something went wrong with our PInvoke call.
Points of Interest
This code has only been tested on Windows 2000 and XP SP1 using Framework version 1.1, however it should also work as far back as Windows 98. Oh yes, the project file is VS.NET 2003 - sorry.
History
Version 1.0 - 07.25.03 - First version.
From:http://www.codeproject.com/KB/audio-video/PlaySounds1.aspx
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment