音频文件解析(二):WAV格式文件波形绘制

  解析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)

音频文件解析(二):WAV格式文件波形绘制
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
View Code

 

你可能感兴趣的:(文件)