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


using System; 
using System.IO; 
 
namespace WaveLib 
{ 
	///  
	/// WAVE 文件流 
	///  
	public class WaveStream : Stream, IDisposable 
	{ 
		//private System.IO.MemoryStream waveStream ; 
		private Stream m_Stream; 
		///  
		/// 当前位置 
		///  
		private long m_DataPos; 
		///  
		/// 长度 
		///  
		private long m_Length; 
 
		//格式 
		private WaveFormat m_Format; 
 
		///  
		/// 该文件的格式(即 WAVE 文件的格式) 
		///  
		public WaveFormat Format 
		{ 
			get { return m_Format; } 
		} 
 
 
		///  
		/// 获取WAVE 文件的 Chunk 的值 
		///  
		///  
		///  
		private string ReadChunk(BinaryReader reader) 
		{ 
			byte[] ch = new byte[4]; 
			reader.Read(ch, 0, ch.Length); 
			return System.Text.Encoding.ASCII.GetString(ch); 
		} 
 
		///  
		/// 解析 WAVE 文件的 Chunk 
		///  
		private void ReadHeader() 
		{ 
			BinaryReader Reader = new BinaryReader(m_Stream); 
			//分析 RIFF WAVE Chunk 的 ID 
			if(ReadChunk(Reader) != "RIFF") 
				throw new Exception("Invalid file format"); 
 
			//跳过 RIFF WAVE Chunk 的 Size 
			Reader.ReadInt32(); // File length minus first 8 bytes of RIFF description, we don't use it 
 
			//分析 RIFF WAVE Chunk 的 Type 
			if (ReadChunk(Reader) != "WAVE") 
				throw new Exception("Invalid file format"); 
 
			//分析 Format Chunk 的 ID 
			if (ReadChunk(Reader) != "fmt ") 
				throw new Exception("Invalid file format"); 
 
			//分析 Format Chunk 的 Size,数值为16或18,18则最后又附加信息 
			int len = Reader.ReadInt32(); 
			if (len < 16) // bad format chunk length 
				throw new Exception("Invalid file format"); 
 
			m_Format = new WaveFormat(22050, 16, 2); // initialize to any format 
			//分析 Format Chunk 的 FormatTag; 编码方式,一般为0x0001  
			m_Format.wFormatTag = Reader.ReadInt16(); 
			//分析 Format Chunk 的 Channels; 声道数目,1--单声道;2--双声道 
			m_Format.nChannels = Reader.ReadInt16(); 
			//分析 Format Chunk 的 SamplesPerSec,采样频率 
			m_Format.nSamplesPerSec = Reader.ReadInt32(); 
			//分析 Format Chunk 的 AvgBytesPerSec,每秒所需字节数  
			m_Format.nAvgBytesPerSec = Reader.ReadInt32(); 
			//分析 Format Chunk 的 BlockAlign,数据块对齐单位(每个采样需要的字节数) 
			m_Format.nBlockAlign = Reader.ReadInt16(); 
			//分析 Format Chunk 的 BitsPerSample,每个采样需要的bit数 
			m_Format.wBitsPerSample = Reader.ReadInt16();  
 
			//跳过两个字节的附加信息 
			// advance in the stream to skip the wave format block  
			len -= 16; // minimum format size 
			while (len > 0) 
			{ 
				Reader.ReadByte(); 
				len--; 
			} 
 
			//跳过 Fact Chunk,定位到 Data Chunk 的起始位置 
			// assume the data chunk is aligned 
			while(m_Stream.Position < m_Stream.Length && ReadChunk(Reader) != "data") 
				; 
 
			if (m_Stream.Position >= m_Stream.Length) 
				throw new Exception("Invalid file format"); 
 
			//分析 Data Chunk 的 Size 
			m_Length = Reader.ReadInt32(); 
			//保存 Data 在 m_Stream 中的位置 
			m_DataPos = m_Stream.Position; 
 
			Position = 0; 
		} 
 
 
		public WaveStream(string fileName) : this(new FileStream(fileName, FileMode.Open)) 
		{ 
		} 
		public WaveStream(Stream S) 
		{ 
			m_Stream = S; 
			ReadHeader(); 
		} 
		~WaveStream() 
		{ 
			Dispose(); 
		} 
		public void Dispose() 
		{ 
			if (m_Stream != null) 
				m_Stream.Close(); 
			GC.SuppressFinalize(this); 
		} 
 
 
		public override bool CanRead 
		{ 
			get { return true; } 
		} 
		public override bool CanSeek 
		{ 
			get { return true; } 
		} 
		public override bool CanWrite 
		{ 
			get { return false; } 
		} 
		public override long Length 
		{ 
			get { return m_Length; } 
		} 
		public override long Position 
		{ 
			get { return m_Stream.Position - m_DataPos; } 
			set { Seek(value, SeekOrigin.Begin); } 
		} 
		public override void Close() 
		{ 
			Dispose(); 
		} 
		public override void Flush() 
		{ 
		} 
		public override void SetLength(long len) 
		{ 
			throw new InvalidOperationException(); 
		} 
		public override long Seek(long pos, SeekOrigin o) 
		{ 
			switch(o) 
			{ 
				case SeekOrigin.Begin: 
					m_Stream.Position = pos + m_DataPos; 
					break; 
				case SeekOrigin.Current: 
					m_Stream.Seek(pos, SeekOrigin.Current); 
					break; 
				case SeekOrigin.End: 
					m_Stream.Position = m_DataPos + m_Length - pos; 
					break; 
			} 
			return this.Position; 
		} 
 
 
		public override int Read(byte[] buf, int ofs, int count) 
		{ 
			int toread = (int)Math.Min(count, m_Length - Position); 
			return m_Stream.Read(buf, ofs, toread); 
		} 
		public override void Write(byte[] buf, int ofs, int count) 
		{ 
			throw new InvalidOperationException(); 
		} 
	} 
}