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

simple example to control volume using NAudio

Oct 26, 2015 at 11:19 PM
I know this probably sounds simple, but I'm getting started and need to know how to control the volume. I've seen comments on using the VolumeSampleProvider but I'm having trouble with it. My current code looks like this:

m_WavePlayer = new WaveOut();
m_AudioFileReader = new AudioFileReader(strFullPath);
m_WavePlayer.Init(m_AudioFileReader);
m_WavePlayer.Play();

A little help would go a long way... Thx, Ed
Oct 27, 2015 at 1:22 AM
Here's how i've done it.


format = WaveFormat.CreateIeeeFloatWaveFormat(readerStream.WaveFormat.SampleRate, 2);
        // Provide PCM conversion if needed
        if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
        {
            readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
            readerStream = new BlockAlignReductionStream(readerStream);
        }

        // Provide conversion to 16 bits if needed
        if (readerStream.WaveFormat.BitsPerSample != 16)
        {
            readerStream = new WaveFormatConversionStream(format, readerStream);
        }

        mixingSampleProvider = new MixingSampleProvider(format);
        waveChannel = new WaveChannel32(readerStream);


        //Convert wave to samples
        waveToSample = new WaveToSampleProvider(waveChannel);

        //Provide metering support
        meterSampleProvider = new MeteringSampleProvider(waveToSample);

        //Provide volume support
        volumeSampleProvider = new VolumeSampleProvider(meterSampleProvider);

        //Convert samples back to wave
        sampleToWave = new SampleToWaveProvider(volumeSampleProvider );

        if (waveOutDevice == null)
        {
            waveOutDevice = new WaveOutEvent();
            waveOutDevice.PlaybackStopped += new EventHandler<StoppedEventArgs>(waveOutDevice_PlaybackStopped);
        }

        waveOutDevice.DeviceNumber = CPCore.Instance.AudioOutDevice.Id;
        waveOutDevice.Init(sampleToWave);



Everytime you need to support a new provider, use the last one as input for the next.

Like this:

//Convert wave to samples
        waveToSample = new WaveToSampleProvider(waveChannel);

        //Provide metering support
        meterSampleProvider = new MeteringSampleProvider(waveToSample);

        //Provide volume support
        volumeSampleProvider = new VolumeSampleProvider(meterSampleProvider);

        //Add the samples to the mixed stream used to enable crossfading
        mixingSampleProvider.AddMixerInput(volumeSampleProvider);

        //Add support for equalizer
        equalizerSampleProvider = new EqualizerSampleProvider(mixingSampleProvider, equalizerBands);
        equalizerSampleProvider.IsActive = initialEQIsActive.GetValueOrDefault();

        //Convert samples back to wave
        sampleToWave = new SampleToWaveProvider(equalizerSampleProvider);
Oct 27, 2015 at 6:47 PM
Thank you for the suggestion, here is the code that is functional for creating the wave player:
            m_WavePlayer = new WaveOut();
            m_AudioFileReader = new AudioFileReader(strFullPath);
            m_VolSampleProvider = new VolumeSampleProvider(m_AudioFileReader);
            m_VolSampleProvider.Volume = Volume;
            m_SmplToWaveProvider = new SampleToWaveProvider(m_VolSampleProvider);
            m_WavePlayer.Init(m_SmplToWaveProvider);
And then the volume can dynamically change using this:
            if (m_VolSampleProvider != null)
                m_VolSampleProvider.Volume = value;
Interestingly, the VolumeSampleProvider and SampleToWaveProvider don't have Dispose() methods. I'm wondering if I have a memory leak ?
Oct 27, 2015 at 9:55 PM
Another interesting question, when I run this code out of the main form thread (testing) there are no issues at all. But, in my real application it must be performed from a background thread. Initially I attempted to create a member variable to be used by a background thread but started having issues similar to cross-threading - errors indicating that it was not called on the thread it was created on.

OK, so I decided that I would just create a new instance from whatever thread I planned to use it, then dispose of it after it was done. But I'm finding that the WaveOut object is hanging the thread when I perform the line of code below, any ideas?
            m_WavePlayer.Dispose();
Oct 28, 2015 at 12:38 PM
First, AudioFileReader already has a Volume property, so no need for an additional VolumeSampleProvider.
Second, I recommend WaveOutEvent instead of WaveOut when working on non GUI threads.
Marked as answer by eelston on 10/28/2015 at 6:30 AM
Oct 28, 2015 at 2:30 PM
Thank you for the quick response - I have a lot to learn. So I eliminated the VolumeSampleProvider and seem to have the same results by setting the volume of the AudioFileReader with less complexity. Also, I have changed to WaveOutEvent and the problem with the background thread also seems to have been solved.

Thanks so much for the help.