作者热门文章
- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个无限循环播放的背景音。我希望它在用户按下按钮时淡出。
我尝试了以下方法:
问题:
有人知道更好的解决方案吗?
最佳答案
要执行平滑的淡入或淡出,您需要在样本级别执行此操作。然后将每个样本乘以逐渐增加或减少的数字。您正在使用 WaveChannel32,因此您的音频已经转换为 32 位 float 。然后,我将创建另一个 IWaveProvider 实现程序,负责执行淡入和淡出。通常它会通过样本不变,但在 Read 方法中,如果您处于淡入或淡出状态,它会乘以每个样本(如果是立体声,则成对)。
NAudio 1.5 中的 ISampleProvider 接口(interface)旨在使此类事情变得更加容易,因为它允许您将样本作为 32 位 float 进行处理,而不是实现 IWaveProvider,后者需要您将 byte[] 转换为 float[ ].这是我刚刚制作的用于淡入和淡出的 SampleProvider,我将把它包含在下一个 NAudio 中,并希望尽快在博客中介绍它。只需使用适当的淡入淡出持续时间调用 BeginFadeIn
或 BeginFadeOut
。
public class FadeInOutSampleProvider : ISampleProvider
{
enum FadeState
{
Silence,
FadingIn,
FullVolume,
FadingOut,
}
private readonly object lockObject = new object();
private readonly ISampleProvider source;
private int fadeSamplePosition;
private int fadeSampleCount;
private FadeState fadeState;
public FadeInOutSampleProvider(ISampleProvider source)
{
this.source = source;
this.fadeState = FadeState.FullVolume;
}
public void BeginFadeIn(double fadeDurationInMilliseconds)
{
lock (lockObject)
{
fadeSamplePosition = 0;
fadeSampleCount = (int)((fadeDurationInMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeState = FadeState.FadingIn;
}
}
public void BeginFadeOut(double fadeDurationInMilliseconds)
{
lock (lockObject)
{
fadeSamplePosition = 0;
fadeSampleCount = (int)((fadeDurationInMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeState = FadeState.FadingOut;
}
}
public int Read(float[] buffer, int offset, int count)
{
int sourceSamplesRead = source.Read(buffer, offset, count);
lock (lockObject)
{
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;
}
}
}
public WaveFormat WaveFormat
{
get { return source.WaveFormat; }
}
}
关于c# - 淡入/淡出声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9468083/
我是一名优秀的程序员,十分优秀!