2012-02-27 102 views
5

我有無限循環播放的背景聲音。我希望它在用戶按下按鈕時淡出。衰落聲音輸入/輸出

我試過如下:

  • 一個DirectSoundOut與的WaveStream
  • A定時器開始改變WaveChannel32的體積。

問題:

  • 改變體積,同時播放聲音時產生的噪音。

有沒有人知道更好的解決方案?

回答

6

要執行平滑的淡入或淡出,您需要在樣本級別執行此操作。然後將每個樣本乘以逐漸增加或減少的數字。您正在使用WaveChannel32,因此您的音頻已被轉換爲32位浮點。然後,我會創建另一個負責淡入和淡出的IWaveProvider實現者。通常它會通過樣本不變,但在Read方法中,如果您處於淡入或淡出狀態,它將乘以每個樣本(如果它是立體聲的話)。

NAudio 1.5中的ISampleProvider接口旨在使這種類型的事情更容易,因爲它允許您將樣本作爲32位浮點數處理,而不是實現IWaveProvider,它需要您將byte []轉換爲float []。這裏有一個用於淡入和淡出的SampleProvider,我只是將它包含在下一個NAudio中,並希望儘快發佈它。只需撥打BeginFadeInBeginFadeOut以適當的淡入持續時間。

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; } 
    } 
} 
-1

或者你也可以,這樣做:

while (waveOut.volume > 0.1) 
{ 
    waveOut.volume -= 0.1; 
    System.Threading.Thread.Sleep(10); 
} 

^一個淡出的例子。我在我自己的程序中使用它,工作正常。