3

I'm coding my first audio application, and I'm struggling for hours on trying to change samplerate of a cached sound. I'm using NAudio and I was able to change the Volume, tweaking the Read() method of my ISampleProvider.

Here is the CachedSound Class :

public class CachedSound
{
    public float[] AudioData { get; private set; }
    public WaveFormat WaveFormat { get; set; }

    public CachedSound(string audioFileName)
    {
        using (var audioFileReader = new AudioFileReader(audioFileName))
        {
            WaveFormat = audioFileReader.WaveFormat;

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

And here is the CachedSoundSampleProvider class :

using NAudio.Wave;
using System;

public delegate void PlaybackEndedHandler();

public class CachedSoundSampleProvider : ISampleProvider
{
    public event PlaybackEndedHandler PlaybackEnded;
    private CachedSound cachedSound;

    private long _position;
    public long Position {
        get { return _position; }
        set { _position = value; }
    }

    private float _volume;
    public float Volume {
        get { return _volume; }
        set { _volume = value; }
    }

    private float _pitchMultiplicator;
    public float PitchMultiplicator
    {
        get { return _pitchMultiplicator; }
        set { _pitchMultiplicator = value; }
    }

    public WaveFormat OriginalWaveFormat { get; set; }

    public WaveFormat WaveFormat {
        get { return cachedSound.WaveFormat; }
    }

    //Constructeur
    public CachedSoundSampleProvider(CachedSound _cachedSound)
    {
        cachedSound = _cachedSound;
        OriginalWaveFormat = WaveFormat;
    }

    public int Read(float[] destBuffer, int offset, int numBytes)
    {
        long availableSamples = cachedSound.AudioData.Length - Position;
        long samplesToCopy = Math.Min(availableSamples, numBytes);

        //Changing original audio data samplerate
        //Double speed to check if working
        cachedSound.WaveFormat = new WaveFormat(cachedSound.WaveFormat.SampleRate*2, cachedSound.WaveFormat.Channels);
        Array.Copy(cachedSound.AudioData, Position, destBuffer, offset, samplesToCopy);

        //Changing Volume
        for (int i = 0; i < destBuffer.Length; ++i)
            destBuffer[i] *= (Volume > -40) ? (float)Math.Pow(10.0f, Volume * 0.05f) : 0;

        Position += samplesToCopy;
        if (availableSamples == 0) PlaybackEnded();
        return (int)samplesToCopy;
    }
}

I don't know how I can achieve this yet. My goal is simple, I want to be able to tweak sample rate at realtime. I read it's impossible to change it on the ISampleProvider interface.

That's why I tried to change it on the original audioData.

Thanks in advance for your help ! :)

Alann S.
  • 125
  • 12
  • Are you trying to resample the sound at a different rate or simply change the playback frequency? – Corey Aug 27 '15 at 08:09
  • I think changing the playback frequency of my ISampleProvider herited class is what I'm looking for. You might find usefull to know that I'm playing multiple sound at the same time. So I'm sending each of my "CachedSound" in this CachedSoundSampleProvider, then I'm adding it to a MixingSampleProvider using AddMixerInput() (start the playing), or using RemoveMixerInput() (stop the playing) – Alann S. Aug 27 '15 at 18:03
  • I was wrong, I think the shifting must be done on my audio, directly; – Alann S. Aug 28 '15 at 21:05
  • I found a solution. I rewrote a small part of the mixer, to allow different samplerate in the same mixer. – Alann S. Aug 29 '15 at 01:13

0 Answers0