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
}