Click here to Skip to main content
15,881,812 members
Articles / Multimedia / DirectX

Sound Experiments in Managed DirectX

Rate me:
Please Sign up or sign in to vote.
4.85/5 (46 votes)
16 Feb 200726 min read 267.2K   4K   118  
Using static and streaming sound buffers in Managed DirectX.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES
//  OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//  � 2007 Gary W. Schwede and Stream Computers, Inc. All rights reserved.
//  Contact: gary at streamcomputers dot com. Permission to incorporate
//  all or part of this code in your application is given on the condition
//  that this notice accompanies it in your code and documentation.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using Microsoft.DirectX.DirectSound;
using StreamComputers.Riff;

namespace StreamComputers.MdxDirectSound
{
	/// <summary>
	/// Simple Windows Forms Dialog to play CD-standard .WAV files using Managed 
	/// DirectX DirectSound functions.  This player locates SecondaryBuffers in software 
	/// only, avoiding spurious notifications seen when located in hardware. 
	/// </summary>
	public class SimpleMdxPlayer : Form
	{
		#region private fields

		private Label lblSoundFile;
		private Button btnOpenFile;
		private Label lblBufSize;
		private Button btnPlay;
		private Button btnPause;
		private Button btnStop;
		private RadioButton rdoBtnStatic;
		private RadioButton rdoBtnStreaming;
		private Button btnCreateBuf;

		/// <summary>
		/// Required designer variable.
		/// </summary>
		private Container components = null;

		private string				m_PathToSoundFile = string.Empty;
		private string				m_SelectedFilePathAndName = string.Empty;
		private MdxSoundBuffer		m_Buffer = null;
		private Device				m_MDXDevice = null;

		#endregion

		public SimpleMdxPlayer()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();
			
			EnableFileSelectUI(true);
			EnableBufferUI(false);
			EnablePlayUI(false);
		}

		#region IDisposable implementation

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if(m_Buffer != null)
				{
					m_Buffer.Dispose();
				}

				if(m_MDXDevice != null)
				{
					m_MDXDevice.Dispose();
					m_MDXDevice = null;
				}				
				
				if (components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose(disposing);
		}

		#endregion

		#region Windows Form Designer generated code

		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.lblSoundFile = new System.Windows.Forms.Label();
			this.btnOpenFile = new System.Windows.Forms.Button();
			this.rdoBtnStatic = new System.Windows.Forms.RadioButton();
			this.rdoBtnStreaming = new System.Windows.Forms.RadioButton();
			this.lblBufSize = new System.Windows.Forms.Label();
			this.btnPlay = new System.Windows.Forms.Button();
			this.btnPause = new System.Windows.Forms.Button();
			this.btnStop = new System.Windows.Forms.Button();
			this.btnCreateBuf = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// lblSoundFile
			// 
			this.lblSoundFile.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblSoundFile.Location = new System.Drawing.Point(112, 32);
			this.lblSoundFile.Name = "lblSoundFile";
			this.lblSoundFile.Size = new System.Drawing.Size(200, 24);
			this.lblSoundFile.TabIndex = 0;
			this.lblSoundFile.Text = "no file selected.";
			this.lblSoundFile.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// btnOpenFile
			// 
			this.btnOpenFile.Location = new System.Drawing.Point(16, 32);
			this.btnOpenFile.Name = "btnOpenFile";
			this.btnOpenFile.Size = new System.Drawing.Size(80, 24);
			this.btnOpenFile.TabIndex = 1;
			this.btnOpenFile.Text = "&Open File";
			this.btnOpenFile.Click += new System.EventHandler(this.btnOpenFile_Click);
			// 
			// rdoBtnStatic
			// 
			this.rdoBtnStatic.Checked = true;
			this.rdoBtnStatic.Location = new System.Drawing.Point(112, 80);
			this.rdoBtnStatic.Name = "rdoBtnStatic";
			this.rdoBtnStatic.Size = new System.Drawing.Size(80, 24);
			this.rdoBtnStatic.TabIndex = 6;
			this.rdoBtnStatic.TabStop = true;
			this.rdoBtnStatic.Text = "Static";
			// 
			// rdoBtnStreaming
			// 
			this.rdoBtnStreaming.Location = new System.Drawing.Point(112, 104);
			this.rdoBtnStreaming.Name = "rdoBtnStreaming";
			this.rdoBtnStreaming.Size = new System.Drawing.Size(80, 24);
			this.rdoBtnStreaming.TabIndex = 7;
			this.rdoBtnStreaming.Text = "Streaming";
			// 
			// lblBufSize
			// 
			this.lblBufSize.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblBufSize.Location = new System.Drawing.Point(208, 88);
			this.lblBufSize.Name = "lblBufSize";
			this.lblBufSize.Size = new System.Drawing.Size(104, 24);
			this.lblBufSize.TabIndex = 8;
			this.lblBufSize.Text = "Buffer Size (KB)";
			this.lblBufSize.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// btnPlay
			// 
			this.btnPlay.Location = new System.Drawing.Point(40, 160);
			this.btnPlay.Name = "btnPlay";
			this.btnPlay.Size = new System.Drawing.Size(64, 24);
			this.btnPlay.TabIndex = 10;
			this.btnPlay.Text = "&Play";
			this.btnPlay.Click += new System.EventHandler(this.btnPlay_Click);
			// 
			// btnPause
			// 
			this.btnPause.Location = new System.Drawing.Point(140, 160);
			this.btnPause.Name = "btnPause";
			this.btnPause.Size = new System.Drawing.Size(64, 24);
			this.btnPause.TabIndex = 11;
			this.btnPause.Text = "Pa&use";
			this.btnPause.Click += new System.EventHandler(this.btnPause_Click);
			// 
			// btnStop
			// 
			this.btnStop.Location = new System.Drawing.Point(240, 160);
			this.btnStop.Name = "btnStop";
			this.btnStop.Size = new System.Drawing.Size(64, 24);
			this.btnStop.TabIndex = 12;
			this.btnStop.Text = "&Stop";
			this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
			// 
			// btnCreateBuf
			// 
			this.btnCreateBuf.Location = new System.Drawing.Point(16, 88);
			this.btnCreateBuf.Name = "btnCreateBuf";
			this.btnCreateBuf.Size = new System.Drawing.Size(80, 24);
			this.btnCreateBuf.TabIndex = 9;
			this.btnCreateBuf.Text = "Create Buffer";
			this.btnCreateBuf.Click += new System.EventHandler(this.btnCreateBuf_Click);
			// 
			// SimpleMdxPlayer
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(336, 213);
			this.Controls.Add(this.btnCreateBuf);
			this.Controls.Add(this.btnStop);
			this.Controls.Add(this.btnPause);
			this.Controls.Add(this.btnPlay);
			this.Controls.Add(this.lblBufSize);
			this.Controls.Add(this.rdoBtnStreaming);
			this.Controls.Add(this.rdoBtnStatic);
			this.Controls.Add(this.btnOpenFile);
			this.Controls.Add(this.lblSoundFile);
			this.Name = "SimpleMdxPlayer";
			this.Text = "SimpleMdxPlayer";
			this.Load += new System.EventHandler(this.SimpleMdxPlayer_Load);
			this.ResumeLayout(false);

		}

		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		private static void Main()
		{
			Application.Run(new SimpleMdxPlayer());
		}

		private void SimpleMdxPlayer_Load(object sender, EventArgs e)
		{
			try
			{
				m_MDXDevice = new Device();						// default device
				Debug.Assert(m_MDXDevice.Caps.Secondary16Bit);	
				m_MDXDevice.SetCooperativeLevel(this, CooperativeLevel.Priority);
			}
			catch
			{
				MessageBox.Show("Cannot find sound device. Application will exit.");
				this.Close();
				throw;
			}		
		}

		#region OpenFileDialog code

		/// <summary>
		/// Stops play if in progress.  Invokes OpenFileDialog to set input sound file member.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnOpenFile_Click(object sender, EventArgs e)
		{
			OpenFileDialog openFileDialog = new OpenFileDialog();
			openFileDialog.InitialDirectory = m_PathToSoundFile;
			openFileDialog.Filter = "Wave files(*.wav)|*.wav";
			if (DialogResult.Cancel == openFileDialog.ShowDialog())
				return;	

			m_PathToSoundFile = Path.GetDirectoryName(openFileDialog.FileName);
			lblSoundFile.Text = Path.GetFileName(openFileDialog.FileName);
			m_SelectedFilePathAndName = openFileDialog.FileName;

			EnableBufferUI(true);
			EnablePlayUI(false);
		}

		#endregion

		#region btnCreateBuf_Click code

		/// <summary>
		/// Creates a new MDX DS SecondaryBuffer of the type specified by the radio buttons.
		/// </summary>
		private void btnCreateBuf_Click(object sender, EventArgs e)
		{
			EnablePlayUI(false);

			if(rdoBtnStatic.Checked)
			{
				// Create a new static secondary buffer, and load the whole sound file.
				// Set GlobalFocus for new buffer, but let other properties be defaults.
				// DirectSound may "locate" the buffer in hardware if resources are available.
				BufferDescription bdesc = new BufferDescription();
				bdesc.GlobalFocus = true;
				if(m_Buffer != null)
				{
					m_Buffer.Dispose();
				}
				try
				{
					m_Buffer = new StaticSoundBuffer(m_SelectedFilePathAndName, bdesc, m_MDXDevice);
				}
				catch(OutOfMemoryException)
				{
					if (m_Buffer != null)
					{
						m_Buffer.Dispose();
					}
					return;
				}
				catch (ArgumentException)
				{
					if (m_Buffer != null)
					{
						m_Buffer.Dispose();
					}
					return;
				}
			}
			else
			{
				Debug.Assert(rdoBtnStreaming.Checked, "None of two radio buttons checked.") ;
				if(m_Buffer != null)
				{
					m_Buffer.Dispose();
				}
				try
				{
					// create a streaming secondary buffer, "located" in software.
					m_Buffer = new SimpleStreamingSoundBuffer(m_SelectedFilePathAndName, m_MDXDevice);
				}
				catch(RiffParserException)
				{
					if(m_Buffer != null)
					{
						m_Buffer.Dispose();
					}
					return;
				}
			}
			// set the buffer length label
			lblBufSize.Text =  String.Format("{0} KB", m_Buffer.BufferLength / 1024) ;

			EnablePlayUI(true);
		}
		#endregion

		#region IPlayable event code

		private void btnPlay_Click(object sender, EventArgs e)
		{
			EnableFileSelectUI(false);
			EnableBufferUI(false);

			try
			{
				m_Buffer.Play();
			}
			catch (OutOfMemoryException)
			{
				m_Buffer.Dispose();
				EnablePlayUI(false);
				EnableBufferUI(true);
				EnableFileSelectUI(true);
			}
		}

		private void btnPause_Click(object sender, EventArgs e)
		{
			m_Buffer.Pause();
		}

		private void btnStop_Click(object sender, EventArgs e)
		{
			m_Buffer.Stop();
			EnableBufferUI(true);
			EnableFileSelectUI(true);
		}

		#endregion

		#region EnableUI code

		private void EnableFileSelectUI(bool enable)
		{
			btnOpenFile.Enabled = enable;
		}

		private void EnableBufferUI(bool enable)
		{
			btnCreateBuf.Enabled = enable;
		}

		private void EnablePlayUI(bool enable)
		{
			btnPlay.Enabled = enable;
			btnPause.Enabled = enable;
			btnStop.Enabled = enable;
		}

		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
Software Developer (Senior)
United States United States
My life and career have been a bit unusual (mostly in good ways). So, I'm grateful every day for the opportunities God's given me to do different things and see different aspects of life.

Education: B.S. Physics '73 (atmospheric physics, sounding rockets), M.S. Computer Science '76 (radio astronomy, fuzzy controllers, music pattern recognition and visualization) New Mexico Tech; Ph.D. Engineering '83 (parallel computer architecture, digital signal processing, economics) U.C. Berkeley.

I'm married to Susan, a wonderful woman whom I met in a Computer Architecture class at U.C. Berkeley.

Professional activities: Digital systems engineer, digital audio pioneer, founder or key in several tech startups, consulting engineer, expert witness. I'm currently developing a multithreading framework in C# .NET, that makes it almost easy to write correct programs for multicore processors. I'm also implementing a new transform for recognizing, editing, and processing signals, especially sound.

I'm an occasional essayist, public speaker, and podcaster, and free-market space advocate. I enjoy good wine, good music, good friends, and cats.

If you think your project could use a different point of view, I'm available for consulting work in the San Francisco Bay area, or (preferrably) via the net.

Comments and Discussions