This project has moved and is read-only. For the latest updates, please go here.

Writing MixingSampleProvider to file

Jan 29, 2015 at 3:53 PM
Edited Jan 29, 2015 at 3:54 PM
Hi, I'm trying to write mixers data to file but can't get it stopping.
This is the code I use for data writing. I also have added writer.Dispose() on Stop function but never get to there because mixer data just comes in. Maybe it's a wrong place to write output on BufferedWaveProvider.DataAvailable?
private void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
        {
            bufferedWaveProvider.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
            lock (this)
            {
                int nReadF = 0;
                float[] bufferF = new float[1024];
                byte[] bufferB = new byte[2048];
                WaveBuffer destWaveBuffer = new WaveBuffer(bufferB);
                int destOffset = 0;
                float volume = 1;
                do
                {
                    destOffset = 0;
                    nReadF = waveMixer.Read(bufferF, 0, bufferF.Length);
                    for (int n = 0; n < bufferF.Length; n++)  //  (HTML FORMATTING GLITCH)
                    {

                        // adjust volume
                        float sample32 = bufferF[n] * volume;
                        // clip
                        if (sample32 > 1.0f)
                            sample32 = 1.0f;
                        if (sample32 < -1.0f)
                            sample32 = -1.0f;

                        destWaveBuffer.ShortBuffer[destOffset++] = (short)(sample32 * 32767);
                    }

                    writer.Write(bufferB, 0, nReadF * 2);
                    destWaveBuffer.Clear();
                }
                while (nReadF > 0);
            }
        }
Any advice or sample would be cool. I looked all over the internet for sample how to write this output to file but didn't find any. Mark you said you will get us this sample later :)
Jan 29, 2015 at 10:47 PM
I'm not clear what you're doing here. What are you mixing with? What's reading from your bufferedWaveProvider?
Have you seen my article here?
Feb 2, 2015 at 11:06 AM
Yes I have read your article there and most of the logic is from there but I don't know how to implement saving MixingSampleProvider to a file.

Here is my all code
class SoundRecorder
    {
        private WaveIn recorder;
        private WaveIn backRecorder;
        private BufferedWaveProvider bufferedWaveProvider, bufferedWaveProvider2;
        private MixingSampleProvider waveMixer;

        private WaveFileWriter writer;

        public void Record()
        {
            lock (this)
            {
                var format = WaveFormat.CreateIeeeFloatWaveFormat(11500, 2);


                recorder = new WaveIn();
                recorder.WaveFormat = format;
                recorder.DataAvailable += RecorderOnDataAvailable;
                recorder.RecordingStopped += recorder_RecordingStopped;
                bufferedWaveProvider = new BufferedWaveProvider(recorder.WaveFormat) { DiscardOnBufferOverflow = true };

                backRecorder = new WaveIn();
                backRecorder.DeviceNumber = 1;
                backRecorder.DataAvailable += backRecorder_DataAvailable;
                backRecorder.WaveFormat = format;
                bufferedWaveProvider2 = new BufferedWaveProvider(backRecorder.WaveFormat) { DiscardOnBufferOverflow = true };
                waveMixer = new MixingSampleProvider(format);
                waveMixer.ReadFully = false;
                waveMixer.AddMixerInput(bufferedWaveProvider);
                waveMixer.AddMixerInput(bufferedWaveProvider2);

                writer = new WaveFileWriter("woho.wav", format);

                recorder.StartRecording();
                backRecorder.StartRecording();

            }

        }

        void recorder_RecordingStopped(object sender, StoppedEventArgs e)
        {
            waveMixer.RemoveAllMixerInputs();
        }

        void backRecorder_DataAvailable(object sender, WaveInEventArgs waveInEventArgs)
        {
            bufferedWaveProvider2.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
        }
        private void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
        {
            bufferedWaveProvider.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
            lock (this)
            {
                int nReadF = 0;
                float[] bufferF = new float[1024];
                byte[] bufferB = new byte[2048];
                WaveBuffer destWaveBuffer = new WaveBuffer(bufferB);
                int destOffset = 0;
                float volume = 1;
                do
                {
                    destOffset = 0;
                    nReadF = waveMixer.Read(bufferF, 0, bufferF.Length);
                    for (int n = 0; n < bufferF.Length; n++)  //  (HTML FORMATTING GLITCH)
                    {

                        // adjust volume
                        float sample32 = bufferF[n] * volume;
                        // clip
                        if (sample32 > 1.0f)
                            sample32 = 1.0f;
                        if (sample32 < -1.0f)
                            sample32 = -1.0f;

                        destWaveBuffer.ShortBuffer[destOffset++] = (short)(sample32 * 32767);
                    }

                    writer.Write(bufferB, 0, nReadF * 2);
                    destWaveBuffer.Clear();
                }
                while (nReadF > 0);
            }
        }

        public void Stop()
        {
            recorder.StopRecording();
            backRecorder.StopRecording();
            writer.Dispose();

        }
    }
All I wan't is to save waveMixer output to a file. I don't need to play it immediately
Feb 2, 2015 at 1:51 PM
I'd do something like this (not tested, just an example):
        void backRecorder_DataAvailable(object sender, WaveInEventArgs waveInEventArgs)
        {
            bufferedWaveProvider2.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
            MixToFile();
        }
        private void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
        {
            bufferedWaveProvider.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
            MixToFile();
        }
        private void MixToFile(object sender, WaveInEventArgs waveInEventArgs)
        {
            var availableSamples = Math.Min(bufferedWaveProvider1.BytesAvailable,bufferedWaveProvider2.BytesAvailable) / 4;
            if (availableSamples > 0)
            {
                float[] buffer = new float[availableSamples]
                var samples = mixer.Read(buffer, 0, samples)
                writer.WriteSamples(buffer,0,samples);
            }
        }
To do your volume and clipping, I'd create a custom ISampleProvider to put after the mixer. This keeps the code clean.

Also, only Dispose your writer once the RecordingFinished event has fired.