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