I'm building a application for background music & ambience sounds. Basically I want to play music and ambience simultaneously. Both inputs are using FadeInOutSampleProviders
which are added to a mixer input.
I want continuous playback on both channels, so after one file has completed playback the next one should be played.
Until now I only had one input file and worked with the WaveOutEvent.PlaybackStopped
event, but this event doesn't fire using the mixer (presumably because the stream of data technically doesn't end)
Is there an elegant way besides just calculating the playtime of the clip and just assuming it finished playing after the playtime elapsed?
I use this class as a "container" for audioclips which handle the playback for me.
public sealed class FadingAudioPlaybackContainer: IDisposable
{
private readonly AudioPlaybackEngine _engine;
private readonly FadeInOutSampleProvider _fader;
private readonly AudioFileReader _fileReader;
public event EventHandler? PlaybackStopped;
public FadingAudioPlaybackContainer(string filePath, AudioPlaybackEngine engine)
{
_engine = engine;
_fileReader = new AudioFileReader(filePath);
_fader = new FadeInOutSampleProvider(_fileReader, true);
//THIS event doesn't fire because the stream doesn't end
_engine.PlaybackStopped += (sender, args) => PlaybackStopped?.Invoke(sender, EventArgs.Empty);
}
public async Task FadeInAsync(int durationInMs)
{
_fader.BeginFadeIn(durationInMs);
_engine.AddMixerInput(_fader);
await Task.Delay(durationInMs);
}
/*...*/
}
This is my "playback engine" which is registered as a singleton on the Host.
//Thanks, Mark!
public class AudioPlaybackEngine : IDisposable
{
public event EventHandler? PlaybackStopped;
private readonly IWavePlayer _outputDevice;
private readonly MixingSampleProvider _mixer;
public AudioPlaybackEngine(int sampleRate = 44100, int channelCount = 2)
{
_outputDevice = new WaveOutEvent();
_mixer = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channelCount))
{
ReadFully = true
};
_outputDevice.Init(_mixer);
//AGAING: This doesn't fire because the stream never ends(?)
_outputDevice.PlaybackStopped += (sender, args) => PlaybackStopped?.Invoke(this, EventArgs.Empty);
_outputDevice.Play();
}
public void AddMixerInput(ISampleProvider input)
{
_mixer.AddMixerInput(input);
}
public void RemoveMixerInput(ISampleProvider input)
{
_mixer.RemoveMixerInput(input);
}
public void Dispose()
{
_outputDevice.Dispose();
}
}
I didn't find a solution for this, so I just switched to using multiple WaveOutEvent
without mixing them manually. I don't know if that's intended, but it works like a charm!