2012-02-27 25 views
5

Tengo un sonido de fondo en un ciclo infinito. Quiero que se desvanezca cuando el usuario presiona un botón.Fading sound in/out

He intentado lo siguiente:

  • A DirectSoundOut se inicia con la WaveStream
  • un temporizador cambia el volumen de la WaveChannel32.

El problema:

  • Cambiar el volumen mientras está reproduciendo el sonido produce ruidos.

¿Alguien sabe una solución mejor?

Respuesta

6

Para realizar un fundido de entrada o desaparición uniforme, debe hacerlo en el nivel de muestra. Luego multiplicas cada muestra por un número que aumenta o disminuye gradualmente. Está utilizando WaveChannel32, por lo que su audio ya se ha convertido en flotador de 32 bits. Luego crearía otro implementador IWaveProvider que fue responsable de hacer el fundido de entrada y el desvanecimiento. Normalmente pasaría por las muestras sin cambios, pero en el método de lectura, si está fundido o atenuado, se multiplicaría cada muestra (o se emparejaría si es estéreo).

La interfaz ISampleProvider en NAudio 1.5 fue diseñada para facilitar mucho este tipo de cosas, ya que le permite tratar muestras como flotadores de 32 bits, en lugar de implementar IWaveProvider que requiere convertir de un byte [] a flotar []. Aquí hay un SampleProvider para fade-in y fade-out que acabo de hacer, que incluiré en el próximo NAudio, y con suerte lo bloguearé pronto. Simplemente llame al BeginFadeIn o BeginFadeOut con la duración de fade adecuada.

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

O puede simplemente, hacer esto:

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

^Un ejemplo de un fundido de salida. Lo uso en mis propios programas, funciona bien.

Cuestiones relacionadas