none
Real Time Brass Synthesis? RRS feed

  • Question

  • Hello! I've been working on a project for the past 3 months. I want to make a mini electrical trombone, that uses a breath pressure sensor for the modulation/oscillation+volume, and an optical encoder for the slide. I will be using either a raspberry Pi 3B or an Intel Atom board for the audio processing.

    So far, I am stuck on creating a decent real-time trombone/brass synthesizer that doesn't take boat loads of CPU. In my last attempt, I tried re-sampling some of my own trombone playing and looping it with a library called NAudio, and doing pitch adjustment when the slide is moved. It sounds decent, but the more i shift the pitch, the more robotic it sounds. Even if I fixed the robotic sounds, it requires massive amounts of CPU. The portable boards I can use are just barely able to hand it.

    If anyone can give me tips, or even point me in the right direction, that would really help me.
    Sunday, November 19, 2017 10:16 AM

All replies

  • Hi lucasheer,

    Can you tell me your application is vb.net or other? If it is vb.net project, How is your project progressing? Can you share the code of your current project?

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, November 21, 2017 6:43 AM
    Moderator
  • Ofcourse. My project is VB.Net based, but I can work in C#, not a problem. I've been working on this project for several months, and I just cannot get the code efficient enough, and also sounding good. I want to put it on a small low powered PC hopefully.

    Currently, I am using NAudio to manipulate and change the pitch of a small recorded sample of me playing trombone. This sample is 1.8 seconds long, and im just looping it and changing the pitch.

    It might also be worth mentioning that I get better CPU and response time with the shorter sample, but it sounds more bland with less modulation and filtering : It it about a 1/120 of the 1.8 second sample, at 0.015 seconds.

    If you are familiar with NAudio, its a really great audio manipulation library. It does have some synthesizing features, but it uses the basic MIDI functions of windows. I cant use the windows synth because it wants specific notes. I need to be able play specific notes, and hundreds of notes between those notes. That's how a trombone works. 

    That being said, I made a resampler that changes pitch with a trackbar, and here is the main form code:

    Imports NAudio
    Imports NAudio.Midi
    Imports NAudio.Wave
    Imports NAudio.Wave.SampleProviders
    
    Public Class Form1
    
        Dim smb As SmbPitchShiftingSampleProvider
        Dim wo As New WaveOutEvent() With {
            .DesiredLatency = 100,
            .NumberOfBuffers = 8}
    
        Private Sub TrackBar1_Scroll(sender As Object, e As EventArgs) Handles TrackBar1.Scroll
            smb.PitchFactor = TrackBar1.Value * 0.01F
            Me.Text = TrackBar1.Value
        End Sub
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            smb = New SmbPitchShiftingSampleProvider(New LoopStream(New AudioFileReader("tromboneSample.wav")).ToSampleProvider, 8192, 4L, 1.0F)
            wo.Init(New SampleToWaveProvider16(smb))
            wo.Play()
            smb.PitchFactor = TrackBar1.Value * 0.001F + 1.0F
            PlayUp()
            smb.PitchFactor = TrackBar1.Value * 0.01F
            Me.Text = TrackBar1.Value '100 * 0.01F is 1, which causes no pitch changes. It sounds normal
        End Sub
    
        Dim noteArr As String() = New String() {15, 139, 279, 355, 521, 707, 917, 1030}
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            For I As Integer = 0 To noteArr.Length - 1
                If Not (I = noteArr.Length - 1) Then
                    If (I = 0) Then
                        smb.PitchFactor = noteArr(I) * 0.001F + 1.0F
                        Threading.Thread.Sleep(1000)
                    Else
                        smb.PitchFactor = noteArr(I) * 0.001F + 1.0F
                        Threading.Thread.Sleep(300)
                    End If
    
                    For B As Integer = noteArr(I) To noteArr(I + 1)
                        smb.PitchFactor = B * 0.001F + 1.0F
                        Threading.Thread.Sleep(1)
                    Next
                Else
                    smb.PitchFactor = noteArr(I) * 0.001F + 1.0F
                    Threading.Thread.Sleep(1000)
                End If
            Next
    
            For I As Integer = noteArr.Length - 2 To 0 Step -1
                If Not (I = 0) Then
                    smb.PitchFactor = noteArr(I) * 0.001F + 1.0F
                    Threading.Thread.Sleep(300)
    
                    For B As Integer = noteArr(I) To noteArr(I - 1) Step -1
                        smb.PitchFactor = B * 0.001F + 1.0F
                        Threading.Thread.Sleep(1)
                    Next
                Else
                    smb.PitchFactor = noteArr(I) * 0.001F + 1.0F
                    Threading.Thread.Sleep(1000)
                End If
            Next
        End Sub
    
        Private curVolume As Int32 = 100
    
        Private Sub PlayUp()
            wo.Play()
            For I As Integer = curVolume To 100 Step 1
                curVolume = I
                wo.Volume = I * 0.01F
                Threading.Thread.Sleep(1)
            Next
        End Sub
    
        Private Sub PlayDown()
            For I As Integer = curVolume To 0 Step -1
                curVolume = I
                wo.Volume = I * 0.01F
                Threading.Thread.Sleep(1)
            Next
            wo.Pause()
            sendPause = False
        End Sub
    
        Dim sendPause As Boolean = False
        Dim t As Threading.Thread = Nothing
    End Class

    Here is the pitch shifting class I am using:

    Imports NAudio.Dsp
    Imports NAudio.Wave
    Public Class SmbPitchShiftingSampleProvider
        Implements ISampleProvider
        'Shifter objects
        Private ReadOnly sourceStream As ISampleProvider
        Private ReadOnly waveFormat As WaveFormat
        Private pitch As Single = 1.0F
        Private ReadOnly fftSize As Integer
        Private ReadOnly osamp As Long
        Private ReadOnly shifterLeft As New SmbPitchShifter()
        Private ReadOnly shifterRight As New SmbPitchShifter()
    
        'Limiter constants
        Const LIM_THRESH As Single = 0.95F
        Const LIM_RANGE As Single = (1.0F - LIM_THRESH)
        Const M_PI_2 As Single = CSng(Math.PI / 2)
    
    
        Public FPSCounter As Int32 = 0
        Public FPS As Int32 = 0
        Private SW As New Stopwatch
    
        ''' <summary>
        ''' Creates a new SMB Pitch Shifting Sample Provider with default settings
        ''' </summary>
        ''' <param name="sourceProvider">Source provider</param>
        Public Sub New(sourceProvider As ISampleProvider)
            Me.New(sourceProvider, 4096, 4L, 0.5F)
            SW.Start()
        End Sub
    
        ''' <summary>
        ''' Creates a new SMB Pitch Shifting Sample Provider with custom settings
        ''' </summary>
        ''' <param name="sourceProvider">Source provider</param>
        ''' <param name="fftSize">FFT Size (any power of two &lt;= 4096: 4096, 2048, 1024, 512, ...)</param>
        ''' <param name="osamp">Oversampling (number of overlapping windows)</param>
        ''' <param name="initialPitch">Initial pitch (0.5f = octave down, 1.0f = normal, 2.0f = octave up)</param>
        Public Sub New(sourceProvider As ISampleProvider, fftSize As Integer, osamp As Long, initialPitch As Single)
            sourceStream = sourceProvider
            waveFormat = sourceProvider.WaveFormat
            Me.fftSize = fftSize
            Me.osamp = osamp
            PitchFactor = initialPitch
            SW.Start()
        End Sub
    
        ''' <summary>
        ''' Read from this sample provider
        ''' </summary>
        Public Function Read(buffer As Single(), offset As Integer, count As Integer) As Integer Implements ISampleProvider.Read
            If (SW.ElapsedMilliseconds > 1000) Then
                SW.Restart()
                FPS = FPSCounter
                FPSCounter = 0
            Else
                FPSCounter += 1
            End If
            Dim sampRead As Integer = sourceStream.Read(buffer, offset, count)
            If pitch = 1.0F Then
                'Nothing to do.
                Return sampRead
            End If
            If waveFormat.Channels = 1 Then
                Dim mono = New Single(sampRead - 1) {}
                Dim index = 0
                For sample As Object = offset To sampRead + offset - 1
                    mono(index) = buffer(sample)
                    index += 1
                Next
                shifterLeft.PitchShift(pitch, sampRead, fftSize, osamp, waveFormat.SampleRate, mono)
                index = 0
                For sample As Object = offset To sampRead + offset - 1
                    buffer(sample) = Limiter(mono(index))
                    index += 1
                Next
                Return sampRead
            End If
            If waveFormat.Channels = 2 Then
                Dim left = New Single((sampRead >> 1) - 1) {}
                Dim right = New Single((sampRead >> 1) - 1) {}
                Dim index = 0
                For sample As Object = offset To sampRead + offset - 1 Step 2
                    left(index) = buffer(sample)
                    right(index) = buffer(sample + 1)
                    index += 1
                Next
                shifterLeft.PitchShift(pitch, sampRead >> 1, fftSize, osamp, waveFormat.SampleRate, left)
                shifterRight.PitchShift(pitch, sampRead >> 1, fftSize, osamp, waveFormat.SampleRate, right)
                index = 0
                For sample As Object = offset To sampRead + offset - 1 Step 2
                    buffer(sample) = Limiter(left(index))
                    buffer(sample + 1) = Limiter(right(index))
                    index += 1
                Next
                Return sampRead
            End If
            Throw New Exception("Shifting of more than 2 channels is currently not supported.")
        End Function
    
        ''' <summary>
        ''' WaveFormat
        ''' </summary>
        'Public WaveFormat WaveFormat => waveFormat
        ' Public Shadows waveFormat As WaveFormat = waveFormat
        ''' <summary>
        ''' Pitch Factor (0.5f = octave down, 1.0f = normal, 2.0f = octave up)
        ''' </summary>
        Public Property PitchFactor() As Single
            Get
                Return pitch
            End Get
            Set
                pitch = Value
            End Set
        End Property
    
        Private ReadOnly Property pWaveFormat As WaveFormat Implements ISampleProvider.WaveFormat
            Get
                Return waveFormat
            End Get
        End Property
    
        Private Function Limiter(sample As Single) As Single
            'Return sample
            Dim res As Single
            If (LIM_THRESH < sample) Then
                res = (sample - LIM_THRESH) / LIM_RANGE
                res = CSng((Math.Atan(res) / M_PI_2) * LIM_RANGE + LIM_THRESH)
            ElseIf (sample < -LIM_THRESH) Then
                res = -(sample + LIM_THRESH) / LIM_RANGE
                res = -CSng((Math.Atan(res) / M_PI_2) * LIM_RANGE + LIM_THRESH)
            Else
                res = sample
            End If
            Return res
        End Function
    End Class

    And here is the looping class that I use

    Imports NAudio.Wave
    
    Class LoopStream
        Inherits WaveStream
        ReadOnly sourceStream As WaveStream
    
        Public Sub New(source As WaveStream)
            sourceStream = source
        End Sub
    
        Public Overrides ReadOnly Property WaveFormat() As WaveFormat
            Get
                Return sourceStream.WaveFormat
            End Get
        End Property
    
        Public Overrides ReadOnly Property Length() As Long
            Get
                Return Long.MaxValue / 32
            End Get
        End Property
    
        Public Overrides Property Position() As Long
            Get
                Return sourceStream.Position
            End Get
            Set
                sourceStream.Position = Value
            End Set
        End Property
    
        Public Overrides Function HasData(count As Integer) As Boolean
            ' infinite loop
            Return True
        End Function
    
        Public Overrides Function Read(buffer As Byte(), offset As Integer, count As Integer) As Integer
            Dim read__1 As Integer = 0
            While read__1 < count
                Dim required As Integer = count - read__1
                Dim readThisTime As Integer = sourceStream.Read(buffer, offset + read__1, required)
                If readThisTime < required Then
                    sourceStream.Position = 0
                End If
    
                If sourceStream.Position >= sourceStream.Length Then
                    sourceStream.Position = 0
                End If
                read__1 += readThisTime
            End While
            Return read__1
        End Function
    
        Protected Overrides Sub Dispose(disposing As Boolean)
            sourceStream.Dispose()
            MyBase.Dispose(disposing)
        End Sub
    End Class

    I think resampling is not really a great way to do what I am wanting. The pitch shifting makes it sounds like a robot if you do it too much. I can find 30+ year old Yamaha keyboards that have a way better trombone sound than my program. I think I need to figure out how to create my own oscillator, and add filters such as modulation and mutes.

    *I cant add images because my account is unverified sadly.


    • Edited by lucasheer Thursday, November 23, 2017 4:48 AM
    Thursday, November 23, 2017 4:48 AM
  • luca,

    So if I understand, the basic problem is speed?

    You sound fairly smart, but we dont know your skill level, so do take my questions the wrong way, ok?

    Also I am no expert. I have only looked at your code breifly,

    Do you understand how your code works? What is the threading for? Why do you have all the thread.sleeps? Do you understand what that does? What else is the app doing that a special thread must be used?

    As I say I looked quickly, you tell me, is your code reading your sample from disc each time it plays? Each time you playup() does it read the file from disc? I see it using the file stream. I suspect that is your problem??? You should read the file into memory at start up one time. I think you can then make a stream from the memory. Not sure. Others will know more. But you cant read from disc very fast.

    If you can explain how it works then I bet the problem will be more clear?

    Thursday, November 23, 2017 1:04 PM
  • If you understand a little about wave files you can try using a class I wrote that creates wave files. I wrote this a long time ago, so you're gonna have to figure some more out on your own. Once you generate your wav's you can play them back with directx or something...

    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/ Jump
        'The File's Header
        Public FileHeader As Header
        'Wave File's Format Sub Chunk
        Public FileFormatSubChunk As FormatSubChunk
        'Data Subchunk
        Public FileDataSubChunk As DataSubChunk
        'This structure is an optional parameter for creating a new wave file
        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
        'These are the various structures in the wave file and their description
        '                                               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 LoadFromFile(ByVal FileName As String)
            If Not My.Computer.FileSystem.FileExists(FileName) Then Exit Sub
            Dim FileBytes() As Byte = My.Computer.FileSystem.ReadAllBytes(FileName)
            Try
                Me.FileHeader.ChunkID = GetDataFromByteArray(FileBytes, 0, 0, 4)
                Me.FileHeader.ChunkSize = BitConverter.ToUInt32(FileBytes, 4)
                Me.FileHeader.Format = GetDataFromByteArray(FileBytes, 0, 8, 4)
                Me.FileFormatSubChunk.Subchunk1ID = GetDataFromByteArray(FileBytes, 0, 12, 4)
                Me.FileFormatSubChunk.Subchunk1Size = BitConverter.ToUInt32(FileBytes, 16)
                Me.FileFormatSubChunk.AudioFormat = BitConverter.ToUInt16(FileBytes, 20)
                Me.FileFormatSubChunk.NumChannels = BitConverter.ToUInt16(FileBytes, 22)
                Me.FileFormatSubChunk.SampleRate = BitConverter.ToUInt32(FileBytes, 24)
                Me.FileFormatSubChunk.ByteRate = BitConverter.ToUInt32(FileBytes, 28)
                Me.FileFormatSubChunk.BlockAlign = BitConverter.ToUInt16(FileBytes, 32)
                Me.FileFormatSubChunk.BitsPerSample = BitConverter.ToUInt16(FileBytes, 34)
                Me.FileDataSubChunk.Subchunk2ID = GetDataFromByteArray(FileBytes, 0, 36, 4)
                Me.FileDataSubChunk.Subchunk2Size = BitConverter.ToUInt32(FileBytes, 40)
                Me.FileDataSubChunk.Data = GetDataFromByteArray(FileBytes, 0, 44, Me.FileDataSubChunk.Subchunk2Size)
            Catch
                Throw New Exception("File Is Invalid or corrupt!")
            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
        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 Answer(0 To CInt((DataLength - 1))) As 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
            Dim count As Integer = -1
            For Each bt As Byte In AnswerL
                count = count + 1
                Answer(count) = bt
            Next
            Return Answer
        End Function
        Sub New(Optional ByVal Options As WaveFileOptions = Nothing)
            Try
                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
            Catch ex As Exception
            End Try
        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


    Hire Me For This Job!
    Don't forget to vote for Helpful Posts and Mark Answers!
    *This post does not reflect the opinion of Microsoft, or its employees.

    Thursday, November 23, 2017 2:29 PM
    Moderator
  • The calculations for creating sawtooth and sine wave forms are pretty straight forward, but do you know how i can use these calculations and play them in real time? I know I need a buffer, and a small one at that, but is there a video tutorial you can show me to use DirectSound or some other library to play my small buffers in real time?

    Also, would the sound player call my procedure for the sound, or will I have to feed the buffer to the sound player? Or will I need to create a class that will support the type of the sound player?

    Do you have a video tutorial or an example project? That would probably help me the most.

    • Edited by lucasheer Saturday, November 25, 2017 4:18 AM
    Saturday, November 25, 2017 4:17 AM
  • Hello! I've been working on a project for the past 3 months. I want to make a mini electrical trombone, that uses a breath pressure sensor for the modulation/oscillation+volume, and an optical encoder for the slide. I will be using either a raspberry Pi 3B or an Intel Atom board for the audio processing.

    So far, I am stuck on creating a decent real-time trombone/brass synthesizer that doesn't take boat loads of CPU. In my last attempt, I tried re-sampling some of my own trombone playing and looping it with a library called NAudio, and doing pitch adjustment when the slide is moved. It sounds decent, but the more i shift the pitch, the more robotic it sounds. Even if I fixed the robotic sounds, it requires massive amounts of CPU. The portable boards I can use are just barely able to hand it.

    If anyone can give me tips, or even point me in the right direction, that would really help me.

    Well I don't have a PC in order to attempt to assist you codewise. However the code I posted in this thread Making a "ding" sound which is from this thread originally Beep Beep may be able to help. However I believe a byte array for a .Wav file is created and then once the byte array is complete SoundPlayer is used to play the byte array stored in a memory stream.

    I suppose it could be possible to somehow use the math you know to alter the sound bytes placed into the byte array to be played such that a trombone sound would occur. However I believe that for the header of a .Wav file there is a requirement to know how my bytes of sound there are for the header itself.

    Here's a link to creating a .Wav file header and note the WavFile helper class too - Stream Mic Audio to another computer - so I suppose the wav file headers values at the appropriate byte locations could be altered once the byte array of audio is created such that then you would know the entire files length requirement maybe. But I didn't read all the code so maybe that isn't necessary if the code is used correctly.


    La vida loca

    Saturday, December 2, 2017 7:13 PM