diff --git a/Docs/FadeInOutSampleProvider.md b/Docs/FadeInOutSampleProvider.md index c267e608..32439977 100644 --- a/Docs/FadeInOutSampleProvider.md +++ b/Docs/FadeInOutSampleProvider.md @@ -14,6 +14,14 @@ var fade = new FadeInOutSampleProvider(audio, true); fade.BeginFadeIn(2000); ``` +After fade in is complete, `FadeInComplete` event is triggered: +```c# +fade.FadeInComplete += (sender, e) => { + Console.WriteLine("Fade in was done!"); +}; +fade.BeginFadeIn(2000); +``` + Now we can pass our `FadeInOutSampleProvider` to an output device and start playing. We'll hear the audio fading in over the first two seconds. ```c# @@ -28,6 +36,15 @@ At some point in the future, we might want to fade out, and we can trigger that fade.BeginFadeOut(2000); ``` +It also triggers `FadeOutComplete` event, when fade out is complete + +```c# +fade.FadeOutComplete += (sender, e) => { + Console.WriteLine("Fade out was done!"); +}; +fade.BeginFadeOut(2000); +``` + Once the audio has faded out, the `FadeInOutSampleProvider` continues to read from its source but emits silence until it reaches its end, or until you call `BeginFadeIn` again. ### Taking it further diff --git a/NAudio.Core/Wave/SampleProviders/FadeInOutSampleProvider.cs b/NAudio.Core/Wave/SampleProviders/FadeInOutSampleProvider.cs index e589b6ca..b3522f5a 100644 --- a/NAudio.Core/Wave/SampleProviders/FadeInOutSampleProvider.cs +++ b/NAudio.Core/Wave/SampleProviders/FadeInOutSampleProvider.cs @@ -1,4 +1,6 @@ -namespace NAudio.Wave.SampleProviders +using System; + +namespace NAudio.Wave.SampleProviders { /// /// Sample Provider to allow fading in and out @@ -13,6 +15,16 @@ enum FadeState FadingOut, } + /// + /// Raised when scheduled fade-in is done + /// + public event EventHandler FadeInComplete; + + /// + /// Raised when scheduled fade-out is done + /// + public event EventHandler FadeOutComplete; + private readonly object lockObject = new object(); private readonly ISampleProvider source; private int fadeSamplePosition; @@ -108,6 +120,8 @@ private void FadeOut(float[] buffer, int offset, int sourceSamplesRead) if (fadeSamplePosition > fadeSampleCount) { fadeState = FadeState.Silence; + FadeOutComplete?.Invoke(this, EventArgs.Empty); + // clear out the end ClearBuffer(buffer, sample + offset, sourceSamplesRead - sample); break; @@ -129,6 +143,8 @@ private void FadeIn(float[] buffer, int offset, int sourceSamplesRead) if (fadeSamplePosition > fadeSampleCount) { fadeState = FadeState.FullVolume; + FadeInComplete?.Invoke(this, EventArgs.Empty); + // no need to multiply any more break; } diff --git a/NAudioTests/WaveStreams/FadeInOutSampleProviderTests.cs b/NAudioTests/WaveStreams/FadeInOutSampleProviderTests.cs index 9192ae66..310e2c12 100644 --- a/NAudioTests/WaveStreams/FadeInOutSampleProviderTests.cs +++ b/NAudioTests/WaveStreams/FadeInOutSampleProviderTests.cs @@ -120,5 +120,61 @@ public void BufferIsZeroedAfterFadeOut() Assert.AreEqual(20, read); Assert.AreEqual(0, buffer[0]); } + + [Test] + public void FadeInCompleteInvoked() + { + // given + var source = new TestSampleProvider(10, 1); // 10 samples per second + source.UseConstValue = true; + source.ConstValue = 100; + var fade = new FadeInOutSampleProvider(source); + var fadeInsCount = 0; + fade.FadeInComplete += (sender, e) => + { + fadeInsCount++; + }; + + // when + fade.BeginFadeIn(1000); + + // then + float[] buffer = new float[20]; + int read = fade.Read(buffer, 0, 20); + Assert.AreEqual(20, read); + Assert.AreEqual(0, buffer[0]); // start of fade-in + Assert.AreEqual(50, buffer[5]); // half-way + Assert.AreEqual(100, buffer[10]); // fully fade in + Assert.AreEqual(100, buffer[15]); // fully fade in + Assert.AreEqual(1, fadeInsCount); // we want one-shot event (when fade in was completed once) + } + + [Test] + public void FadeOutCompleteInvoked() + { + // given + var source = new TestSampleProvider(10, 1); // 10 samples per second + source.UseConstValue = true; + source.ConstValue = 100; + var fade = new FadeInOutSampleProvider(source); + var fadeOutsCount = 0; + fade.FadeOutComplete += (sender, e) => + { + fadeOutsCount++; + }; + + // when + fade.BeginFadeOut(1000); + + // then + float[] buffer = new float[20]; + int read = fade.Read(buffer, 0, 20); + Assert.AreEqual(20, read); + Assert.AreEqual(100, buffer[0]); // start of fade-out + Assert.AreEqual(50, buffer[5]); // half-way + Assert.AreEqual(0, buffer[10]); // fully fade out + Assert.AreEqual(0, buffer[15]); // fully fade out + Assert.AreEqual(1, fadeOutsCount); // we want one-shot event (when fade out was completed once) + } } }