Class CWAVReader
'by ENO
'To Read a WAV File and Populate basic Properties
'On 3/11/2007
'For AfricaDotNet user group
'BigEndian bytes number 0 - 4
Private mChunkID As String
Public ReadOnly Property ChunkID() As String
Get
ChunkID = mChunkID
End Get
End Property
'from the Constructor
Private mWAVFileName As String
Public ReadOnly Property WAVFileName() As String
Get
WAVFileName = mWAVFileName
End Get
End Property
'Constructor to open stream
Sub New(ByVal SoundFilePathName As String)
mWAVFileName = SoundFilePathName
mOpen = OpenWAVStream(mWAVFileName)
'******************* MAIN WORK HERE ******************
'Parse the WAV file and read the
If mOpen Then
'Read the Header Data in THIS ORDER
'Each Read results to the File Pointer Moving
mChunkID = ReadChunkID(mWAVStream)
mChunkSize = ReadChunkSize(mWAVStream)
mFormatID = ReadFormatID(mWAVStream)
mSubChunkID = ReadSubChunkID(mWAVStream)
mSubChunkSize = ReadSubChunkSize(mWAVStream)
mAudioFormat = ReadAudioFormat(mWAVStream)
mNumChannels = ReadNumChannels(mWAVStream)
mSampleRate = ReadSampleRate(mWAVStream)
mByteRate = ReadByteRate(mWAVStream)
mBlockAlign = ReadBlockAlign(mWAVStream)
mBitsPerSample = ReadBitsPerSample(mWAVStream)
mSubChunkIDTwo = ReadSubChunkIDTwo(mWAVStream)
mSubChunkSizeTwo = ReadSubChunkSizeTwo(mWAVStream)
mWaveSoundData = ReadWAVSampleData(mWAVStream)
mWAVStream.Close()
End If
End Sub
'Property to tell if stream is open or not
Private mOpen As Boolean
Public ReadOnly Property IsWAVFileOPen() As Boolean
Get
IsWAVFileOPen = mOpen
End Get
End Property
'Open an IO Binary Stream to Read the WavFile
Private mWAVStream As IO.BinaryReader
Private Function OpenWAVStream(ByVal SoundFilePathName As String) As Boolean
Dim WAVStreamReader As IO.StreamReader
WAVStreamReader = New IO.StreamReader(SoundFilePathName)
mWAVStream = New IO.BinaryReader(WAVStreamReader.BaseStream)
If mWAVStream Is Nothing Then
Return False
Else
Return True
End If
End Function
'Dipose the resource
Sub Dispose()
If Not mWAVStream Is Nothing Then
mWAVStream.Close()
mWAVStream = Nothing
mOpen = False
End If
GC.SuppressFinalize(Me)
End Sub
'Close the stream
Protected Overrides Sub Finalize()
Me.Dispose()
MyBase.Finalize()
End Sub
'Read the ChunkID and return a string
Private Function ReadChunkID(ByVal WAVIOstreamReader As IO.BinaryReader) As String
Dim DataBuffer() As Byte
Dim DataEncoder As System.Text.ASCIIEncoding
Dim TempString As Char()
DataEncoder = New System.Text.ASCIIEncoding
DataBuffer = WAVIOstreamReader.ReadBytes(4)
'Ensure we have data to spit out
If DataBuffer.Length <> 0 Then
TempString = DataEncoder.GetChars(DataBuffer, 0, 4)
Return TempString(0) & TempString(1) & TempString(2) & TempString(3)
Else
Return ""
End If
End Function
'Chunk size little endian bytes No. 5-13
Private mChunkSize As Long
Public ReadOnly Property ChunkSize() As Long
Get
ChunkSize = mChunkSize
End Get
End Property
'Read the ChunkID and return a string
Private Function ReadChunkSize(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(4)
ReadChunkSize = CLng(GetLittleEndianStringValue(DataBuffer))
End Function
'BigEndian bytes number 9 - 13
Private mFormatID As String
Public ReadOnly Property FormatID() As String
Get
FormatID = mFormatID
End Get
End Property
'Read the Format and return a string
Private Function ReadFormatID(ByVal WAVIOstreamReader As IO.BinaryReader) As String
Dim DataBuffer() As Byte
Dim DataEncoder As System.Text.ASCIIEncoding
Dim TempString As Char()
DataEncoder = New System.Text.ASCIIEncoding
DataBuffer = WAVIOstreamReader.ReadBytes(4)
'Ensure we have data to spit out
If DataBuffer.Length <> 0 Then
TempString = DataEncoder.GetChars(DataBuffer, 0, 4)
Return TempString(0) & TempString(1) & TempString(2) & TempString(3)
Else
Return ""
End If
End Function
'Little Endian bytes number 13 - 17
Private mSubChunkID As String
Public ReadOnly Property SubChunkID() As String
Get
SubChunkID = mSubChunkID
End Get
End Property
'Read the sub chunkID and return a string
Private Function ReadSubChunkID(ByVal WAVIOstreamReader As IO.BinaryReader) As String
Dim DataBuffer() As Byte
Dim DataEncoder As System.Text.ASCIIEncoding
Dim TempString As Char()
DataEncoder = New System.Text.ASCIIEncoding
DataBuffer = WAVIOstreamReader.ReadBytes(4)
'Ensure we have data to spit out
If DataBuffer.Length <> 0 Then
TempString = DataEncoder.GetChars(DataBuffer, 0, 4)
Return TempString(0) & TempString(1) & TempString(2) & TempString(3)
Else
Return ""
End If
End Function
'SubChunk size little endian bytes No. 17-21
Private mSubChunkSize As Long
Public ReadOnly Property SubChunkSize() As Long
Get
SubChunkSize = mSubChunkSize
End Get
End Property
'Read the SubChunkID and return a string
Private Function ReadSubChunkSize(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(4)
ReadSubChunkSize = CLng(GetLittleEndianStringValue(DataBuffer))
End Function
'Audio Format little endian bytes No. 20-22
Private mAudioFormat As Long
Public ReadOnly Property AudioFormat() As Long
Get
AudioFormat = mAudioFormat
End Get
End Property
'Read the SubChunkID and return a string
Private Function ReadAudioFormat(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(2)
ReadAudioFormat = CLng(GetLittleEndianStringValueDuplex(DataBuffer))
End Function
'Number of Channels little endian bytes No. 22-24
Private mNumChannels As Long
Public ReadOnly Property NumChannels() As Long
Get
NumChannels = mNumChannels
End Get
End Property
'Read the SubChunkID and return a string
Private Function ReadNumChannels(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(2)
ReadNumChannels = CLng(GetLittleEndianStringValueDuplex(DataBuffer))
End Function
'Sample Rate little endian bytes No. 24-28
Private mSampleRate As Long
Public ReadOnly Property SampleRate() As Long
Get
SampleRate = mSampleRate
End Get
End Property
Public ReadOnly Property Frequency() As Long
Get
Frequency = mSampleRate
End Get
End Property
'Get the number of samples
Public ReadOnly Property NumberOfSamples() As Long
Get
NumberOfSamples = SubChunkSizeTwo * 8 \ (NumChannels * BitsPerSample)
End Get
End Property
'Read the Sample Rate and return a string
Private Function ReadSampleRate(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(4)
ReadSampleRate = CLng(GetLittleEndianStringValue(DataBuffer))
End Function
'Byte Rate little endian bytes No. 28-32
Private mByteRate As Long
Public ReadOnly Property ByteRate() As Long
Get
ByteRate = mByteRate
End Get
End Property
'Get the play time in seconds
Public ReadOnly Property PlayTimeSeconds() As Single
Get
PlayTimeSeconds = CSng(SubChunkSizeTwo / ByteRate)
End Get
End Property
'Read the Byte Rate and return a string
Private Function ReadByteRate(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(4)
ReadByteRate = CLng(GetLittleEndianStringValue(DataBuffer))
End Function
'Block Align little endian bytes No. 32-34
Private mBlockAlign As Long
Public ReadOnly Property BlockAlign() As Long
Get
BlockAlign = mBlockAlign
End Get
End Property
'Read the Block Align and return a string
Private Function ReadBlockAlign(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(2)
ReadBlockAlign = CLng(GetLittleEndianStringValueDuplex(DataBuffer))
End Function
'Buits Per Sample little endian bytes No. 34-36
Private mBitsPerSample As Long
Public ReadOnly Property BitsPerSample() As Long
Get
BitsPerSample = mBitsPerSample
End Get
End Property
'Read the Bits Per Sample and return a string
Private Function ReadBitsPerSample(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(2)
ReadBitsPerSample = CLng(GetLittleEndianStringValueDuplex(DataBuffer))
End Function
'Buits Per Sample Big endian bytes No. 36-40
Private mSubChunkIDTwo As String
Public ReadOnly Property SubChunkIDTwo() As String
Get
SubChunkIDTwo = mSubChunkIDTwo
End Get
End Property
'Read the SubChunkTwoID Sample and return a string
Private Function ReadSubChunkIDTwo(ByVal WAVIOstreamReader As IO.BinaryReader) As String
Dim DataBuffer() As Byte
Dim DataEncoder As System.Text.ASCIIEncoding
Dim TempString As Char()
Dim Datastr As String
DataEncoder = New System.Text.ASCIIEncoding
DataBuffer = WAVIOstreamReader.ReadBytes(1)
'Ensure we have data to spit out
TempString = DataEncoder.GetChars(DataBuffer, 0, 1)
Datastr = TempString(0)
If Datastr <> "d" Then
'Read until you get data
DataBuffer = WAVIOstreamReader.ReadBytes(1)
TempString = DataEncoder.GetChars(DataBuffer, 0, 1)
Datastr = TempString(0)
While Datastr <> "d"
DataBuffer = WAVIOstreamReader.ReadBytes(1)
TempString = DataEncoder.GetChars(DataBuffer, 0, 1)
Datastr = TempString(0)
End While
DataBuffer = WAVIOstreamReader.ReadBytes(3)
TempString = DataEncoder.GetChars(DataBuffer, 0, 3)
Datastr = "d" & (TempString(0) & TempString(1) & TempString(2))
Else
DataBuffer = WAVIOstreamReader.ReadBytes(3)
TempString = DataEncoder.GetChars(DataBuffer, 0, 3)
Datastr = "d" & (TempString(0) & TempString(1) & TempString(2))
Return Datastr
End If
End Function
'Buits Per Sample little endian bytes No. 40-44
Private mSubChunkSizeTwo As Long
Public ReadOnly Property SubChunkSizeTwo() As Long
Get
SubChunkSizeTwo = mSubChunkSizeTwo
End Get
End Property
'Read the Bits Per Sample and return a string
Private Function ReadSubChunkSizeTwo(ByVal WAVIOstreamReader As IO.BinaryReader) As Long
Dim DataBuffer() As Byte
DataBuffer = WAVIOstreamReader.ReadBytes(4)
ReadSubChunkSizeTwo = CLng(GetLittleEndianStringValue(DataBuffer))
End Function
'Get the little endian value
Private Function GetLittleEndianStringValueDuplex(ByVal DataBuffer() As Byte) As String
Dim ValueString As String = "&h"
If DataBuffer.Length <> 0 Then
'In little endian
If Hex(DataBuffer(1)).Length = 1 Then
ValueString &= "0" & Hex(DataBuffer(1))
Else
ValueString &= Hex(DataBuffer(1))
End If
If Hex(DataBuffer(0)).Length = 1 Then
ValueString &= "0" & Hex(DataBuffer(0))
Else
ValueString &= Hex(DataBuffer(0))
End If
Else
ValueString = "0"
End If
GetLittleEndianStringValueDuplex = ValueString
End Function
'Get the small endian value
Private Function GetLittleEndianStringValue(ByVal DataBuffer() As Byte) As String
Dim ValueString As String = "&h"
If DataBuffer.Length <> 0 Then
'In little endian we reverse the aray data and pad the same where the
'length is 1
If Hex(DataBuffer(3)).Length = 1 Then
ValueString &= "0" & Hex(DataBuffer(3))
Else
ValueString &= Hex(DataBuffer(3))
End If
If Hex(DataBuffer(2)).Length = 1 Then
ValueString &= "0" & Hex(DataBuffer(2))
Else
ValueString &= Hex(DataBuffer(2))
End If
If Hex(DataBuffer(1)).Length = 1 Then
ValueString &= "0" & Hex(DataBuffer(1))
Else
ValueString &= Hex(DataBuffer(1))
End If
If Hex(DataBuffer(0)).Length = 1 Then
ValueString &= "0" & Hex(DataBuffer(0))
Else
ValueString &= Hex(DataBuffer(0))
End If
Else
ValueString = "0"
End If
GetLittleEndianStringValue = ValueString
End Function
'Buffers to hold Data
Private mWaveSoundData As Byte()
'Return the sound Data to display
ReadOnly Property WaveSoundData() As Byte()
Get
WaveSoundData = mWaveSoundData
End Get
End Property
'Read Data to Pans both left and right
Private Function ReadWAVSampleData(ByVal WAVIOstreamReader As IO.BinaryReader) As Byte()
Dim tempBuffer() As Byte
tempBuffer = WAVIOstreamReader.ReadBytes(CInt(mSubChunkSizeTwo))
Return tempBuffer
End Function
'returns the wave data as a byte array
Public Function GetSoundDataValue() As Int16()
Dim DataCount As Integer
Dim tempStream As IO.BinaryReader
tempStream = New IO.BinaryReader(New IO.MemoryStream(mWaveSoundData))
tempStream.BaseStream.Position = 0
'Create a data array to hold the data read from the stream
'Read chunks of int16 from the stream (already aligned!)
Dim tempData(CInt(tempStream.BaseStream.Length / 2)) As Int16
While DataCount <= tempData.Length - 2
tempData(DataCount) = tempStream.ReadInt16()
DataCount += 1
End While
tempStream.Close()
tempStream = Nothing
Return tempData
End Function
End Class