Search code examples
c#audionaudio

Is this NAudio re-sampling audio correctly implemented?


I've used Mark Heath's example of using a MixingSampleProvider, but one of the things he said he hadn't done was re-sampling. So I've had a go at doing that myself, but although the audio plays fine, I would appreciate if somebody could confirm that I have done it correctly please.

I have created resampledAudio using MediaFoundationResampler and instead of reading from the audioFileReader I read from resampledAudio. However the WaveToSampleProvider doesn't have a .Length property so I'm still using audioFileReader.Length for the size of List<float> and assuming they are the same length because it's the same audio file?

class CachedSound
{
    public float[] AudioData { get; private set; }
    public WaveFormat WaveFormat { get; private set; }
    public CachedSound(string audioFileName)
    {
        using (var audioFileReader = new AudioFileReader(audioFileName))
        {
            WaveToSampleProvider resampledAudio;

            resampledAudio = new WaveToSampleProvider(new MediaFoundationResampler(new SampleToWaveProvider(audioFileReader), WaveFormat.CreateIeeeFloatWaveFormat(44100, 2)) { ResamplerQuality = 60 });
            WaveFormat = resampledAudio.WaveFormat;

            //WaveFormat = audioFileReader.WaveFormat;
            var wholeFile = new List<float>((int)(audioFileReader.Length / 4));
            var readBuffer = new float[resampledAudio.WaveFormat.SampleRate * resampledAudio.WaveFormat.Channels];
            int samplesRead;
            while ((samplesRead = resampledAudio.Read(readBuffer, 0, readBuffer.Length)) > 0)
            {
                wholeFile.AddRange(readBuffer.Take(samplesRead));
            }
            AudioData = wholeFile.ToArray();
        }
    }
}

The other problem I had was that I originally decided to check if the audio needed re-sampling in the first place with:

if (audioFileReader.WaveFormat.SampleRate != 44100)
{
     resampledAudio = new WaveToSampleProvider(new MediaFoundationResampler(new SampleToWaveProvider(audioFileReader), WaveFormat.CreateIeeeFloatWaveFormat(44100, 2)) { ResamplerQuality = 60 });
} else
{
    resampledAudio = ??; //I'm not sure how to convert from an AudioFileReader to a WaveToSampleProvider
}

But as the comment suggests, if the audio didn't need re-sampling how do I get the audio into resampledAudio so it can be read as they are of different types? The only other option I could think of was to repeat the code which reads the audio so it reads from audioFileReader if it ins't re-sampled and resampledAudio if it is.


Solution

  • Declare resampledAudio as an ISampleProvider so you can assign audioFileReader directly to it.