www.pudn.com > SoundDone.rar > WaveOut.cs


using System; 
using System.Threading; 
using System.Runtime.InteropServices; 
 
namespace WaveLib 
{ 
	///  
	/// 音频输出帮助 
	///  
	internal class WaveOutHelper 
	{ 
		///  
		/// 抛出指定的异常 
		///  
		/// 异常号 
		public static void Try(int err) 
		{ 
			if (err != WaveNative.MMSYSERR_NOERROR) 
				throw new Exception(err.ToString()); 
		} 
	} 
 
	///  
	/// 缓冲区满时委托 
	///  
	public delegate void BufferFillEventHandler(IntPtr data, int size); 
 
	///  
	/// 代表音频输出缓冲区 
	///  
	internal class WaveOutBuffer : IDisposable 
	{ 
		///  
		/// 缓冲池中的缓冲区 
		///  
		public WaveOutBuffer NextBuffer; 
 
		///  
		/// 控制播放状态 
		///  
		private AutoResetEvent m_PlayEvent = new AutoResetEvent(false); 
		///  
		/// 波形输出设备句柄 
		///  
		private IntPtr m_WaveOut; 
		///  
		/// WAVE 文件控制块 
		///  
		private WaveNative.WaveHdr m_Header; 
		///  
		/// 暂存 WAVE 文件的数据 
		///  
		private byte[] m_HeaderData; 
		///  
		/// 保存 WAVE 文件句柄,用于操作 WAVE 文件(因为是非托管对象) 
		///  
		private GCHandle m_HeaderHandle; 
		///  
		/// 保存 WAVE 文件数据句柄,用于操作 WAVE 文件数据(因为是非托管对象) 
		///  
		private GCHandle m_HeaderDataHandle; 
		///  
		/// 该缓冲区的当前播放状态 
		///  
		private bool m_Playing; 
 
		///  
		/// 缓冲区空时回调方法 
		///  
		/// 设备指针 
		/// 用户信息 
		///  
		///  
		///  
		internal static void WaveOutProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2) 
		{ 
			if (uMsg == WaveNative.MM_WOM_DONE) 
			{ 
				try 
				{ 
					GCHandle h = (GCHandle)wavhdr.dwUser; 
					WaveOutBuffer buf = (WaveOutBuffer)h.Target; 
					buf.OnCompleted(); 
				} 
				catch 
				{ 
				} 
			} 
		} 
 
 
		///  
		/// 构造函数 
		///  
		/// 波形输出设备句柄 
		/// 缓冲区大小 
		public WaveOutBuffer(IntPtr waveOutHandle, int size) 
		{ 
			//保存波形输出设备句柄 
			m_WaveOut = waveOutHandle; 
			//获得 WAVE 文件句柄 
			m_HeaderHandle = GCHandle.Alloc(m_Header, GCHandleType.Pinned); 
			//将本实例指定为用户数据区 
			m_Header.dwUser = (IntPtr)GCHandle.Alloc(this); 
			//为用户数据设置缓冲区 
			m_HeaderData = new byte[size]; 
			//获得 WAVE 文件数据区句柄 
			m_HeaderDataHandle = GCHandle.Alloc(m_HeaderData, GCHandleType.Pinned); 
			//获得数据区的指针 
			m_Header.lpData = m_HeaderDataHandle.AddrOfPinnedObject(); 
			//设置 WAVE 文件结构--缓冲区大小 
			m_Header.dwBufferLength = size; 
			//为播放准备一个波形缓冲区 
			WaveOutHelper.Try(WaveNative.waveOutPrepareHeader(m_WaveOut, ref m_Header, Marshal.SizeOf(m_Header))); 
		} 
		~WaveOutBuffer() 
		{ 
			Dispose(); 
		} 
		public void Dispose() 
		{ 
			if (m_Header.lpData != IntPtr.Zero) 
			{ 
				WaveNative.waveOutUnprepareHeader(m_WaveOut, ref m_Header, Marshal.SizeOf(m_Header)); 
				m_HeaderHandle.Free(); 
				m_Header.lpData = IntPtr.Zero; 
			} 
			m_PlayEvent.Close(); 
			if (m_HeaderDataHandle.IsAllocated) 
				m_HeaderDataHandle.Free(); 
			GC.SuppressFinalize(this); 
		} 
 
		///  
		/// 返回缓冲区大小 
		///  
		public int Size 
		{ 
			get { return m_Header.dwBufferLength; } 
		} 
 
		///  
		/// 获得 WAVE 文件数据区句柄 
		///  
		public IntPtr Data 
		{ 
			get { return m_Header.lpData; } 
		} 
 
		///  
		/// 播放 
		///  
		/// 播放状态 
		public bool Play() 
		{ 
			lock(this) 
			{ 
				m_PlayEvent.Reset(); 
				m_Playing = WaveNative.waveOutWrite(m_WaveOut, ref m_Header, Marshal.SizeOf(m_Header)) == WaveNative.MMSYSERR_NOERROR; 
				return m_Playing; 
			} 
		} 
		///  
		/// 阻塞,直到正在播放的缓冲区播放完毕 
		///  
		public void WaitFor() 
		{ 
			if (m_Playing) 
			{ 
				m_Playing = m_PlayEvent.WaitOne(); 
			} 
			else 
			{ 
				Thread.Sleep(0); 
			} 
		} 
		///  
		/// 确定当前播放已完成 
		///  
		public void OnCompleted() 
		{ 
			m_PlayEvent.Set(); 
			m_Playing = false; 
		} 
	} 
 
 
	///  
	/// 该类实现音频的播放 
	///  
	public class WaveOutPlayer : IDisposable 
	{ 
		///  
		/// 代表输出设备的名柄 
		///  
		private IntPtr m_WaveOut; 
		///  
		/// linked list 
		/// 保存该次播放所用的缓冲池 
		///  
		private WaveOutBuffer m_Buffers;  
		///  
		/// 当前缓冲区 
		///  
		private WaveOutBuffer m_CurrentBuffer; 
		///  
		/// 自定义的线程,用于起用播放线程 
		///  
		private Thread m_Thread; 
		///  
		/// 保存缓冲区空时的处理器 
		///  
		private BufferFillEventHandler m_FillProc; 
		///  
		/// 播放是否完成 
		///  
		private bool m_Finished; 
		///  
		/// 用于将所有的位置零 
		///  
		private byte m_zero; 
 
		///  
		/// 缓冲区空时的回调方法 
		///  
		private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveOutBuffer.WaveOutProc); 
 
		///  
		/// 检取系统中存在的波形输出设备的数量 
		///  
		public static int DeviceCount 
		{ 
			get { return WaveNative.waveOutGetNumDevs(); } 
		} 
 
 
		///  
		/// 构造函数 
		///  
		/// 设备号 
		/// 格式 
		/// 缓冲区大小 
		/// 缓冲区个数 
		/// 缓冲区满时处理器 
		public WaveOutPlayer(int device, WaveFormat format, int bufferSize, int bufferCount, BufferFillEventHandler fillProc) 
		{ 
			//根据 WAVE 文件的每个采样需要的 bit 数设置 m_zero 的值 
			m_zero= format.wBitsPerSample == 8 ? (byte)128 : (byte)0; 
			//取得缓冲区空时事件 
			m_FillProc = fillProc; 
 
			//设备能否打开 
			//若能,则返回设备指针 
			WaveOutHelper.Try(WaveNative.waveOutOpen(out m_WaveOut, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION)); 
 
			//为音频输出分配给定的大小和个数 
			AllocateBuffers(bufferSize, bufferCount); 
			//起用播放线程进行播放 
			m_Thread = new Thread(new ThreadStart(ThreadProc)); 
			m_Thread.Start(); 
		} 
		~WaveOutPlayer() 
		{ 
			Dispose(); 
		} 
		public void Dispose() 
		{ 
			if (m_Thread != null) 
				try 
				{ 
					m_Finished = true; 
					if (m_WaveOut != IntPtr.Zero) 
						WaveNative.waveOutReset(m_WaveOut); 
					m_Thread.Join(); 
					m_FillProc = null; 
					FreeBuffers(); 
					if (m_WaveOut != IntPtr.Zero) 
						WaveNative.waveOutClose(m_WaveOut); 
				} 
				finally 
				{ 
					m_Thread = null; 
					m_WaveOut = IntPtr.Zero; 
				} 
			GC.SuppressFinalize(this); 
		} 
		///  
		///  
		///  
		private void ThreadProc() 
		{ 
			while (!m_Finished) 
			{ 
				Advance(); 
				if (m_FillProc != null && !m_Finished) 
					m_FillProc(m_CurrentBuffer.Data, m_CurrentBuffer.Size); 
				else 
				{ 
					// zero out buffer 
					byte v = m_zero; 
					byte[] b = new byte[m_CurrentBuffer.Size]; 
					for (int i = 0; i < b.Length; i++) 
						b[i] = v; 
					Marshal.Copy(b, 0, m_CurrentBuffer.Data, b.Length); 
 
				} 
				m_CurrentBuffer.Play(); 
			} 
			WaitForAllBuffers(); 
		} 
		///  
		/// 分配缓冲区 
		///  
		/// 缓冲区大小 
		/// 缓冲区数量 
		private void AllocateBuffers(int bufferSize, int bufferCount) 
		{ 
			FreeBuffers(); 
 
			if (bufferCount > 0) 
			{ 
				m_Buffers = new WaveOutBuffer(m_WaveOut, bufferSize); 
				WaveOutBuffer Prev = m_Buffers; 
				try 
				{ 
					//建立一个新的循环链表缓冲池 
					for (int i = 1; i < bufferCount; i++) 
					{ 
						WaveOutBuffer Buf = new WaveOutBuffer(m_WaveOut, bufferSize); 
						Prev.NextBuffer = Buf; 
						Prev = Buf; 
					} 
				} 
				finally 
				{ 
					Prev.NextBuffer = m_Buffers; 
				} 
			} 
		} 
		///  
		/// 清空缓冲区 
		///  
		private void FreeBuffers() 
		{ 
			m_CurrentBuffer = null; 
			if (m_Buffers != null) 
			{ 
				WaveOutBuffer First = m_Buffers; 
				m_Buffers = null; 
 
				WaveOutBuffer Current = First; 
				//循环清空缓冲池中的缓冲区 
				do 
				{ 
					WaveOutBuffer Next = Current.NextBuffer; 
					Current.Dispose(); 
					Current = Next; 
				} while(Current != First); 
			} 
		} 
		///  
		/// 将当前缓冲区移动到缓冲池中的下一个缓冲区 
		///  
		private void Advance() 
		{ 
			m_CurrentBuffer= m_CurrentBuffer == null ? m_Buffers : m_CurrentBuffer.NextBuffer; 
			m_CurrentBuffer.WaitFor(); 
		} 
		///  
		/// 循环等待缓冲池中的缓冲区 
		///  
		private void WaitForAllBuffers() 
		{ 
			WaveOutBuffer Buf = m_Buffers; 
			while (Buf.NextBuffer != m_Buffers) 
			{ 
				Buf.WaitFor(); 
				Buf = Buf.NextBuffer; 
			} 
		} 
	} 
}