internal class WaveFile { #region 字段和属性 //文件路径 private string filepath; //文件详情对象 private FileInfo fileInfo; //文件流 private FileStream fileStream; private byte[] fileByteData; //临时存放byte数组 private byte[] tempByte; //是否需要追加信息的标记 private Boolean isNeedAppend; private DataBlock dataBlock; /// <summary> /// Data块 /// </summary> public DataBlock Data { get { return dataBlock; } } private FactBlock factBlock; /// <summary> /// fact块 /// </summary> public FactBlock Fact { get { return factBlock; } } private FmtBlock fmtBlock; /// <summary> /// fmt块 /// </summary> public FmtBlock Format { get { return fmtBlock; } } private RiffBlock riffBlock; /// <summary> /// riff块 /// </summary> public RiffBlock Riff { get { return riffBlock; } } /// <summary> /// 记录文件长度 /// </summary> public float FileLenth { get { return (float)dataBlock.DataSize / (float)fmtBlock.AverageBytesPerSec; } } private Boolean isWave; /// <summary> /// 记录是否是正确的wave文件 /// </summary> public Boolean IsWAVE { get { return isWave; } } #endregion /// <summary> /// 构造函数 /// </summary> /// <param name="inFilepath"></param> public WaveFile(String inFilepath) { tempByte = new byte[4]; filepath = inFilepath; riffBlock = new RiffBlock(); fmtBlock = new FmtBlock(); factBlock = new FactBlock(); dataBlock = new DataBlock(); fileInfo = new FileInfo(inFilepath); fileStream = new FileStream(inFilepath, FileMode.Open, FileAccess.ReadWrite);// m_FileInfo.OpenRead(); fileByteData = new byte[fileStream.Length]; fileStream.Read(fileByteData, 0, (int)fileStream.Length); fileStream.Dispose(); if(JudgeIsHaveFmt(fileByteData)) { if (!JudgeFmtIsRight(fileByteData)) { fileInfo = new FileInfo(inFilepath); fileStream = new FileStream(inFilepath, FileMode.Open, FileAccess.ReadWrite);// m_FileInfo.OpenRead(); fileByteData = new byte[fileStream.Length]; fileStream.Read(fileByteData, 0, (int)fileStream.Length); fileStream.Dispose(); } } else { isWave = false; return; } Read(fileByteData); Dispose(); //Read(fileStream); //fileStream.Dispose(); } /// <summary> /// 判断是否有fmt块 /// </summary> /// <param name="byteData"></param> private bool JudgeIsHaveFmt(byte[] byteData) { byte[] temp = new byte[4]; int index = 12; for (int i = 0; i < 4; i++) { temp[i] = byteData[index]; index++; } if (temp[0] != WaveMark.szRiffFormat[0] || temp[1] != WaveMark.szRiffFormat[1] || temp[2] != WaveMark.szRiffFormat[2] || temp[3] != WaveMark.szRiffFormat[3]) return false; return true; } /// <summary> /// 判断fmt块是否正确 不正确的话,重新生成文件 /// </summary> /// <param name="byteData"></param> private bool JudgeFmtIsRight(byte[] byteData) { #region format块 fmtBlock.FmtSize = System.BitConverter.ToUInt32(byteData, 16); fmtBlock.FmtTag = System.BitConverter.ToUInt16(byteData, 20); if ((fmtBlock.FmtTag == 6 || fmtBlock.FmtTag == 7) && fmtBlock.FmtSize == 16) { byteData[16] = 18; byte[] tempByteData = new byte[byteData.Length + 2]; for (int i = 0; i < 16 + 20; i++) { tempByteData[i] = byteData[i]; } tempByteData[36] = 0; tempByteData[37] = 0; for (int i = 36; i < byteData.Length; i++) { tempByteData[i+2] = byteData[i]; } File.WriteAllBytes(filepath,tempByteData); return false; } return true; #endregion } /// <summary> /// 通过byte[]来读取数据 /// </summary> private void Read(byte[] byteData) { #region riff块 isWave = false; for (int i = 0; i < 4; i++) { riffBlock.RiffID[i] = byteData[i]; } if (riffBlock.RiffID[0] != WaveMark.szRiffID[0] || riffBlock.RiffID[1] != WaveMark.szRiffID[1] || riffBlock.RiffID[2] != WaveMark.szRiffID[2] || riffBlock.RiffID[3] != WaveMark.szRiffID[3]) { return; } riffBlock.RiffSize = System.BitConverter.ToUInt32(byteData, 4); if ((uint)fileInfo.Length - 8 != riffBlock.RiffSize) { //return; } int y = 0; for (int i = 8; i < 12; i++) { riffBlock.RiffFormat[y] = byteData[i]; y++; } #endregion #region format块 y = 0; for (int i = 12; i < 16; i++) { fmtBlock.FmtID[y] = byteData[i]; y++; } if (fmtBlock.FmtID[0] != WaveMark.szRiffFormat[0] || fmtBlock.FmtID[1] != WaveMark.szRiffFormat[1] || fmtBlock.FmtID[2] != WaveMark.szRiffFormat[2] || fmtBlock.FmtID[3] != WaveMark.szRiffFormat[3]) return; fmtBlock.FmtSize = System.BitConverter.ToUInt32(byteData, 16); fmtBlock.FmtTag = System.BitConverter.ToUInt16(byteData, 20); fmtBlock.Channels = System.BitConverter.ToUInt16(byteData, 22); fmtBlock.SamplesPerSec = System.BitConverter.ToUInt32(byteData, 24); fmtBlock.AverageBytesPerSec = System.BitConverter.ToUInt32(byteData, 28); fmtBlock.BlockAlign = System.BitConverter.ToUInt16(byteData, 32); fmtBlock.BitsPerSample = System.BitConverter.ToUInt16(byteData, 34); #endregion #region fact块 y = 0; int index = (int)fmtBlock.FmtSize + 20; for (int i = index; i < index + 4; i++) { tempByte[y] = byteData[i]; y++; } index = index + 4; factBlock.FactID = tempByte; if (factBlock.FactID[0] == WaveMark.factID[0] && factBlock.FactID[1] == WaveMark.factID[1] && factBlock.FactID[2] == WaveMark.factID[2] && factBlock.FactID[3] == WaveMark.factID[3]) { #region Fact_Chunk factBlock.Size = System.BitConverter.ToUInt32(byteData, index); index = index + 4; index = index +(int)factBlock.Size; #endregion y = 0; for (int i = index; i < index + 4; i++) { tempByte[y] = byteData[i]; y++; } index = index + 4; } #endregion #region data块 dataBlock.DataID = tempByte; if (dataBlock.DataID[0] == WaveMark.dataID[0] && dataBlock.DataID[1] == WaveMark.dataID[1] && dataBlock.DataID[2] == WaveMark.dataID[2] && dataBlock.DataID[3] == WaveMark.dataID[3]) { y = 0; for (int i = index; i < index + 4; i++) { tempByte[y] = byteData[i]; y++; } index = index + 4; dataBlock.DataSize = BitConverter.ToUInt32(tempByte, 0); } dataBlock.DataArray = new Int16[dataBlock.DataSize]; dataBlock.NumSamples = (int)(dataBlock.DataSize); dataBlock.ByteDataArray = new byte[dataBlock.DataSize]; int z = 0; for (int i = index; z< dataBlock.DataSize; i++) { dataBlock.ByteDataArray[z] = byteData[i]; z++; } if (fmtBlock.FmtTag == 1)//pcm数据 { dataBlock.NumSamples = (int)(dataBlock.DataSize / 2); for (int i = 0; i < dataBlock.NumSamples; i++) { dataBlock.DataArray[i] = System.BitConverter.ToInt16(byteData, index);// byteData[index]; index += 2; } } else { byte[] bytedata = new byte[dataBlock.DataSize]; y = 0; for (int i = index; y < dataBlock.DataSize; i++) { bytedata[y] = byteData[i]; y++; } dataBlock.NumSamples = (int)(dataBlock.DataSize); if (fmtBlock.FmtTag == 6)//alaw数据 { for (int i = 0; i < dataBlock.NumSamples; i++) { dataBlock.DataArray[i] = (short)AlawToPcm(bytedata[i]); } } if (fmtBlock.FmtTag == 7)//ulaw数据 { for (int i = 0; i < dataBlock.NumSamples; i++) { dataBlock.DataArray[i] = (short)UlawToPCM(bytedata[i]); } } } isWave = true; #endregion } /// <summary> /// 读取数据 /// </summary> private void Read(FileStream inFS) { #region riff块 isWave = false; inFS.Read(riffBlock.RiffID, 0, 4); if (riffBlock.RiffID[0] != WaveMark.szRiffID[0] || riffBlock.RiffID[1] != WaveMark.szRiffID[1] || riffBlock.RiffID[2] != WaveMark.szRiffID[2] || riffBlock.RiffID[3] != WaveMark.szRiffID[3]) { return; } BinaryReader binRead = new BinaryReader(inFS); riffBlock.RiffSize = binRead.ReadUInt32(); if ((uint)fileInfo.Length - 8 != riffBlock.RiffSize) { //return; } inFS.Read(riffBlock.RiffFormat, 0, 4); #endregion #region format块 inFS.Read(fmtBlock.FmtID, 0, 4); if (fmtBlock.FmtID[0] != WaveMark.szRiffFormat[0] || fmtBlock.FmtID[1] != WaveMark.szRiffFormat[1] || fmtBlock.FmtID[2] != WaveMark.szRiffFormat[2] || fmtBlock.FmtID[3] != WaveMark.szRiffFormat[3]) return; fmtBlock.FmtSize = binRead.ReadUInt32(); fmtBlock.FmtTag = binRead.ReadUInt16(); fmtBlock.Channels = binRead.ReadUInt16(); fmtBlock.SamplesPerSec = binRead.ReadUInt32(); fmtBlock.AverageBytesPerSec = binRead.ReadUInt32(); fmtBlock.BlockAlign = binRead.ReadUInt16(); fmtBlock.BitsPerSample = binRead.ReadUInt16(); // This accounts for the variable format header size // 12 bytes of Riff Header, 4 bytes for FormatId, 4 bytes for FormatSize & the Actual size of the Format Header inFS.Seek(fmtBlock.FmtSize + 20, System.IO.SeekOrigin.Begin); #endregion #region fact块 inFS.Read(tempByte, 0, 4); factBlock.FactID = tempByte; if (factBlock.FactID[0] == WaveMark.factID[0] && factBlock.FactID[1] == WaveMark.factID[1] && factBlock.FactID[2] == WaveMark.factID[2] && factBlock.FactID[3] == WaveMark.factID[3]) { #region Fact_Chunk inFS.Read(tempByte, 0, 4); factBlock.Size = BitConverter.ToUInt32(tempByte, 0); inFS.Position += factBlock.Size; #endregion inFS.Read(tempByte, 0, 4); } #endregion #region data块 dataBlock.DataID = tempByte; if (dataBlock.DataID[0] == WaveMark.dataID[0] && dataBlock.DataID[1] == WaveMark.dataID[1] && dataBlock.DataID[2] == WaveMark.dataID[2] && dataBlock.DataID[3] == WaveMark.dataID[3]) { inFS.Read(tempByte, 0, 4); dataBlock.DataSize = BitConverter.ToUInt32(tempByte, 0); //if (m_Data.DataSize != (uint)m_FileInfo.Length - (uint)inFS.Position) //{ // uint size2 = (uint)m_FileInfo.Length - (uint)inFS.Position; // byte[] bpara = System.BitConverter.GetBytes(size2); // inFS.Seek(inFS.Position - 4, SeekOrigin.Begin);//定位文件头 // foreach (byte bt in bpara) // inFS.WriteByte(bt); //} } else { //wave文件数据 dataBlock.DataSize = riffBlock.RiffSize + 8 - (uint)inFS.Position; } //m_Data.DataSize = (uint)m_FileInfo.Length - (uint)inFS.Position; dataBlock.DataArray = new Int16[dataBlock.DataSize]; dataBlock.NumSamples = (int)(dataBlock.DataSize); if (fmtBlock.FmtTag == 1)//pcm数据 { inFS.Seek(40, System.IO.SeekOrigin.Begin); dataBlock.NumSamples = (int)(dataBlock.DataSize / 2); for (int i = 0; i < dataBlock.NumSamples; i++) { dataBlock.DataArray[i] = binRead.ReadInt16(); } } else { byte[] bytedata = new byte[dataBlock.DataSize]; inFS.Read(bytedata, 0, (int)dataBlock.DataSize); dataBlock.NumSamples = (int)(dataBlock.DataSize); if (fmtBlock.FmtTag == 6)//alaw数据 { for (int i = 0; i < dataBlock.NumSamples; i++) { dataBlock.DataArray[i] = (short)AlawToPcm(bytedata[i]); } } if (fmtBlock.FmtTag == 7)//ulaw数据 { for (int i = 0; i < dataBlock.NumSamples; i++) { dataBlock.DataArray[i] = (short)UlawToPCM(bytedata[i]); } } } isWave = true; #endregion } /// <summary> /// 释放资源 /// </summary> public void Dispose() { fileInfo = null; fileStream.Dispose(); } #region alaw转pcm 、ulaw转pcm /// <summary> /// alaw转pcm /// </summary> /// <param name="a_val"></param> /// <returns></returns> private int AlawToPcm(byte a_val) { int t; int seg; a_val ^= 0x55; t = (a_val & 0xf) << 4; seg = (a_val & 0x70) >> 4; switch (seg) { case 0: t += 8; break; case 1: t += 0x108; break; default: t += 0x108; t <<= seg - 1; break; } if ((a_val & 0x80) == 0) { return -t; } return t; //return ((a_val & 0x80) ? t : -t); } /// <summary> /// ulaw转pcm /// </summary> /// <param name="u_val"></param> /// <returns></returns> private int UlawToPCM(byte u_val) { int t; int u = (int)u_val; /* Complement to obtain normal u-law value. */ u = ~u; t = ((u & 0xf) << 3) + 0x84; t <<= (u & 0x70) >> 4; if ((u & 0x80) == 0) return t - 0x84; return (0x84 - t); } #endregion #region 类: riff、fmt、fact、data /// <summary> /// riff块 /// </summary> public class RiffBlock { public RiffBlock() { m_RiffID = new byte[4]; m_RiffFormat = new byte[4]; } private byte[] m_RiffID; //文件前四个字节 为RIFF public byte[] RiffID { get { return m_RiffID; } set { m_RiffID = value; } } private uint m_RiffSize; /// <summary> /// 数据大小 文件大小= 这个数字+8 /// </summary> public uint RiffSize { get { return m_RiffSize; } set { m_RiffSize = value; } } private byte[] m_RiffFormat; /// <summary> /// wave /// </summary> public byte[] RiffFormat { get { return m_RiffFormat; } set { m_RiffFormat = value; } } } /// <summary> /// format块 /// </summary> public class FmtBlock { public FmtBlock() { fmtID = new byte[4]; } private byte[] fmtID; /// <summary> /// 固定为 是"fmt " /// 以'fmt '作为标示 /// </summary> public byte[] FmtID { get { return fmtID; } set { fmtID = value; } } private uint fmtSize; /// <summary> /// 一般情况下Size为16,此时最后附加信息没有;如果为18 /// 则最后多了2个字节的附加信息 /// </summary> public uint FmtSize { get { return fmtSize; } set { fmtSize = value; } } private ushort fmtTag; /// <summary> /// fmt /// </summary> public ushort FmtTag { get { return fmtTag; } set { fmtTag = value; } } private ushort channels; /// <summary> /// 声道数 /// </summary> public ushort Channels { get { return channels; } set { channels = value; } } private uint samplesPerSec; // 采样率(每秒样本数),表示每个通道的播放速度, public uint SamplesPerSec { get { return samplesPerSec; } set { samplesPerSec = value; } } private uint averageBytesPerSec; /// <summary> /// 波形音频数据传送速率,其值为通道数*每秒数据位数*每样 /// 本的数据位数/8。播放软件利用此值可以估计缓冲区的大小。 /// </summary> public uint AverageBytesPerSec { get { return averageBytesPerSec; } set { averageBytesPerSec = value; } } private ushort blockAlign; public ushort BlockAlign { get { return blockAlign; } set { blockAlign = value; } } private ushort bitsPerSample; /// <summary> /// 每样本的数据位数,表示每个声道中各个样本的数据位数。如果有多 /// 个声道,对每个声道而言,样本大小都一样。 /// </summary> public ushort BitsPerSample { get { return bitsPerSample; } set { bitsPerSample = value; } } } /// <summary> /// fact块 /// </summary> public class FactBlock { /// <summary> /// 构造函数 /// </summary> public FactBlock() { factId = new byte[4]; } #region 字段、属性 private byte[] factId; /// <summary> /// 文件前四个字节 为fact /// </summary> public byte[] FactID { get { return factId; } set { factId = value; } } private uint size; /// <summary> /// 数据大小 /// </summary> public uint Size { get { return size; } set { size = value; } } #endregion } /// <summary> /// data块 /// </summary> public class DataBlock { /// <summary> /// 构造函数 /// </summary> public DataBlock() { DataID = new byte[4]; } #region 字段、属性 private byte[] m_DataID; /// <summary> /// 文件前四个字节 为data /// </summary> public byte[] DataID { get { return m_DataID; } set { m_DataID = value; } } private uint m_DataSize; /// <summary> /// 大小 /// </summary> public uint DataSize { get { return m_DataSize; } set { m_DataSize = value; } } private Int16[] m_Data; /// <summary> /// 数据 /// </summary> public Int16[] DataArray { get { return m_Data; } set { m_Data = value; } } private Byte[] byteDataArray; /// <summary> /// 数据 /// </summary> public Byte[] ByteDataArray { get { return byteDataArray; } set { byteDataArray = value; } } //public Int16 this[int pos] //{ // get { return m_Data[pos]; } // set { m_DataID = value; } //} private int m_NumSamples; /// <summary> /// 采样数 /// </summary> public int NumSamples { get { return m_NumSamples; } set { m_NumSamples = value; } } #endregion } #endregion } /// <summary> /// 文件头 标识类 /// </summary> public static class WaveMark { /// <summary> /// 文件前四个字节 为RIFF /// </summary> public static byte[] szRiffID = new byte[] { 0x52, 0x49, 0x46, 0x46 }; // 'R','I','F','F' /// <summary> ///WAVE文件定义 为WAVE /// </summary> public static byte[] szRiffWaveID = new byte[] { 0x57, 0x41, 0x56, 0x45 }; // 'W','A','V','E' /// <summary> /// 固定为 是"fmt "字后一位为0x20 /// </summary> public static byte[] szRiffFormat = new byte[] { 0x66, 0x6D, 0x74, 0x20 }; // fmt /// <summary> /// 文件前四个字节 为fact /// </summary> public static byte[] factID = new byte[] { 0x66, 0x61, 0x63, 0x74 }; // 'f','a','c','t' /// <summary> /// 文件前四个字节 为RIFF /// </summary> public static byte[] dataID = new byte[] { 0x64, 0x61, 0x74, 0x61 }; // 'd','a','t','a' } /// <summary> /// 音频格式 /// </summary> public enum EnumAudioType { /// <summary> /// 未知格式 /// </summary> UnKnown = 0, /// <summary> /// 8k U-law 单声道 /// </summary> Ulaw8k1 = 1, /// <summary> /// 8k U-law 双声道 /// </summary> Ulaw8k2 = 2, /// <summary> /// 8K A-law单声道 /// </summary> Alaw8k1 = 3, /// <summary> /// 8K A-law双声道 /// </summary> Alaw8k2 = 4, /// <summary> /// 16K A-law单声道 /// </summary> Alaw16k1 = 5, /// <summary> /// 16K A-law双声道 /// </summary> Alaw16k2 = 6, /// <summary> /// 8K 8bit PCM单声道 /// </summary> Linear8k8bit1 = 7, /// <summary> /// 8K 8bit PCM双声道 /// </summary> Linear8k8bit2 = 8, /// <summary> /// 8K 16bit PCM单声道 /// </summary> Linear8k16bit1 = 9, /// <summary> /// 8K 16bit PCM双声道 /// </summary> Linear8k16bit2 = 10, /// <summary> /// 16K 16bit PCM单声道 /// </summary> Linear16k16bit1 = 11, /// <summary> /// 16K 16bit PCM双声道 /// </summary> Linear16k16bit2 = 12, /// <summary> /// 16K 8bit PCM单声道 /// </summary> Linear16k8bit1 = 13, /// <summary> /// 16K 8bit PCM双声道 /// </summary> Linear16k8bit2 = 14, /// <summary> /// 16k U-law 单声道 /// </summary> Ulaw16k1 = 15, /// <summary> /// 16k U-law 双声道 /// </summary> Ulaw16k2 = 16 }