[RESOLVED] Creating a wav file for use as an Infrared carrier
Hello,
I am using the following code, which creates a wav file, for use as audio signal generation, to modulate an Infrared LED connected across the left and right channels of the headphone jack.
I am able to create a maximum output frequency of 20 kHz because of the general limitations of head-phone ports. I need to modulate the Infrared LED at circa 38 kHz, so I have read about the technique of creating a stereo wav file where, for instance, the left channel is the inverse of the right channel, so with the LED connected across the channels, the LED effectively flashes at double the input frequency.
My problem is, I cannot see how I can amend the code to be able to invert one channel. This code uses one byte-array for the data, but if you select stereo in the property set-up then the left and right channels are identical - I think I need to add another byte-array which I can build up as the inverse.
Any help much appreciated. The form code and the class is shown, code originally comes from a person called Paul Ishak on this website (half way down the thread):-
https://social.msdn.microsoft.com/Fo...orum=vbgeneral
The form code creates a square wave at a fixed frequency for testing.
Class code:-
Code:
Option Strict On
Imports System.Text
Public Class Wave
'By Paul Ishak
'WAVE PCM soundfile format
'The Canonical WAVE file format
'As Described Here: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
Public FileHeader As Header
Public FileFormatSubChunk As FormatSubChunk
Public FileDataSubChunk As DataSubChunk
Const _Byte As Integer = 1
Const _word As Integer = 2
Const _dword As Integer = 4
Const _qword As Integer = 8
Public Structure WaveFileOptions
Public SampleRate As WavSampleRate
Public AudioFormat As Format
Public BitsPerSample As BitsPerSample
Public NumberOfChannels As NumberOfChannels
Public FormatSize As FormatSize
Public NumberOfSamples As UInt32
Public Data As Byte()
End Structure
' DATATYPE OFFSET Endian Description
Structure Header
Public Property ChunkID As Byte() ' Dword 0 Big Contains the letters "RIFF" in ASCII form(0x52494646 big-endian form).
Public Property ChunkSize As UInt32 ' Dword 4 Little 36 + SubChunk2Size, or more precisely: 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
Public Property Format As Byte() ' Dword 8 Big Contains the letters "WAVE" in ASCII form (0x57415645 big-endian form).
End Structure
Structure FormatSubChunk
Public Property Subchunk1ID As Byte() ' Dword 12 Big Contains the letters "fmt "(0x666d7420 big-endian form).
Public Property Subchunk1Size As UInt32 ' Dword 16 little 16 for PCM. This is the size of the rest of the Subchunk which follows this number.
Public Property AudioFormat As UInt16 ' Word 20 little PCM = 1 (i.e. Linear quantization)Values other than 1 indicate some form of compression.
Public Property NumChannels As UInt16 ' Word 22 little Mono = 1, Stereo = 2, etc.
Public Property SampleRate As UInt32 ' Dword 24 little 8000, 44100, etc.
Public Property ByteRate As UInt32 ' Dword 28 little == SampleRate * NumChannels * BitsPerSample/8
Public Property BlockAlign As UInt16 ' Word 32 little == NumChannels * BitsPerSample/8
Public Property BitsPerSample As UInt16 ' Word 34 little 8 bits = 8, 16 bits = 16, etc.
End Structure
Structure DataSubChunk
Public Property Subchunk2ID As Byte() ' Dword 36 Big Contains the letters "data"(0x64617461 big-endian form).
Public Property Subchunk2Size As UInt32 ' Dword 40 little == NumSamples * NumChannels * BitsPerSample/8 This is the number of bytes in the data.
Public Property Data As Byte() ' VariableLength 44 little The actual sound data.
End Structure
Public Sub OpenFile(ByVal FileName As String)
Try
If CBool(Not InStr(LCase(FileName), ".wav")) Then Throw New Exception("Invalid File Extension Specified!")
If Not My.Computer.FileSystem.FileExists(FileName) Then Throw New Exception("File Does Not Exist!")
Dim FileBytes() As Byte = My.Computer.FileSystem.ReadAllBytes(FileName)
'Get Header
Me.FileHeader.ChunkID = GetDataFromByteArray(FileBytes, 0, 0, _dword)
Me.FileHeader.ChunkSize = CUInt(BitConverter.ToInt32(GetDataFromByteArray(FileBytes, 0, 4, _dword), 0))
Me.FileHeader.Format = GetDataFromByteArray(FileBytes, 0, 8, _dword)
'Get FormatSubChunk
Me.FileFormatSubChunk.Subchunk1ID = GetDataFromByteArray(FileBytes, 0, 12, _dword)
Me.FileFormatSubChunk.Subchunk1Size = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 16, _dword), 0)
Me.FileFormatSubChunk.AudioFormat = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 20, _word), 0)
Me.FileFormatSubChunk.NumChannels = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 22, _word), 0)
Me.FileFormatSubChunk.SampleRate = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 24, _dword), 0)
Me.FileFormatSubChunk.ByteRate = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 28, _dword), 0)
Me.FileFormatSubChunk.BlockAlign = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 32, _word), 0)
Me.FileFormatSubChunk.BitsPerSample = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 34, _word), 0)
'Get DataSubChunck
Me.FileDataSubChunk.Subchunk2ID = GetDataFromByteArray(FileBytes, 0, 36, _dword)
Me.FileDataSubChunk.Subchunk2Size = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 40, _dword), 0)
Me.FileDataSubChunk.Data = GetDataFromByteArray(FileBytes, 0, 44, Me.FileDataSubChunk.Subchunk2Size)
Catch
Throw New Exception("File Is Invalid or corrupt!")
End Try
End Sub
Public Sub SetDirectBytes(ByVal FileBytes() As Byte)
Try
'Get Header
Me.FileHeader.ChunkID = GetDataFromByteArray(FileBytes, 0, 0, _dword)
Me.FileHeader.ChunkSize = CUInt(BitConverter.ToInt32(GetDataFromByteArray(FileBytes, 0, 4, _dword), 0))
Me.FileHeader.Format = GetDataFromByteArray(FileBytes, 0, 8, _dword)
'Get FormatSubChunk
Me.FileFormatSubChunk.Subchunk1ID = GetDataFromByteArray(FileBytes, 0, 12, _dword)
Me.FileFormatSubChunk.Subchunk1Size = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 16, _dword), 0)
Me.FileFormatSubChunk.AudioFormat = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 20, _word), 0)
Me.FileFormatSubChunk.NumChannels = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 22, _word), 0)
Me.FileFormatSubChunk.SampleRate = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 24, _dword), 0)
Me.FileFormatSubChunk.ByteRate = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 28, _dword), 0)
Me.FileFormatSubChunk.BlockAlign = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 32, _word), 0)
Me.FileFormatSubChunk.BitsPerSample = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 34, _word), 0)
'Get DataSubChunck
Me.FileDataSubChunk.Subchunk2ID = GetDataFromByteArray(FileBytes, 0, 36, _dword)
Me.FileDataSubChunk.Subchunk2Size = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 40, _dword), 0)
Me.FileDataSubChunk.Data = GetDataFromByteArray(FileBytes, 0, 44, Me.FileDataSubChunk.Subchunk2Size)
Catch ex As Exception
' Throw New Exception("File Is Invalid or corrupt!")
MsgBox(ex.StackTrace)
End Try
End Sub
Public Function GetBytes() As Byte()
Dim Results As Byte() = Nothing
Results = CombineArrays(FileHeader.ChunkID, BitConverter.GetBytes(FileHeader.ChunkSize))
Results = CombineArrays(Results, FileHeader.Format)
Results = CombineArrays(Results, FileFormatSubChunk.Subchunk1ID)
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.Subchunk1Size))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.AudioFormat))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.NumChannels))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.SampleRate))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.ByteRate))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.BlockAlign))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.BitsPerSample))
Results = CombineArrays(Results, FileDataSubChunk.Subchunk2ID)
Results = CombineArrays(Results, BitConverter.GetBytes(FileDataSubChunk.Subchunk2Size))
Results = CombineArrays(Results, FileDataSubChunk.Data)
Return Results
End Function
Function CombineArrays(ByVal Array1() As Byte, ByVal Array2() As Byte) As Byte()
Dim AllResults(Array1.Length + Array2.Length - 1) As Byte
Array1.CopyTo(AllResults, 0)
Array2.CopyTo(AllResults, Array1.Length)
Return AllResults
End Function
Public Sub SaveFile(ByVal FileName As String)
Dim FileBytes As Byte() = Me.GetBytes()
My.Computer.FileSystem.WriteAllBytes(FileName, FileBytes, False)
End Sub
Private Function GetDataFromByteArray(ByVal ByteArray As Byte(), ByVal BlockOffset As Long, ByVal RangeStartOffset As Long, ByVal DataLength As Long) As Byte()
On Error Resume Next
Dim AnswerL As New List(Of Byte)
Dim CurrentOffset As Long
For I = 0 To UBound(ByteArray)
CurrentOffset = BlockOffset + I
If CurrentOffset >= RangeStartOffset Then
If CurrentOffset <= RangeStartOffset + DataLength Then
AnswerL.Add(ByteArray(I))
End If
End If
Next
Return AnswerL.ToArray
End Function
Sub New(ByVal Options As WaveFileOptions)
FileHeader.ChunkID = Encoding.ASCII.GetBytes("RIFF")
FileFormatSubChunk.Subchunk1Size = Options.FormatSize
FileFormatSubChunk.NumChannels = Options.NumberOfChannels
FileFormatSubChunk.BitsPerSample = Options.BitsPerSample
FileDataSubChunk.Subchunk2Size = CUInt(Options.NumberOfSamples * Options.NumberOfChannels * Options.BitsPerSample / 8)
FileHeader.ChunkSize = CUInt(4 + (8 + FileFormatSubChunk.Subchunk1Size) + (8 + FileDataSubChunk.Subchunk2Size))
FileHeader.Format = Encoding.ASCII.GetBytes("WAVE")
FileFormatSubChunk.Subchunk1ID = Encoding.ASCII.GetBytes("fmt ")
FileFormatSubChunk.AudioFormat = Options.AudioFormat
FileFormatSubChunk.SampleRate = Options.SampleRate
FileFormatSubChunk.ByteRate = CUInt(Options.SampleRate * Options.NumberOfChannels * Options.BitsPerSample / 8)
FileFormatSubChunk.BlockAlign = CUShort(Options.NumberOfChannels * Options.BitsPerSample / 8)
FileDataSubChunk.Subchunk2ID = Encoding.ASCII.GetBytes("data")
FileDataSubChunk.Data = Options.Data
End Sub
Public Enum WavSampleRate As UInt32
hz8000 = 8000
hz11025 = 11025
hz16000 = 16000
hz22050 = 22050
hz32000 = 32000
hz44100 = 44100
hz48000 = 48000
hz96000 = 96000
hz192000 = 192000
End Enum
Public Enum Format As UInt16
Standard = 1
End Enum
Public Enum BitsPerSample As UInt16
bps_8 = 8
bps_16 = 16
bps_32 = 32
bps_64 = 64
bps_128 = 128
bps_256 = 256
End Enum
Public Enum NumberOfChannels As UInt16
Mono = 1
Stereo = 2
End Enum
Public Enum FormatSize As UInt32
PCM = 16
End Enum
End Class
Main form code:-
Code:
Option Strict On
Imports System.Text
Public Class Form1
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
Dim WaveFileOptions As New Wave.WaveFileOptions
With WaveFileOptions
.AudioFormat = Wave.Format.Standard
.FormatSize = Wave.FormatSize.PCM
.BitsPerSample = Wave.BitsPerSample.bps_8
.NumberOfChannels = Wave.NumberOfChannels.Stereo
.SampleRate = Wave.WavSampleRate.hz44100
.NumberOfSamples = 4096
End With
Dim DataUpperBound As Integer = CInt(((WaveFileOptions.NumberOfSamples * WaveFileOptions.NumberOfChannels * WaveFileOptions.BitsPerSample) / 8) - 1)
Dim Data(0 To DataUpperBound) As Byte
'
' 255 = +100%
' 128 = 0%
' 0 = -100%
'
Dim q As Integer = 0
For pulse As Integer = 0 To 2047
For i As Integer = 0 To 1 ' 2 pulses ON
Data(q) = CByte(255)
q += 1
Next
For i As Integer = 0 To 1 ' 2 pulses OFF
Data(q) = CByte(128)
q += 1
Next
Next
'
WaveFileOptions.Data = Data
Dim WaveFile As New Wave(WaveFileOptions)
WaveFile.SaveFile(My.Computer.FileSystem.SpecialDirectories.Desktop & "\whitenoise.wav")
Process.Start(My.Computer.FileSystem.SpecialDirectories.Desktop & "\whitenoise.wav")
End Sub
End Class
Re: Creating a wav file for use as an Infrared carrier
I don't see how inverting a channel will double the frequency. I would think all it would do is double the voltage (the delta between the two wave magnitudes).
Re: Creating a wav file for use as an Infrared carrier
So, the way I understand it, if the LED is just connected across Left and Ground with a Mono signal, then the LED will only flash on the positive cycle, when the negative cycle occurs, the LED just sits there doing nothing.
Whereas, if the LED is connected across Left and Right (not ground) with a Stereo signal (one channel in opposite phase to the other) then when the Left channel is positive the LED will come on and when the Right channel is positive the LED will come on again, occurring twice in the same time period.
Re: Creating a wav file for use as an Infrared carrier
Ok, I guess there must be more components involved here than just the LED. Perhaps you have a transistor to amplify the signal to the level needed to trigger the LED and a resister to limit the current. The D in LED stands for Diode and a Diode will primarily pass current in one direction so as you say it would light when the voltage was positive (the current moving in one direction) and not light when the voltage was negative (the current trying to move in the other direction but blocked by the diode).
If you connected one side of the LED to ground, that gives you a fixed reference on that pin, and when the other pin goes higher than ground you have the positive voltage and the diode passes the current lighting the LED and when the other pin goes less than ground you have a negative voltage (in reference to the ground) so the diode blocks the current and the LED is unlit.
If you connected a signal to one pin and an inverted version of that signal to the other pin the relative voltage potential between the pins would increase as the signals moved away from each other so at the peak of the signal the voltage potential between the two pins would be twice the value of the signal.
Let's assume a one volt signal where the reference is ground and the wave (i.e. the voltage) goes to a peak of 1v above ground and 1v below ground in its cycle. If this signal is connected to one pin of the LED and the other pin of the LED is connected to ground (0), then the potential at the positive peak (1 - 0) is 1 and the potential at the negative peak (-1 - 0) is -1.
If you connect a negative version of the signal to the one pin in place of the ground, then the potential at the positive peak is (1 - -1) = 2 and the potential at the negative peak is (-1 - 1) = -2.
The result is you've double the voltage potential between the two pins compared to the original signal (original cycled between 1 and -1, the second cycles between 2 and -2).
For what you propose there must be (I would think) two diodes inline (one on each signal input) with the "outputs" connected to the "input" of the LED so that when the signal is positive current is passing through that diode to the LED and the other signal is block by its diode because its signal is negative. Then when the signal is negative the diode on that input is blocking current while the inverted signal's (now positive) current is passed driving the LED.
Of course, it seems to me like you wouldn't need a stereo input, i.e. two signals to accomplish this as the one wave could use a rectifier circuit of diodes to change the negative swing of the signal into a relative positive swing giving you two pulses per cycle from the one signal, but perhaps because you are modulating the signal to communicate data, flipping the signal with a rectifier would mess up or complicate the modulation mechanism.
I guess I only "know enough to be dangerous", not enough to be competent or sure, but since the LED by design should conduct current when the voltage potential of the pins is in one condition, connecting an inverted signal to the other pin doesn't seem like the correct terminology for what you need to do.
Re: Creating a wav file for use as an Infrared carrier
I've been doing some testing following your posts and you're absolutely right :)
You know when you run something through your brain and you come up with 2 answers and 1 is the wish-list answer!
I'd still like to be able to do this (inverting the one channel), as like you say, I'd at least get double the volts. which will help with range etc.
What I'm doing now is creating a positive DC pulse twice in the time period for 19kHz (effectively 38kHz), but it seems to be cutting out, perhaps the sound card doesn't like it - I can't get data streams longer than 60ms?
Re: Creating a wav file for use as an Infrared carrier
Update:-
So, I now have a working solution for my infrared transmitter. The following code creates a .wav file based on 1s and 0s which represent arbitrary values, in my case, approximately 560us long pulse for a logic 1, and a 560us long space for a logic 0.
The modulation is 19kHz AC, so when two infrared LEDs are connected back-to-back, the effective frequency in terms of the infrared modulation is double that.
Interestingly, through testing I have found that most infrared receivers will work on half the nominal 38kHz frequency, using only one infrared LED.
The code creates the .wav file, and then plays it.
Here is the test code if anybody is interested:-
Code:
Option Strict On
Imports System.Text
Public Class Form1
Dim q As Integer = 0
Dim Data As Byte() = New Byte(12500000) {}
Dim pulse_mark As Integer = 3 ' Maximum current flow per cycle = 3
Dim pulse_space As Integer = 0 ' Maximum current flow per cycle = 0
'
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
'
' Code to create a small .wav file with data = 10101
' Based on 19kHz modulating 2 LED connecteds across Left channel and ground
' which flashes effectively at 38kHz. But it also works with 1 LED.
'
' .wav values:-
' 255 = +100%
' 128 = 0%
' 0 = -100%
'
' An ideal 38kHz with a 50% duty cycle is:-
' 1/38000 = 26.3us/2 = 13.15us ON and 13.15us OFF
'
' 1/192000*10 = 0.00005208 = 1/0.00005208 * 2 LEDs = 38400
'
q = 0
Dim WaveFileOptions As New Wave.WaveFileOptions
With WaveFileOptions
.AudioFormat = Wave.Format.Standard
.FormatSize = Wave.FormatSize.PCM
.BitsPerSample = Wave.BitsPerSample.bps_8
.NumberOfChannels = Wave.NumberOfChannels.Mono
.SampleRate = Wave.WavSampleRate.hz192000
.NumberOfSamples = 13260 ' adjust as necessary to fit the data in
End With
'
add_One_19kHz()
add_Zero_19kHz()
add_One_19kHz()
add_Zero_19kHz()
add_One_19kHz()
'
WaveFileOptions.Data = Data
Dim WaveFile As New Wave(WaveFileOptions)
WaveFile.SaveFile(My.Computer.FileSystem.SpecialDirectories.Desktop & "\Remote.wav")
My.Computer.Audio.Play(My.Computer.FileSystem.SpecialDirectories.Desktop & "\Remote.wav")
End Sub
'
Private Sub add_One_19kHz()
' Create an AC pulse which has a length of 580 us
For pulse As Integer = 0 To 10
' the following is 10 pulses long
For i As Integer = 0 To pulse_mark
Data(q) = CByte(255)
q += 1
Next
For i As Integer = 0 To pulse_space
Data(q) = CByte(128)
q += 1
Next
For i As Integer = 0 To pulse_mark
Data(q) = CByte(0)
q += 1
Next
For i As Integer = 0 To pulse_space
Data(q) = CByte(128)
q += 1
Next
Next
End Sub
'
Private Sub add_Zero_19kHz()
' Create an AC pulse which has a length of 580 us
For pulse As Integer = 0 To 10
' the following is 10 pulses long
For i As Integer = 0 To pulse_mark
Data(q) = CByte(255)
q += 1
Next
For i As Integer = 0 To pulse_space
Data(q) = CByte(128)
q += 1
Next
For i As Integer = 0 To pulse_mark
Data(q) = CByte(0)
q += 1
Next
For i As Integer = 0 To pulse_space
Data(q) = CByte(128)
q += 1
Next
Next
End Sub
'
End Class
wave class code again:-
Option Strict On
Imports System.Text
Public Class Wave
'By Paul Ishak
'WAVE PCM soundfile format
'The Canonical WAVE file format
'As Described Here: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
Public FileHeader As Header
Public FileFormatSubChunk As FormatSubChunk
Public FileDataSubChunk As DataSubChunk
Const _Byte As Integer = 1
Const _word As Integer = 2
Const _dword As Integer = 4
Const _qword As Integer = 8
Public Structure WaveFileOptions
Public SampleRate As WavSampleRate
Public AudioFormat As Format
Public BitsPerSample As BitsPerSample
Public NumberOfChannels As NumberOfChannels
Public FormatSize As FormatSize
Public NumberOfSamples As UInt32
Public Data As Byte()
End Structure
' DATATYPE OFFSET Endian Description
Structure Header
Public Property ChunkID As Byte() ' Dword 0 Big Contains the letters "RIFF" in ASCII form(0x52494646 big-endian form).
Public Property ChunkSize As UInt32 ' Dword 4 Little 36 + SubChunk2Size, or more precisely: 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
Public Property Format As Byte() ' Dword 8 Big Contains the letters "WAVE" in ASCII form (0x57415645 big-endian form).
End Structure
Structure FormatSubChunk
Public Property Subchunk1ID As Byte() ' Dword 12 Big Contains the letters "fmt "(0x666d7420 big-endian form).
Public Property Subchunk1Size As UInt32 ' Dword 16 little 16 for PCM. This is the size of the rest of the Subchunk which follows this number.
Public Property AudioFormat As UInt16 ' Word 20 little PCM = 1 (i.e. Linear quantization)Values other than 1 indicate some form of compression.
Public Property NumChannels As UInt16 ' Word 22 little Mono = 1, Stereo = 2, etc.
Public Property SampleRate As UInt32 ' Dword 24 little 8000, 44100, etc.
Public Property ByteRate As UInt32 ' Dword 28 little == SampleRate * NumChannels * BitsPerSample/8
Public Property BlockAlign As UInt16 ' Word 32 little == NumChannels * BitsPerSample/8
Public Property BitsPerSample As UInt16 ' Word 34 little 8 bits = 8, 16 bits = 16, etc.
End Structure
Structure DataSubChunk
Public Property Subchunk2ID As Byte() ' Dword 36 Big Contains the letters "data"(0x64617461 big-endian form).
Public Property Subchunk2Size As UInt32 ' Dword 40 little == NumSamples * NumChannels * BitsPerSample/8 This is the number of bytes in the data.
Public Property Data As Byte() ' VariableLength 44 little The actual sound data.
End Structure
Public Sub OpenFile(ByVal FileName As String)
Try
If CBool(Not InStr(LCase(FileName), ".wav")) Then Throw New Exception("Invalid File Extension Specified!")
If Not My.Computer.FileSystem.FileExists(FileName) Then Throw New Exception("File Does Not Exist!")
Dim FileBytes() As Byte = My.Computer.FileSystem.ReadAllBytes(FileName)
'Get Header
Me.FileHeader.ChunkID = GetDataFromByteArray(FileBytes, 0, 0, _dword)
Me.FileHeader.ChunkSize = CUInt(BitConverter.ToInt32(GetDataFromByteArray(FileBytes, 0, 4, _dword), 0))
Me.FileHeader.Format = GetDataFromByteArray(FileBytes, 0, 8, _dword)
'Get FormatSubChunk
Me.FileFormatSubChunk.Subchunk1ID = GetDataFromByteArray(FileBytes, 0, 12, _dword)
Me.FileFormatSubChunk.Subchunk1Size = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 16, _dword), 0)
Me.FileFormatSubChunk.AudioFormat = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 20, _word), 0)
Me.FileFormatSubChunk.NumChannels = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 22, _word), 0)
Me.FileFormatSubChunk.SampleRate = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 24, _dword), 0)
Me.FileFormatSubChunk.ByteRate = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 28, _dword), 0)
Me.FileFormatSubChunk.BlockAlign = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 32, _word), 0)
Me.FileFormatSubChunk.BitsPerSample = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 34, _word), 0)
'Get DataSubChunck
Me.FileDataSubChunk.Subchunk2ID = GetDataFromByteArray(FileBytes, 0, 36, _dword)
Me.FileDataSubChunk.Subchunk2Size = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 40, _dword), 0)
Me.FileDataSubChunk.Data = GetDataFromByteArray(FileBytes, 0, 44, Me.FileDataSubChunk.Subchunk2Size)
Catch
Throw New Exception("File Is Invalid or corrupt!")
End Try
End Sub
Public Sub SetDirectBytes(ByVal FileBytes() As Byte)
Try
'Get Header
Me.FileHeader.ChunkID = GetDataFromByteArray(FileBytes, 0, 0, _dword)
Me.FileHeader.ChunkSize = CUInt(BitConverter.ToInt32(GetDataFromByteArray(FileBytes, 0, 4, _dword), 0))
Me.FileHeader.Format = GetDataFromByteArray(FileBytes, 0, 8, _dword)
'Get FormatSubChunk
Me.FileFormatSubChunk.Subchunk1ID = GetDataFromByteArray(FileBytes, 0, 12, _dword)
Me.FileFormatSubChunk.Subchunk1Size = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 16, _dword), 0)
Me.FileFormatSubChunk.AudioFormat = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 20, _word), 0)
Me.FileFormatSubChunk.NumChannels = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 22, _word), 0)
Me.FileFormatSubChunk.SampleRate = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 24, _dword), 0)
Me.FileFormatSubChunk.ByteRate = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 28, _dword), 0)
Me.FileFormatSubChunk.BlockAlign = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 32, _word), 0)
Me.FileFormatSubChunk.BitsPerSample = BitConverter.ToUInt16(GetDataFromByteArray(FileBytes, 0, 34, _word), 0)
'Get DataSubChunck
Me.FileDataSubChunk.Subchunk2ID = GetDataFromByteArray(FileBytes, 0, 36, _dword)
Me.FileDataSubChunk.Subchunk2Size = BitConverter.ToUInt32(GetDataFromByteArray(FileBytes, 0, 40, _dword), 0)
Me.FileDataSubChunk.Data = GetDataFromByteArray(FileBytes, 0, 44, Me.FileDataSubChunk.Subchunk2Size)
Catch ex As Exception
' Throw New Exception("File Is Invalid or corrupt!")
MsgBox(ex.StackTrace)
End Try
End Sub
Public Function GetBytes() As Byte()
Dim Results As Byte() = Nothing
Results = CombineArrays(FileHeader.ChunkID, BitConverter.GetBytes(FileHeader.ChunkSize))
Results = CombineArrays(Results, FileHeader.Format)
Results = CombineArrays(Results, FileFormatSubChunk.Subchunk1ID)
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.Subchunk1Size))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.AudioFormat))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.NumChannels))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.SampleRate))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.ByteRate))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.BlockAlign))
Results = CombineArrays(Results, BitConverter.GetBytes(FileFormatSubChunk.BitsPerSample))
Results = CombineArrays(Results, FileDataSubChunk.Subchunk2ID)
Results = CombineArrays(Results, BitConverter.GetBytes(FileDataSubChunk.Subchunk2Size))
Results = CombineArrays(Results, FileDataSubChunk.Data)
Return Results
End Function
Function CombineArrays(ByVal Array1() As Byte, ByVal Array2() As Byte) As Byte()
Dim AllResults(Array1.Length + Array2.Length - 1) As Byte
Array1.CopyTo(AllResults, 0)
Array2.CopyTo(AllResults, Array1.Length)
Return AllResults
End Function
Public Sub SaveFile(ByVal FileName As String)
Dim FileBytes As Byte() = Me.GetBytes()
My.Computer.FileSystem.WriteAllBytes(FileName, FileBytes, False)
End Sub
Private Function GetDataFromByteArray(ByVal ByteArray As Byte(), ByVal BlockOffset As Long, ByVal RangeStartOffset As Long, ByVal DataLength As Long) As Byte()
On Error Resume Next
Dim AnswerL As New List(Of Byte)
Dim CurrentOffset As Long
For I = 0 To UBound(ByteArray)
CurrentOffset = BlockOffset + I
If CurrentOffset >= RangeStartOffset Then
If CurrentOffset <= RangeStartOffset + DataLength Then
AnswerL.Add(ByteArray(I))
End If
End If
Next
Return AnswerL.ToArray
End Function
Sub New(ByVal Options As WaveFileOptions)
FileHeader.ChunkID = Encoding.ASCII.GetBytes("RIFF")
FileFormatSubChunk.Subchunk1Size = Options.FormatSize
FileFormatSubChunk.NumChannels = Options.NumberOfChannels
FileFormatSubChunk.BitsPerSample = Options.BitsPerSample
FileDataSubChunk.Subchunk2Size = CUInt(Options.NumberOfSamples * Options.NumberOfChannels * Options.BitsPerSample / 8)
FileHeader.ChunkSize = CUInt(4 + (8 + FileFormatSubChunk.Subchunk1Size) + (8 + FileDataSubChunk.Subchunk2Size))
FileHeader.Format = Encoding.ASCII.GetBytes("WAVE")
FileFormatSubChunk.Subchunk1ID = Encoding.ASCII.GetBytes("fmt ")
FileFormatSubChunk.AudioFormat = Options.AudioFormat
FileFormatSubChunk.SampleRate = Options.SampleRate
FileFormatSubChunk.ByteRate = CUInt(Options.SampleRate * Options.NumberOfChannels * Options.BitsPerSample / 8)
FileFormatSubChunk.BlockAlign = CUShort(Options.NumberOfChannels * Options.BitsPerSample / 8)
FileDataSubChunk.Subchunk2ID = Encoding.ASCII.GetBytes("data")
FileDataSubChunk.Data = Options.Data
End Sub
Public Enum WavSampleRate As UInt32
hz8000 = 8000
hz11025 = 11025
hz16000 = 16000
hz22050 = 22050
hz32000 = 32000
hz44100 = 44100
hz48000 = 48000
hz96000 = 96000
hz192000 = 192000
End Enum
Public Enum Format As UInt16
Standard = 1
End Enum
Public Enum BitsPerSample As UInt16
bps_8 = 8
bps_16 = 16
bps_32 = 32
bps_64 = 64
bps_128 = 128
bps_256 = 256
End Enum
Public Enum NumberOfChannels As UInt16
Mono = 1
Stereo = 2
End Enum
Public Enum FormatSize As UInt32
PCM = 16
End Enum
End Class