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.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using StreamComputers.Utilities;

namespace StreamComputers.Riff
{
	/// <summary>
	/// RiffWaveWriter assembles a RIFF WAVE file to be written to disk, sets properties,
	/// and exposes methods for writing data to the file.  Construct an instance of 
	/// RiffWaveWriter and keep it around until the application is finished writing the file,
	/// then call Close() to clean up its resources.
	/// </summary>
	public class RiffWaveWriter : RiffWaveManager
	{
		private BinaryWriter	m_Writer = null;

		#region properties

		public WaveFormatTag FormatTag
		{
			get { return m_FormatTag; }
			set { m_FormatTag = value; }
		}

		public short Channels
		{
			get { return m_Channels;}
			set { m_Channels = value; }
		}

		public int SamplesPerSecond
		{
			get { return m_SamplesPerSecond;}
			set { m_SamplesPerSecond = value; }
		}

		public int AverageBytesPerSecond
		{
			get { return m_AverageBytesPerSecond;}
			set { m_AverageBytesPerSecond = value; }
		}

		public short BlockAlign
		{
			get { return m_BlockAlign;}
			set { m_BlockAlign = value; }
		}

		public short BitsPerSample
		{
			get { return m_BitsPerSample;}
			set { m_BitsPerSample = value; }
		}

		public long StreamLength
		{
			get { return m_StreamLength;}
			set { m_StreamLength = value; }
		}

		public long DataStart
		{
			get { return m_DataStart;}
			set { m_DataStart = value; }
		}

		public long DataLength
		{
			get { return m_DataLength;}
			set { m_DataLength = value; }
		}

		#endregion

		public RiffWaveWriter(string fileName)
		{
			try
			{
				m_Stream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);
				DebugConsole.WriteLine("Set Wave properties for new file!");
			}
			catch (Exception e)
			{
				MessageBox.Show("RiffWaveWriter(string fileName) failed: " + e);
				Cleanup();
				ZeroAllInfo();
				throw;
			}
		}

		#region Methods to write RIFF WAVE files

		// Failed to find valid data header, so zero out the header information.
		protected void ZeroAllInfo()
		{
			m_AverageBytesPerSecond = 0;
			m_BitsPerSample = 0;
			m_BlockAlign = 0;
			m_Channels = 0;
			m_DataLength = 0;
			m_DataStart = 0;
			m_FormatTag = 0;
			m_SamplesPerSecond = 0;
			m_StreamLength = 0;
		}
		
		/// <summary>
		/// Sets properties to values appropriate for standard CD-quality 
		/// 16-bit 44.1KHz stereo samples
		/// </summary>
		public void SetCD16Info()
		{
			m_FormatTag = WaveFormatTag.Pcm;
			m_Channels = 2;
			m_SamplesPerSecond = 44100;
			m_AverageBytesPerSecond = 44100*2*2;
			m_BlockAlign = 2*2;
			m_BitsPerSample = 16;
		}

		/// <summary>
		/// Writes header information to RIFF WAVE file.  Properties must be set 
		/// before call. 
		/// Leaves writer pointer at start of data field, and zeros m_DataLength.
		/// </summary>
		public void WriteHeader()
		{
			m_Writer = new BinaryWriter(m_Stream);

			// uberheader
			m_Writer.Write(EncodeChars("RIFF"));
			Int32 i = 0;							// placeholder for (filesize - 8)
			m_Writer.Write(i);						// byte position = 4
			m_Writer.Write(EncodeChars("WAVE"));

			// fmt chunk (without extra format bytes)
			m_Writer.Write(EncodeChars("fmt "));
			i = 16;
			m_Writer.Write(i);
			m_Writer.Write((short) m_FormatTag);
			m_Writer.Write(m_Channels);
			m_Writer.Write(m_SamplesPerSecond);
			m_Writer.Write(m_AverageBytesPerSecond);
			m_Writer.Write(m_BlockAlign);
			m_Writer.Write(m_BitsPerSample);

			// data chunk
			m_Writer.Write(EncodeChars("data"));
			i = 0;									// placeholder for data length
			m_Writer.Write(i);						// byte position 0x28, 40 decimal

			Debug.Assert(m_Stream.Position == 44);
			m_DataLength = 0;
		}

		private byte[] EncodeChars(string s)
		{
			byte[] es = new byte[s.Length];
			es = Encoding.ASCII.GetBytes(s);
			return es;
		}

		/// <summary>
		/// Appends PCM16Data frames to a RiffWaveWriter-managed file.
		/// </summary>
		/// <param name="buf">PCM16Frame[] buffer to write to file</param>
		public void WritePCM16DataFrames(Pcm16Frame[] buf)
		{
			Debug.Assert(buf.Length <= Int32.MaxValue, "WritePCM16DataFrames called with buffer too big.");
			int i = 0;
			for (; i < buf.Length; i++)
			{
				m_Writer.Write(buf[i].Lch);
				m_Writer.Write(buf[i].Rch);
			}
			m_DataLength += buf.Length*m_BlockAlign;
		}

		/// <summary>
		/// Finishes writing chunk length fields to a RIFF WAVE file but does not close it.
		/// </summary>
		public void WriteFinal()
		{
			// RIFF spec wants uint, stream length is really a long
			Debug.Assert(m_Writer.BaseStream.Length <= Int32.MaxValue,
			             "RiffWaveWriter.WriteFinal() saw file too big for an int32 length");
			int size = (int) m_Writer.BaseStream.Length;
			m_Writer.BaseStream.Position = 4;
			m_Writer.Write(size - 8);
			m_Writer.BaseStream.Position = 40;
			m_Writer.Write(m_DataLength);
		}

		#endregion

		#region Finalization

		// Flushes and closes the file and releases resources.  
		public override void Close()
		{
			Dispose();
		}

		protected override void Cleanup()
		{
			try
			{
				if(m_Writer != null)
				{
					m_Writer.Flush();
					m_Writer.Close();
				}
			}
			finally
			{
				base.Cleanup();
			}
		}
		#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
Web01 | 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