2012-02-27 17 views
5

Mam dźwięk w tle odtwarzany w nieskończonej pętli. Chcę, aby zanikło, gdy użytkownik naciśnie przycisk.Zanikanie/zanikanie dźwięku

że próbował następujące:

  • DirectSoundOut rozpoczyna się z WaveStream
  • czasomierza zmienia objętość WaveChannel32.

Problem:

  • Zmiana głośności podczas odtwarzania dźwięku wytwarza dźwięki.

Czy ktoś zna lepsze rozwiązanie?

Odpowiedz

6

Aby wykonać płynne pojawianie się lub zanikanie, należy to zrobić na poziomie próbki. Następnie pomnóż każdą próbkę przez stopniowo rosnącą lub malejącą liczbę. Używasz WaveChannel32, więc twoje audio zostało już przekonwertowane do formatu 32-bitowego. Następnie utworzyłbym innego programistę IWaveProvider, który był odpowiedzialny za wykonanie zanikania i zanikania. Zwykle przechodzi on przez niezmienione próbki, ale w metodzie Read, jeśli jesteś w fazie zanikania lub zanikania, to pomnożysz każdą próbkę (lub parę, jeśli jest stereo).

Interfejs ISampleProvider w NAudio 1.5 został zaprojektowany w taki sposób, aby uczynić tego typu rzeczy łatwiejszym, ponieważ pozwala na przetwarzanie próbek już jako 32-bitowych zmiennoprzecinkowych, zamiast implementacji IWaveProvider, która wymaga konwersji z bajtu [] na float []. Oto SampleProvider dla zanikania i zanikania, które właśnie napisałem, a które dołączę do następnego NAudio i mam nadzieję, że wkrótce o tym pomówimy. Wystarczy zadzwonić pod numer BeginFadeIn lub BeginFadeOut z odpowiednim czasem trwania.

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

Albo można po prostu to zrobić:

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

^Przykładem zaniku-out. Używam go w swoich własnych programach, działa dobrze.