简介
WAV 为微软开发的一种vb.net教程声音文件格式,它符合 RIFF(Resource Interchange File Format)文件规范,用于保存 Windows 平台c#教程的音频信息资源。
第一节 文件头部格式
文件头(Header)是位于文件python基础教程开头的一段承担一定任务的数据,通常是对主体数据的描述。
WAV 文件头由java基础教程哪几部分构成
RIFF块(RIFF-Chunk)
格式化块(Format-Chunk)
附加块(Fact-Chunk)块偏移sql教程地址需要根据实际数据变更
数据块(Data-Chunk)块偏移地址需要根据实际数据变更
| 偏移地址 | 字节数 | 数据类型 | 内容 |
| &H00 | 4 | String | 'RIFF'文件标志 |
| &H04 | 4 | UInteger | 文件总长 |
| &H08 | 4 | String | 'WAVE'文件标志 |
表1-1 RIFF块(RIFF-Chunk)
| 偏移地址 | 字节数 | 数据类型 | 内容 |
| &H0C | 4 | String | 'fmt'标志 |
| &H10 | 4 | UInteger | 块长度 |
| &H12 | 2 | UShort | PCM格式类别 |
| &H14 | 2 | UShort | 声道数目 |
| &H18 | 4 | UInteger | 采样率 |
| &H1C | 4 | UInteger | 传输速率 |
| &H1E | 2 | UShort | 数据块对齐 |
| &H20 | 2 | UShort | 每样本bit数 |
| &H22 | 2 | UShort | 可选 |
表1-2 格式化块(Format-Chunk)
| 偏移地址 | 字节数 | 数据类型 | 内容 |
| &H26 | 4 | String | 'fact'标志 |
| &H2A | 4 | UInteger | 块长度 |
| &H2E | 4 | UInteger | 附加信息 |
表1-3 附加块(Fact-Chunk)
| 偏移地址 | 字节数 | 数据类型 | 内容 |
| &H32 | 4 | String | 'data'文件标志 |
| &H36 | 4 | UInteger | 数据块总长 |
表1-4 数据块(Data-Chunk)
第二节 代码实现
1. 构建一个 WaveHeader 结构体


''' <summary>
''' wav音频头部信息
''' </summary>
Public Structure WaveHeader
#Region "RiffChunk"
''' <summary>
''' RIFF标志
''' </summary>
Dim RIFF As String
''' <summary>
''' 文件长度
''' </summary>
Dim FileSize As UInteger
''' <summary>
''' WAVE标志
''' </summary>
Dim WAVE As String
#End Region
#Region "FormatChunk"
''' <summary>
''' FORMAT标志
''' </summary>
Dim FORMAT As String
''' <summary>
''' Format长度
''' </summary>
Dim FormatSize As UInteger
''' <summary>
''' 编码方式
''' </summary>
Dim FilePadding As UShort
''' <summary>
''' 声道数目
''' </summary>
Dim FormatChannels As UShort
''' <summary>
''' 采样频率
''' </summary>
Dim SamplesPerSecond As UInteger
''' <summary>
''' 每秒所需字节数
''' </summary>
Dim AverageBytesPerSecond As UInteger
''' <summary>
''' 数据块对齐单位
''' </summary>
Dim BytesPerSample As UShort
''' <summary>
''' 单个采样所需Bit数
''' </summary>
Dim BitsPerSample As UShort
''' <summary>
''' 附加信息
''' </summary>
Dim FormatExtra As UShort
#End Region
#Region "FactChunk"
''' <summary>
''' FACT标志
''' </summary>
Dim FACT As String
''' <summary>
''' Fact长度
''' </summary>
Dim FactSize As UInteger
''' <summary>
''' Fact信息
''' </summary>
Dim FactInf As UInteger
#End Region
#Region "DataChunk"
''' <summary>
''' DATA标志
''' </summary>
Dim DATA As String
''' <summary>
''' Data长度
''' </summary>
Dim DataSize As UInteger
#End Region
End Structure



/// <summary>
/// wav音频头部信息
/// </summary>
public struct WaveHeader
{
#region "RiffChunk"
/// <summary>
/// RIFF标志
/// </summary>
public string RIFF;
/// <summary>
/// 文件长度
/// </summary>
public uint FileSize;
/// <summary>
/// WAVE标志
/// </summary>
#endregion
public string WAVE;
#region "FormatChunk"
/// <summary>
/// FORMAT标志
/// </summary>
public string FORMAT;
/// <summary>
/// Format长度
/// </summary>
public uint FormatSize;
/// <summary>
/// 编码方式
/// </summary>
public ushort FilePadding;
/// <summary>
/// 声道数目
/// </summary>
public ushort FormatChannels;
/// <summary>
/// 采样频率
/// </summary>
public uint SamplesPerSecond;
/// <summary>
/// 每秒所需字节数
/// </summary>
public uint AverageBytesPerSecond;
/// <summary>
/// 数据块对齐单位
/// </summary>
public ushort BytesPerSample;
/// <summary>
/// 单个采样所需Bit数
/// </summary>
public ushort BitsPerSample;
/// <summary>
/// 附加信息
/// </summary>
#endregion
public ushort FormatExtra;
#region "FactChunk"
/// <summary>
/// FACT标志
/// </summary>
public string FACT;
/// <summary>
/// Fact长度
/// </summary>
public uint FactSize;
/// <summary>
/// Fact信息
/// </summary>
#endregion
public uint FactInf;
#region "DataChunk"
/// <summary>
/// DATA标志
/// </summary>
public string DATA;
/// <summary>
/// Data长度
/// </summary>
#endregion
public uint DataSize;
}

2. 打开 *.wav 二进制文件

Dim data() As Byte = My.Computer.FileSystem.ReadAllBytes(wavFileName)

byte[] data = System.IO.File.ReadAllBytes(wavFileName);
3. 文件头部信息解析


''' <summary>
''' 返回指定字节数组包含的Wave头部信息
''' </summary>
Public Function GetWaveHeaderFromBytes(data As Byte()) As WaveHeader
Dim header As New WaveHeader
Dim tempIndex As UShort = 0
header.RIFF = CType(System.Text.Encoding.ASCII.GetChars(data, 0, 4), String)
header.FileSize = System.BitConverter.ToUInt32(data, 4)
header.WAVE = CType(System.Text.Encoding.ASCII.GetChars(data, 8, 4), String)
'FormatChunk
header.FORMAT = CType(System.Text.Encoding.ASCII.GetChars(data, 12, 4), String)
header.FormatSize = System.BitConverter.ToUInt32(data, 16)
header.FilePadding = System.BitConverter.ToUInt16(data, 20)
header.FormatChannels = System.BitConverter.ToUInt16(data, 22)
header.SamplesPerSecond = System.BitConverter.ToUInt32(data, 24)
header.AverageBytesPerSecond = System.BitConverter.ToUInt32(data, 28)
header.BytesPerSample = System.BitConverter.ToUInt16(data, 32)
header.BitsPerSample = System.BitConverter.ToUInt16(data, 34)
If header.FormatSize = 18 Then
header.FormatExtra = System.BitConverter.ToUInt16(data, 36)
Else
header.FormatExtra = 0
End If
tempIndex = 20 + header.FormatSize
'FactChunk
header.FACT = CType(System.Text.Encoding.ASCII.GetChars(data, tempIndex, 4), String)
If header.FACT = "fact" Then
header.FactSize = System.BitConverter.ToUInt32(data, tempIndex + 4)
header.FactInf = IIf(header.FactSize = 2, System.BitConverter.ToUInt16(data, tempIndex + 8), System.BitConverter.ToUInt32(data, tempIndex + 8))
tempIndex = tempIndex + header.FactSize + 8
Else
header.FACT = "NULL"
header.FactSize = 0
header.FactInf = 0
End If
'DataChunk
header.DATA = CType(System.Text.Encoding.ASCII.GetChars(data, tempIndex, 4), String)
header.DataSize = System.BitConverter.ToUInt32(data, tempIndex + 4)
Return header
End Function



/// <summary>
/// 返回指定字节数组包含的Wave头部信息
/// </summary>
public WaveHeader GetWaveHeaderFromBytes(byte[] data)
{
WaveHeader header = new WaveHeader();
ushort tempIndex = 0;
header.RIFF = Convert.ToString(System.Text.Encoding.ASCII.GetChars(data, 0, 4));
header.FileSize = System.BitConverter.ToUInt32(data, 4);
header.WAVE = Convert.ToString(System.Text.Encoding.ASCII.GetChars(data, 8, 4));
//FormatChunk
header.FORMAT = Convert.ToString(System.Text.Encoding.ASCII.GetChars(data, 12, 4));
header.FormatSize = System.BitConverter.ToUInt32(data, 16);
header.FilePadding = System.BitConverter.ToUInt16(data, 20);
header.FormatChannels = System.BitConverter.ToUInt16(data, 22);
header.SamplesPerSecond = System.BitConverter.ToUInt32(data, 24);
header.AverageBytesPerSecond = System.BitConverter.ToUInt32(data, 28);
header.BytesPerSample = System.BitConverter.ToUInt16(data, 32);
header.BitsPerSample = System.BitConverter.ToUInt16(data, 34);
if (header.FormatSize == 18) {
header.FormatExtra = System.BitConverter.ToUInt16(data, 36);
} else {
header.FormatExtra = 0;
}
tempIndex = 20 + header.FormatSize;
//FactChunk
header.FACT = Convert.ToString(System.Text.Encoding.ASCII.GetChars(data, tempIndex, 4));
if (header.FACT == "fact") {
header.FactSize = System.BitConverter.ToUInt32(data, tempIndex + 4);
header.FactInf = (header.FactSize == 2 ? System.BitConverter.ToUInt16(data, tempIndex + 8) : System.BitConverter.ToUInt32(data, tempIndex + 8));
tempIndex = tempIndex + header.FactSize + 8;
} else {
header.FACT = "NULL";
header.FactSize = 0;
header.FactInf = 0;
}
//DataChunk
header.DATA = Convert.ToString(System.Text.Encoding.ASCII.GetChars(data, tempIndex, 4));
header.DataSize = System.BitConverter.ToUInt32(data, tempIndex + 4);
return header;
}




















