2012-02-27 64 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); 
} 

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