How to code circullar buffer to create a delay and used the wavein for micrcophone and output to speaker?

Oct 16, 2012 at 2:52 PM

How to code circullar buffer to create a delay and used the wavein for micrcophone input and output to speaker?

 

 public NAudio.Wave.WaveIn input = null;
        public NAudio.Wave.DirectSoundOut waveout = null;
        public NAudio.Wave.WaveInProvider wavein = null;
       
        private void button1_Click(object sender, EventArgs e)
        {

            WaveIn input = new NAudio.Wave.WaveIn();
            input.WaveFormat = new NAudio.Wave.WaveFormat(44100, 2);
            IWaveProvider wavein = new NAudio.Wave.WaveInProvider(input);
       
            waveout = new NAudio.Wave.DirectSoundOut();
            waveout.Play();
         
     
           

        }

 

Any answer Guys? :)   

Coordinator
Oct 17, 2012 at 1:34 PM

put the audio received into a BufferedWaveProvider and play from that.

Nov 29, 2012 at 11:51 AM

Hi all,

I have seen this topic, and I have a question like the one above. here 

is my code;

private WaveIn sourceStream = null;
            private WaveOut waveOut = null;
            private BufferedWaveProvider bufferedWaveIn = null;
            public WaveIn_WaveOut_TimeShift(int deviceNumberIN, int deviceNumberOUT, int sampleRate)
            {
                sourceStream = new WaveIn();
                sourceStream.DeviceNumber = deviceNumberIN;
                sourceStream.WaveFormat = new WaveFormat(sampleRate, WaveIn.GetCapabilities(deviceNumberIN).Channels);
                sourceStream.DataAvailable += new EventHandler<WaveInEventArgs>(sourceStream_DataAvailable);

                bufferedWaveIn = new BufferedWaveProvider(sourceStream);
                bufferedWaveIn.BufferDuration = TimeSpan.FromSeconds(30);

                waveOut = new WaveOut();
                waveOut.DeviceNumber = deviceNumberOUT;
                waveOut.Init(waveIn);
                
            }
            ~WaveIn_WaveOut_TimeShift()
            {
                Dispose();
            }
            public void Dispose()
            {
                if (sourceStream != null)
                {
                    sourceStream.StopRecording();
                    sourceStream.Dispose();
                    sourceStream = null;
                }
                if (waveOut != null)
                {
                    waveOut.Stop();
                    waveOut.Dispose();
                    waveOut = null;
                }
            }
           
            public void Start()
            {
                sourceStream.StartRecording();
                waveOut.Play();
            }
            public void Stop()
            {
                sourceStream.StopRecording();
            }
            private void sourceStream_DataAvailable(object sender, WaveInEventArgs e)
            {
                bufferedWaveIn.AddSamples(e.Buffer, 0, e.BytesRecorded);
            }
 
        }

How can I add a delay of 15 second for example. I am routing waveIn to waveOut real time. I want to create a delay of n seconds on it.

Coordinator
Nov 29, 2012 at 11:59 AM

Implement an IWaveProvider that in its Read method, just returns empty buffers until a total of 15 * WaveFormat.AverageBytesPerSecond have been requested. Then start returning data from the BufferedWaveProvider.

Mark

Nov 29, 2012 at 12:26 PM

Sorry but I think that I could not define the question well.

I am routing waveIn input to waveout device at real time.

Then after I want to listen 15 seconds history so I want to roll back to 15 seconds back and listen history for 15 seconds. (I can loose real time data while listening history). 

I think that BufferedWaveProvider buffers the desired length of data with BufferDuration property.  

So in this case I only want BufferedWaveProvider to provide me a buffer (for waveOut device) that is from history of n seconds instead of latest.

İs this possible?

Coordinator
Nov 29, 2012 at 12:57 PM

you'd need to make your own customised version of BufferedWaveProvider in order to do this.

Nov 29, 2012 at 1:02 PM

Ok.

Thanks Mark.

Dec 1, 2012 at 5:29 AM

Hi Mark thank you for responding, 

I am newbie to this framework. kindly explain how to do it? your answer was "put the audio received into a BufferedWaveProvider and play from that."

I don't get it actually. please help me for this stuff. 

 

 

 

Coordinator
Dec 6, 2012 at 5:11 PM

in your code sample above, waveOut.Init should take the bufferedProivder not waveIn. That will mean you are playing from you buffered provider.

Dec 7, 2012 at 9:15 AM

Hi Mark again,

I have implemented my won BufferedWaveProvider as you said, and it was successfully worked. First of all thank you for your advice.

I want to ask another question.

I have multiple analog inputs and I have to sum all of these inputs to route the sum to other waveOut devices.

I have created a list of bufferedwaveProviders that each element is serving for each wave input (recording). ( I have to have an ability to return back to n seconds in any time, so I have used bufferedWaveprovider with some editing)

Now I can route one waveIn analog device to waveOut analog device with the help of this bufferredWaveProvider.

And for summing the audios I have coded like the one below. 

private void SumProviders(int length)
            {
                byte[] last = new byte[length];
                byte[] temp = new byte[length];
                int bytesPerSample = 4; 
                for (int index = 0; index < bufferedWaveInProviders.Count; index++)
                {
                    //read wave providers one by one
                    bufferedWaveInProviders[index].Read(temp, 0, length);
                    //add all...
                    for (int i = 0; i < length / bytesPerSample; i++)
                    {
                        float sampleTemp = BitConverter.ToSingle(temp, i * bytesPerSample);
                        float sampleLast = BitConverter.ToSingle(last, i * bytesPerSample);
                        sampleLast = sampleLast + sampleTemp;
                        byte[] bytes = BitConverter.GetBytes(sampleLast);
                        Array.Copy(bytes, 0, last, i * bytesPerSample, bytesPerSample);
                    }
                }
                bufferedWaveForPlaying.AddSamples(last, 0, length);
            }

I am calling this function on sourceStream_DataAvailable event handler of my waveIn devices for each input.

Here bufferedWaveForPlaying is the buffer that I have initilized my waveOut device with. 

Now I am hearing the mixed audio, but playing speed is too slow? What can be the problem?

 

Coordinator
Dec 9, 2012 at 8:04 AM

if the play speed is too slow, check your waveformat. For example playing stereo audio as though it was mono can result in playback too slow.

Mark

Dec 11, 2012 at 11:25 AM

Hi Again,

I have solved the problem by using WaveMixerStream32 class with some editing.

Another question is I want to send this mixer's output from UDP port to somewhere. (as digital sound)

I have implemented a thread and for each 1000ms, I am sending a block from mixer to udp port.

 

For each 1000 ms;

my thread is reading a block from mixer by mixer.Read(data,0,block_size)

My block size is : waveformat.sampleRate * waveformat.BlockAlign 

An then send this data to udp port.

 

On the server side I am receiving this data, but if I play the data, it is too noisy?

What can be the problem?

 

In adition to this: I have sent an existing wave file like this to udp port, and there is not any problem.  I received and played at the server side. Also I have played the mixer's output by waveout device. The problem is about sending mixer's output by udp(catching mixer's output buffer)!

 

 

Dec 11, 2012 at 12:14 PM

I have solved the problem, thanks.

I had to do a 32 to 16 conversion that I have forgetton before sending it from UDP.