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();
}
}
}