This project has moved. For the latest updates, please go here.

how to use SimpleCompressorStream?

May 17 at 6:19 PM
Edited May 17 at 6:33 PM
Hello

I record from the mic and I need to compress & normalize the wav file that I record. I would like to use SimpleCompressorStream for compressing but I can't find any example how to do that. I also wonder how to normalize the file too

At the moment my record method looks like that:
public void Record(String strFile)
    {            
        m_WaveSource = new WaveIn();
        m_WaveSource.WaveFormat = new WaveFormat(44100, 1);

        m_WaveSource.DataAvailable += new EventHandler<WaveInEventArgs>(DataAvailable);
        m_WaveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(RecordingStopped);

        m_WaveFile = new WaveFileWriter(strFile, _WaveSource.WaveFormat);

        m_WaveSource.StartRecording();
    }
       void DataAvailable(object sender, WaveInEventArgs e)
        {
            if (m_WaveFile != null)
            {
                m_WaveFile.Write(e.Buffer, 0, e.BytesRecorded);
                
                double sum = 0;
                for (var i = 0; i < e.BytesRecorded; i = i + 2)
                {
                    double sample = BitConverter.ToInt16(e.Buffer, i) / 32768.0;
                    sum += (sample * sample);
                }
                double rms = Math.Sqrt(sum / (e.BytesRecorded / 2));
                var decibel = 20 * Math.Log10(rms);
                
              
                VolumeMeter.Value = decibel;
                m_WaveFile.Flush();
            }
        }
May 17 at 7:06 PM
Edited May 17 at 7:07 PM
SimpleCompressorStream is a ISampleProvider implementing class. Meaning, it is thought to be used for output driven systems (PULL, like a output device).

I see two options here:

1) Pass the data to a BufferedWaveProvider -> .ToSampleProvider -> SimpleCompressorStream -> Read the data out again (PULL system)
2) Manually parse the data, as u did above, copy the SimpleCompressorStream functions and objects in the class and process it directly (PUSH system)

I strongly recommend the first option. It has also the nice benift, that you don´t have to parse the format yourself, is well tested and optimized.
May 17 at 7:22 PM
Do you have an example for me how to do option 1? I'm pretty new to the entire audio topic and not sure if I understood what I shall do
May 17 at 7:36 PM
Edited May 17 at 8:02 PM
In VB I´d do it that way (fast pseudo code):

Private BWP as BufferedWaveProvider
Private COMP as SimpleCompressorStream 

Sub DataAvailable(Bayval sender as object, e as WaveInEventArgs)

If BWP is Nothing then
BWP = new BufferedWaveProvider(e.Waveformat)
COMP = new SimpleCompressorStream(BWP.ToSampleProvider)
End If

BWP.AddSamples(e.Buffer, 0, e.BytesRecorded)

Dim SampCount as Integer = e.BytesRecorded / (e.WaveFormat.BitsPerSample / 8)

Dim Samples(SampCount - 1) as Single

COMP.Read(Samples, 0, SampCount)

// Display the compressed samples stored in "Samples", write to file etc.

Next

End Sub
May 18 at 9:16 AM
Thank you for your example but I'm sorry I don't manage to convert this to my C# code because the parameters of
BWP = new BufferedWaveProvider(e.Waveformat)
COMP = new SimpleCompressorStream(BWP.ToSampleProvider)
are not fitting for me and I have no idea what to put there. The first line: e has no value called WaveFormat. I only have that from my record method in m_WaveSource.WaveFormat . I tried to use that but then I have the problem that the secondline isn't working the SimpleCompressorStream wants a wav stream object which I haven't...
May 18 at 5:16 PM
Oh, alright I was wrong. SimpleCompressorStream doenst implement ISampleProvider, but WaveStream.

In this case simply change the second line to:
COMP = new SimpleCompressorStream(BWP)
And it should work. Discard the sample code and just call the read method of COMP.

For the Waveformat you are right, just pass the waveformat of the input device here.
May 22 at 4:28 PM
I finally managed to make it work that way:
WaveFileReader audio = new WaveFileReader(strFile);
            
            string strCompressedFile = "";

            byte[] WaveData = new byte[audio.Length];
            
            SimpleCompressorStream Compressor = new SimpleCompressorStream(audio);
            Compressor.Enabled = true;

            if (Compressor.Read(WaveData, 0, WaveData.Length) > 0)
            {
                strCompressedFile = "xxx.wav";               
            
                WaveFileWriter CompressedWaveFile = new WaveFileWriter(strCompressedFile, audio.WaveFormat);
                CompressedWaveFile.Write(WaveData, 0, WaveData.Length);
                CompressedWaveFile.Flush();                                                     

            }