我有無限循環播放的背景聲音。我希望它在用戶按下按鈕時淡出。衰落聲音輸入/輸出
我試過如下:
- 一個DirectSoundOut與的WaveStream
- A定時器開始改變WaveChannel32的體積。
問題:
- 改變體積,同時播放聲音時產生的噪音。
有沒有人知道更好的解決方案?
我有無限循環播放的背景聲音。我希望它在用戶按下按鈕時淡出。衰落聲音輸入/輸出
我試過如下:
問題:
有沒有人知道更好的解決方案?
要執行平滑的淡入或淡出,您需要在樣本級別執行此操作。然後將每個樣本乘以逐漸增加或減少的數字。您正在使用WaveChannel32,因此您的音頻已被轉換爲32位浮點。然後,我會創建另一個負責淡入和淡出的IWaveProvider實現者。通常它會通過樣本不變,但在Read方法中,如果您處於淡入或淡出狀態,它將乘以每個樣本(如果它是立體聲的話)。
NAudio 1.5中的ISampleProvider接口旨在使這種類型的事情更容易,因爲它允許您將樣本作爲32位浮點數處理,而不是實現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; }
}
}
或者你也可以,這樣做:
while (waveOut.volume > 0.1)
{
waveOut.volume -= 0.1;
System.Threading.Thread.Sleep(10);
}
^一個淡出的例子。我在我自己的程序中使用它,工作正常。