Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
NAudio basic example of how to begin a fade out after a certain number of milliseconds have elapsed
// Define other methods and classes here
/// <summary>
/// Sample Provider to allow fading in and out
/// </summary>
public class DelayFadeOutSampleProvider : ISampleProvider
{
enum FadeState
{
Silence,
FadingIn,
FullVolume,
FadingOut,
}
private readonly object lockObject = new object();
private readonly ISampleProvider source;
private int fadeSamplePosition;
private int fadeSampleCount;
private int fadeOutDelaySamples;
private int fadeOutDelayPosition;
private FadeState fadeState;
/// <summary>
/// Creates a new FadeInOutSampleProvider
/// </summary>
/// <param name="source">The source stream with the audio to be faded in or out</param>
/// <param name="initiallySilent">If true, we start faded out</param>
public DelayFadeOutSampleProvider(ISampleProvider source, bool initiallySilent = false)
{
this.source = source;
this.fadeState = initiallySilent ? FadeState.Silence : FadeState.FullVolume;
}
/// <summary>
/// Requests that a fade-in begins (will start on the next call to Read)
/// </summary>
/// <param name="fadeDurationInMilliseconds">Duration of fade in milliseconds</param>
public void BeginFadeIn(double fadeDurationInMilliseconds)
{
lock (lockObject)
{
fadeSamplePosition = 0;
fadeSampleCount = (int)((fadeDurationInMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeState = FadeState.FadingIn;
}
}
/// <summary>
/// Requests that a fade-out begins (will start on the next call to Read)
/// </summary>
/// <param name="fadeDurationInMilliseconds">Duration of fade in milliseconds</param>
public void BeginFadeOut(double fadeAfterMilliseconds, double fadeDurationInMilliseconds)
{
lock (lockObject)
{
fadeSamplePosition = 0;
fadeSampleCount = (int)((fadeDurationInMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeOutDelaySamples = (int)((fadeAfterMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeOutDelayPosition = 0;
//fadeState = FadeState.FadingOut;
}
}
/// <summary>
/// Reads samples from this sample provider
/// </summary>
/// <param name="buffer">Buffer to read into</param>
/// <param name="offset">Offset within buffer to write to</param>
/// <param name="count">Number of samples desired</param>
/// <returns>Number of samples read</returns>
public int Read(float[] buffer, int offset, int count)
{
int sourceSamplesRead = source.Read(buffer, offset, count);
lock (lockObject)
{
if (fadeOutDelaySamples > 0)
{
fadeOutDelayPosition += sourceSamplesRead / WaveFormat.Channels;
if (fadeOutDelayPosition >= fadeOutDelaySamples)
{
fadeOutDelaySamples = 0;
fadeState = FadeState.FadingOut;
}
}
if (fadeState == FadeState.FadingIn)
{
FadeIn(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.FadingOut)
{
FadeOut(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.Silence)
{
ClearBuffer(buffer, offset, count);
}
}
return sourceSamplesRead;
}
private static void ClearBuffer(float[] buffer, int offset, int count)
{
for (int n = 0; n < count; n++)
{
buffer[n + offset] = 0;
}
}
private void FadeOut(float[] buffer, int offset, int sourceSamplesRead)
{
int sample = 0;
while (sample < sourceSamplesRead)
{
float multiplier = 1.0f - (fadeSamplePosition / (float)fadeSampleCount);
for (int ch = 0; ch < source.WaveFormat.Channels; ch++)
{
buffer[offset + sample++] *= multiplier;
}
fadeSamplePosition++;
if (fadeSamplePosition > fadeSampleCount)
{
fadeState = FadeState.Silence;
// clear out the end
ClearBuffer(buffer, sample + offset, sourceSamplesRead - sample);
break;
}
}
}
private void FadeIn(float[] buffer, int offset, int sourceSamplesRead)
{
int sample = 0;
while (sample < sourceSamplesRead)
{
float multiplier = (fadeSamplePosition / (float)fadeSampleCount);
for (int ch = 0; ch < source.WaveFormat.Channels; ch++)
{
buffer[offset + sample++] *= multiplier;
}
fadeSamplePosition++;
if (fadeSamplePosition > fadeSampleCount)
{
fadeState = FadeState.FullVolume;
// no need to multiply any more
break;
}
}
}
/// <summary>
/// WaveFormat of this SampleProvider
/// </summary>
public WaveFormat WaveFormat
{
get { return source.WaveFormat; }
}
}
void Main()
{
using(var reader = new AudioFileReader(@"D:\Audio\Music\Example.mp3"))
{
var fadeOut = new DelayFadeOutSampleProvider(reader);
fadeOut.BeginFadeOut(10000, 2000);
using(var player = new WaveOutEvent())
{
player.Init(fadeOut);
player.Play();
while(player.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(500);
}
}
}
}
@Ahmed-Abdelhameed

This comment has been minimized.

Copy link

@Ahmed-Abdelhameed Ahmed-Abdelhameed commented Sep 1, 2017

I just fixed a bug in the Read method which caused the fade out to be applied in the wrong position. Please update the gist. Here's my fork for reference: https://gist.github.com/Ahmed-Abdelhameed/b867a8cfe739cd7a128b73a33d317402. You can also refer to this SO question: https://stackoverflow.com/a/45997576/4934172.

@fosterz

This comment has been minimized.

Copy link

@fosterz fosterz commented Jun 20, 2018

I'm facing one weird issue with this quick solution. It works fine until I move trackbar of tha song. For e.g if I move the trackbar then fadeout never happens.

@SR-TheCodingGenius

This comment has been minimized.

Copy link

@SR-TheCodingGenius SR-TheCodingGenius commented Nov 30, 2018

I just fixed a bug in the Read method which caused the fade out to be applied in the wrong position. Please update the gist. Here's my fork for reference: https://gist.github.com/Ahmed-Abdelhameed/b867a8cfe739cd7a128b73a33d317402. You can also refer to this SO question: https://stackoverflow.com/a/45997576/4934172.

I tried with your fix , but there are clicks when the audio file is cross-faded with itself , but no clicks were found with the original code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment