EfektyW poprzednim wpisie opisałem niewielki problem z zapętlaniem dźwięków w Silverlight 4. Obecnie w Silverlight 5 Beta, która pojawiła się niecałe 2 tygodnie temu ten problem został rozwiązany dla plików .wav. Klasa SoundEffect została ściągnięta z frameworku XNA i odpowiednio uproszczona na potrzeby Silverlight. XNA to framework, to budowania gier, więc nic dziwnego, że ta klasa jest wręcz stworzona do właśnie takich efektów.

Link do działającej aplikacji.

Aby odtworzyć tę aplikację musisz pobrać Silverlight 5 Beta. Gdy wejdzie pełna wersja aplikacja zostanie zaktualizowana. Licencja bety pozwala ludziom takim jak ja na umieszczanie takich aplikacji na swoich blogach.

Klasa SoundEffect : głośność, ton, głośnik

Umieściłem parę krótkich dźwięków .wav w projekcie Silverlight. Aby były one spakowane w pliku XAP wraz z bibliotekami Silverlight kliknąłem prawym przyciskiem na każdego z nich , a potem wybrałem “Properties” . We właściwościach pliku trzeba ustawić “Bulid Action” na “Content” i to wszystko.

Aby odtworzyć dźwięk podczas naciśnięcia przycisku trzeba naturalnie najpierw zdobyć strumień. Zrobiłem to tym razem za pomocą klasy “Application.GetResource” , która zwraca klasę “StreamResourceInfo”, która posiada właściwość “Stream”. Gdy mamy już strumień trzeba tylko z klasy “SoundEffect” zastosować metodę “FromStream”.

Metoda “Play” umożliwia uruchomienie danego efektu w określonej głośności oraz tonie (od –1 do 1), oraz także w określonym głośniku (od –1 do 1) . W mojej aplikacji te zmienne w metodzie są ustawiane za pomocą kontrolek Slider (SL_Volume i tak dalej). Ponieważ zwracają one wartość double zatem muszą być rzutowane na float.

C#Dzwięk strunyprivate void Button_Struna_Click
    (object sender, RoutedEventArgs e)
{
    var Struna = Application.GetResourceStream
        (new Uri("Struna.wav", UriKind.Relative));

    SoundEffect effect = SoundEffect.FromStream(Struna.Stream);
    effect.Play(
        (float)SL_Volume.Value,
        (float)SL_Pitch.Value,
        (float)SL_Pan.Value);
}

Działanie jest zupełnie inne niż gdybyśmy odtwarzali ten efekt w MediaElement. W grach nie jest niczym dziwnym, że słyszymy np. ten sam efekt eksplozji od różnych elementów. Wcześniej by uzyskać taki efekt trzeba było tymczasowo stworzyć klasę MediaElement, po czym pozbyć się jej po odtworzeniu efektu. Brzmi jak kupa roboty, a właśnie tutaj ten problem mamy z głowy. Wielokrotne naciśnięcie na przycisk spowoduje błyskawiczne odtworzenie każdego efektu, po czym szybką śmierć elementów, które w odtworzeniu wzięły udział.

Klasa SoundEffect ma też właściwość statyczną “MasterVolume”, która kontroluje głośność wszystkich elementów stworzonych w tej właśnie klasie.

SoundEffect.MasterVolume = (float)MasterVolume.Value;

Klasa SoundEffectInstance : zapętlanie dźwięku

Zaraz i to wszystko ? Oczywiście, że nie. Do bardziej skomplikowanych czynności mamy klasę “SoundEffectInstance”. Tutaj w końcu możemy tworzyć pętle, wygląda to tak:

C#Dzwięk L1var SoundBit_L1 = Application.GetResourceStream
    (new Uri("Bit.wav", UriKind.Relative));
SoundEffect bit = SoundEffect.FromStream(SoundBit_L1.Stream);

SoundEffectInstance loopEffect = bit.CreateInstance();
loopEffect.Pan = -1f;
loopEffect.IsLooped = true;
loopEffect.Play();

Poza standardowymi właściwościami zwrócę jeszcze uwagę na możliwość pobraniu stanu w jakim nasz efekt się znajduje.

C#TextTB_1.Text = "Bit:" + loopEffect.State.ToString();

Możliwości : Dispather Timer

Możliwość zapętlania prostych dźwięków .wav pozwala na skomponowanie muzyki bazującej na powtarzających się samplach w odpowiednim momencie. Każdy kto używał “Fruit Loops” albo bawił się w ten sposób to wie o czym mówię. Zastosowałem prosty licznik czasowy, który w odpowiednim momencie poprostu zmienia efekt dźwiękowe.

C#Dispather TimerTimer.Interval = TimeSpan.FromSeconds(10);
Timer.Start();
Timer.Tick += (ss, ee) =>
{
    Timer.Stop();
    if (changeBit == true)
    {
        loopEffect.Stop();
        loopEffect2.Stop();
        loopEffect3.Play();
        loopEffect4.Play();
        changeBit = false;
        Timer.Interval = TimeSpan.FromSeconds(30);
    }
    else {
        loopEffect.Play();
        loopEffect2.Play();
        loopEffect3.Stop();
        loopEffect4.Stop();
        changeBit = true;
        Timer.Interval = TimeSpan.FromSeconds(15);
    }

Timer.Start();

Próbowałem swój utwór wzorować na muzyce z polskiej gry Amigowej “Misja Harolda”. Wyszło nawet całkiem, całkiem . Wsłuchując się w niektóre stare gry można zauważyć, że muzyka składa się z powtarzających się elementów.