解析WAV头部信息后,接下来就可以根据相关参数和DATA块数据绘制波形.
1.重新编码(转换为8bits,单声道数据)
Public Function GetFormatData(ByVal pData() As Byte, ByVal pWaveHeader As waveHeaderStructre) As Byte() Dim temp As Integer Dim data() As Byte = {} If pWaveHeader.BitsPerSample = 8 And pWaveHeader.FormatChannels = 1 Then ReDim data(pData.Length - 1) For i = 0 To data.Length - 1 data(i) = pData(i) Next ElseIf pWaveHeader.BitsPerSample = 8 And pWaveHeader.FormatChannels = 2 Then ReDim data(pData.Length / 2 - 1) For i = 0 To data.Length - 1 data(i) = pData(i * 2) Next ElseIf pWaveHeader.BitsPerSample = 16 And pWaveHeader.FormatChannels = 1 Then ReDim data(pData.Length / 2 - 1) For i = 0 To data.Length - 1 temp = System.BitConverter.ToInt16(pData, i * 2) / 256 + 127 temp = IIf(temp > 255, 255, temp) temp = IIf(temp < 0, 0, temp) data(i) = temp Next ElseIf pWaveHeader.BitsPerSample = 16 And pWaveHeader.FormatChannels = 2 Then ReDim data(pData.Length / 4 - 1) For i = 0 To data.Length - 1 temp = System.BitConverter.ToInt16(pData, i * 4) / 256 + 127 temp = IIf(temp > 255, 255, temp) temp = IIf(temp < 0, 0, temp) data(i) = temp Next End If Return data End Function
2.显示波形
Public Sub PaintingWave(ByVal pData() As Byte, ByVal pWaveHeader As waveHeaderStructre, ByVal pBox As PictureBox) Dim pg As Graphics = pBox.CreateGraphics Dim pwidth As Integer = pBox.Width Dim pheight As Integer = pBox.Height Dim points As New List(Of PointF) Dim PImage As Bitmap = New Bitmap(pwidth, pheight) pg = Drawing.Graphics.FromImage(PImage) For i = 0 To pheight '绘制渐变背景 pg.DrawLine(New Pen(Color.FromArgb(100 + Math.Abs(i / (pheight / 255) - 128), 0, 0, 0), 1), 0, i, pwidth, i) Next For i = 0 To pData.Length - 1 '波形的离散数据点 points.Add(New PointF(i * (pwidth / pData.Length), pheight - pData(i) * (pheight / 255))) Next pg.DrawLines(New Pen(Color.FromArgb(0, 0, 0)), points.ToArray) pBox.Image = PImage pg.Dispose() End Sub
3.完整WAV分析封装类(头部信息解析,重新编码,波形可视化)
示例:
Dim SamplesWave As New WaveClass("F:\Music\李宗盛-山丘.wav")
SamplesWave.PaintWave(PictureBox1)
Class WaveClass Public waveHeadInf As waveHeaderStructre 'wav文件头部信息 Dim fileData() As Byte '文件原始数据 Public waveData() As Byte 'DATA块原始数据 Structure waveHeaderStructre 'RiffChunk Dim RIFF As String Dim FileSize As UInteger Dim WAVE As String 'FormatChunk Dim FORMAT As String Dim FormatSize As UInteger Dim FilePadding As UShort Dim FormatChannels As UShort Dim SamplesPerSecond As UInteger Dim AverageBytesPerSecond As UInteger Dim BytesPerSample As UShort Dim BitsPerSample As UShort Dim FormatExtra As UShort 'FactChunk Dim FACT As String Dim FactSize As UInteger Dim FactInf As UInteger 'DataChunk Dim DATA As String Dim DataSize As UInteger End Structure Public Sub New(ByVal FileName As String) fileData = My.Computer.FileSystem.ReadAllBytes(FileName) '加载wav文件 SplitWaveData(fileData) '分析头部,并获取DATA块数据 End Sub Public Sub PaintWave(ByVal pBox As PictureBox, Optional ByVal pData() As Byte = Nothing) '指定PictureBox绘制波形 If pData Is Nothing Then pData = GetFormatData() Dim pg As Graphics = pBox.CreateGraphics Dim pwidth As Integer = pBox.Width Dim pheight As Integer = pBox.Height Dim points As New List(Of PointF) Dim PImage As Bitmap = New Bitmap(pwidth, pheight) pg = Drawing.Graphics.FromImage(PImage) For i = 0 To pheight '绘制渐变背景 pg.DrawLine(New Pen(Color.FromArgb(100 + Math.Abs(i / (pheight / 255) - 128), 0, 0, 0), 1), 0, i, pwidth, i) Next For i = 0 To pData.Length - 1 '波形的离散数据点 points.Add(New PointF(i * (pwidth / pData.Length), pheight - pData(i) * (pheight / 255))) Next pg.DrawLines(New Pen(Color.FromArgb(0, 0, 0)), points.ToArray) pBox.Image = PImage pg.Dispose() End Sub Private Sub SplitWaveData(ByVal data As Byte()) '提取wav文件头部信息 Dim tempIndex As UShort = 0 waveHeadInf.RIFF = CType(System.Text.Encoding.ASCII.GetChars(data, 0, 4), String) waveHeadInf.FileSize = System.BitConverter.ToUInt32(data, 4) waveHeadInf.WAVE = CType(System.Text.Encoding.ASCII.GetChars(data, 8, 4), String) 'FormatChunk waveHeadInf.FORMAT = CType(System.Text.Encoding.ASCII.GetChars(data, 12, 4), String) waveHeadInf.FormatSize = System.BitConverter.ToUInt32(data, 16) waveHeadInf.FilePadding = System.BitConverter.ToUInt16(data, 20) waveHeadInf.FormatChannels = System.BitConverter.ToUInt16(data, 22) waveHeadInf.SamplesPerSecond = System.BitConverter.ToUInt32(data, 24) waveHeadInf.AverageBytesPerSecond = System.BitConverter.ToUInt32(data, 28) waveHeadInf.BytesPerSample = System.BitConverter.ToUInt16(data, 32) waveHeadInf.BitsPerSample = System.BitConverter.ToUInt16(data, 34) If waveHeadInf.FormatSize = 18 Then waveHeadInf.FormatExtra = System.BitConverter.ToUInt16(data, 36) Else waveHeadInf.FormatExtra = 0 End If tempIndex = 20 + waveHeadInf.FormatSize 'FactChunk waveHeadInf.FACT = CType(System.Text.Encoding.ASCII.GetChars(data, tempIndex, 4), String) If waveHeadInf.FACT = "fact" Then waveHeadInf.FactSize = System.BitConverter.ToUInt32(data, tempIndex + 4) waveHeadInf.FactInf = IIf(waveHeadInf.FactSize = 2, System.BitConverter.ToUInt16(data, tempIndex + 8), System.BitConverter.ToUInt32(data, tempIndex + 8)) tempIndex = tempIndex + waveHeadInf.FactSize + 8 Else waveHeadInf.FACT = "NULL" waveHeadInf.FactSize = 0 waveHeadInf.FactInf = 0 End If 'DataChunk waveHeadInf.DATA = CType(System.Text.Encoding.ASCII.GetChars(data, tempIndex, 4), String) waveHeadInf.DataSize = System.BitConverter.ToUInt32(data, tempIndex + 4) tempIndex = tempIndex + 8 '提取DATA数据块 ReDim waveData(data.Length - tempIndex) Array.Copy(data, tempIndex, waveData, 0, data.Length - tempIndex) End Sub Private Function GetFormatData() As Byte() '重新编码 Dim temp As Integer Dim data() As Byte = {} If waveHeadInf.BitsPerSample = 8 And waveHeadInf.FormatChannels = 1 Then ReDim data(waveData.Length - 1) For i = 0 To data.Length - 1 data(i) = waveData(i) Next ElseIf waveHeadInf.BitsPerSample = 8 And waveHeadInf.FormatChannels = 2 Then ReDim data(waveData.Length / 2 - 1) For i = 0 To data.Length - 1 data(i) = waveData(i * 2) Next ElseIf waveHeadInf.BitsPerSample = 16 And waveHeadInf.FormatChannels = 1 Then ReDim data(waveData.Length / 2 - 1) For i = 0 To data.Length - 1 temp = System.BitConverter.ToInt16(waveData, i * 2) / 256 + 127 temp = IIf(temp > 255, 255, temp) temp = IIf(temp < 0, 0, temp) data(i) = temp Next ElseIf waveHeadInf.BitsPerSample = 16 And waveHeadInf.FormatChannels = 2 Then ReDim data(waveData.Length / 4 - 1) For i = 0 To data.Length - 1 temp = System.BitConverter.ToInt16(waveData, i * 4) / 256 + 127 temp = IIf(temp > 255, 255, temp) temp = IIf(temp < 0, 0, temp) data(i) = temp Next End If Return data End Function End Class