Click here to Skip to main content
Click here to Skip to main content
 
Add your own
alternative version

Sound Experiments in Managed DirectX

, 16 Feb 2007
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.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//  � 2006 Gary W. Schwede  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;
using WaveFormatTag = StreamComputers.Riff.WaveFormatTag;

namespace StreamComputers.MdxDirectSound
{
	/// <summary>
	/// Simple Windows Forms Dialog to exercise Managed DirectX DirectSound functions.
	/// </summary>
	public class MdxSoundExamples : Form
	{
		#region private fields

		private Label lblSoundFile;
		private Button btnOpenFile;
		private Label lblBufSize;
		private Button btnPlay;
		private Button btnPause;
		private Button btnStop;
		private Label lblTruncateTo;
		private NumericUpDown numUDLength;
		private Label lblsec;
		private Button btnWriteFile;
		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 string				m_writeFileDir = string.Empty;
		private string				m_WriteFilePathAndName = string.Empty;
		private MdxSoundBuffer		m_Buffer = null;
		private Device				m_MDXDevice = null;

		#endregion

		public MdxSoundExamples()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();
			
			EnableFileSelectUI(true);
			EnableWriteUI(false);
			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.lblTruncateTo = new System.Windows.Forms.Label();
			this.numUDLength = new System.Windows.Forms.NumericUpDown();
			this.lblsec = new System.Windows.Forms.Label();
			this.btnWriteFile = 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();
			((System.ComponentModel.ISupportInitialize)(this.numUDLength)).BeginInit();
			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);
			// 
			// lblTruncateTo
			// 
			this.lblTruncateTo.Location = new System.Drawing.Point(24, 88);
			this.lblTruncateTo.Name = "lblTruncateTo";
			this.lblTruncateTo.Size = new System.Drawing.Size(72, 16);
			this.lblTruncateTo.TabIndex = 2;
			this.lblTruncateTo.Text = "Truncate to";
			// 
			// numUDLength
			// 
			this.numUDLength.Location = new System.Drawing.Point(112, 86);
			this.numUDLength.Maximum = new System.Decimal(new int[] {
																		60,
																		0,
																		0,
																		0});
			this.numUDLength.Name = "numUDLength";
			this.numUDLength.Size = new System.Drawing.Size(72, 20);
			this.numUDLength.TabIndex = 3;
			this.numUDLength.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
			// 
			// lblsec
			// 
			this.lblsec.Location = new System.Drawing.Point(192, 88);
			this.lblsec.Name = "lblsec";
			this.lblsec.Size = new System.Drawing.Size(30, 16);
			this.lblsec.TabIndex = 4;
			this.lblsec.Text = "sec";
			// 
			// btnWriteFile
			// 
			this.btnWriteFile.Location = new System.Drawing.Point(232, 88);
			this.btnWriteFile.Name = "btnWriteFile";
			this.btnWriteFile.Size = new System.Drawing.Size(80, 24);
			this.btnWriteFile.TabIndex = 5;
			this.btnWriteFile.Text = "&Write File";
			this.btnWriteFile.Click += new System.EventHandler(this.btnWriteFile_Click);
			// 
			// rdoBtnStatic
			// 
			this.rdoBtnStatic.Checked = true;
			this.rdoBtnStatic.Location = new System.Drawing.Point(112, 136);
			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, 160);
			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, 144);
			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, 216);
			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, 216);
			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, 216);
			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, 144);
			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);
			// 
			// MdxSoundExamples
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(336, 269);
			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.btnWriteFile);
			this.Controls.Add(this.lblsec);
			this.Controls.Add(this.numUDLength);
			this.Controls.Add(this.lblTruncateTo);
			this.Controls.Add(this.btnOpenFile);
			this.Controls.Add(this.lblSoundFile);
			this.Name = "MdxSoundExamples";
			this.Text = "MdxSoundExamples";
			this.Load += new System.EventHandler(this.MDXSoundExamples_Load);
			((System.ComponentModel.ISupportInitialize)(this.numUDLength)).EndInit();
			this.ResumeLayout(false);

		}

		#endregion

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

		private void MDXSoundExamples_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;

			EnableWriteUI(true);
			EnableBufferUI(true);
			EnablePlayUI(false);
		}

		#endregion

		#region btnWriteFile_Click code

		/// <summary>
		/// Invokes SaveFileDialog to let user specify name of a file to write, then 
		/// copies the first part of the input sound file to the specified file,
		/// up to the length specified in the up/down control. This new file becomes the
		/// selected input sound file that can be loaded and played.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnWriteFile_Click(object sender, EventArgs e)
		{
			// local helper object for input sound file
			RiffWaveReader selectedFileManager = new RiffWaveReader(m_SelectedFilePathAndName);

			// specify a new file to write to
			SaveFileDialog writeFileDialog = new SaveFileDialog();
			writeFileDialog.InitialDirectory = m_writeFileDir;
			writeFileDialog.Filter = "WaveFiles(*.wav)|*.wav";
			DialogResult res = writeFileDialog.ShowDialog();
			if(res == DialogResult.Cancel)
			{
				return;		
			}
			if(res == DialogResult.OK)
			{
				m_writeFileDir = Path.GetDirectoryName(writeFileDialog.FileName);
				lblSoundFile.Text = Path.GetFileName(writeFileDialog.FileName);
				m_WriteFilePathAndName = writeFileDialog.FileName;				
			}

			RiffWaveWriter outFileManager = new RiffWaveWriter(m_WriteFilePathAndName);
			Debug.Assert(outFileManager.CanRead) ;
			Debug.Assert(outFileManager.CanWrite) ;
			Debug.Assert(outFileManager.Length == 0) ;

			outFileManager.SetCD16Info();

			Debug.Assert(outFileManager.FormatTag == WaveFormatTag.Pcm);
			Debug.Assert(outFileManager.Channels == 2);
			Debug.Assert(outFileManager.SamplesPerSecond == 44100);
			Debug.Assert(outFileManager.AverageBytesPerSecond == 44100 * 2 * 2);
			Debug.Assert(outFileManager.BlockAlign == 2*2);
			Debug.Assert(outFileManager.BitsPerSample == 16);

			outFileManager.WriteHeader();

			int framesPerSec = outFileManager.AverageBytesPerSecond / outFileManager.BlockAlign;

			Pcm16Frame[] frameBuf1sec = new Pcm16Frame[framesPerSec];
			for(int i = 0; i < numUDLength.Value; i++)
			{
				selectedFileManager.GetPCM16DataFrames(ref frameBuf1sec, i * framesPerSec, framesPerSec) ;
				outFileManager.WritePCM16DataFrames(frameBuf1sec);
			}
			outFileManager.WriteFinal();
			outFileManager.Close();

			selectedFileManager.Close();

			// set selected file to truncated version
			m_SelectedFilePathAndName = m_WriteFilePathAndName;
		}
		#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; other properties are defaults.  
				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
					m_Buffer = new StreamingSoundBuffer(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 EnableWriteUI(bool enable)
		{
			numUDLength.Enabled = enable;
			btnWriteFile.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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

DrGary83
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.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 16 Feb 2007
Article Copyright 2006 by DrGary83
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid