Praca z dźwiękiem generowanym dynamicznie

Flash Player 10 i nowsze wersje, Adobe AIR 1.5 i nowsze wersje

Uwaga: Możliwość dynamicznego generowania dźwięku jest dostępna począwszy od wersji 10 programu Flash Player i wersji 1.5 środowiska Adobe AIR.

Zamiast ładowania lub przesyłania strumieniowego istniejącego dźwięku można generować dane audio dynamicznie. Dane audio można generować po przypisaniu detektora zdarzenia sampleData obiektu Sound. (Zdarzenie sampleData jest zdefiniowane w klasie SampleDataEvent w pakiecie flash.events). W tym środowisku obiekt Sound nie ładuje danych dźwięku z pliku. Zamiast tego działa jak gniazdo dla danych audio, które są do niego przesyłane strumieniowo dzięki wykorzystaniu funkcji przypisanej dla danego zdarzenia.

Po dodaniu detektora zdarzenia sampleData do obiektu Sound obiekt tymczasowo żąda danych, które zostaną dodane do bufora dźwięku. Ten bufor zawiera dane dla obiektu Sound przeznaczonego do odtworzenia. Wywołana metoda play() obiektu Sound wywołuje zdarzenie sampleData w przypadku żądania nowych danych. (Jest to prawdziwe tylko wówczas, gdy obiekt Sound nie załadował danych mp3 z pliku).

Obiekt SampleDataEvent zawiera właściwość data . W detektorze zdarzenia należy zapisać obiekty ByteArray do obiektu data . Tablice bajtów zapisane w tym obiekcie są dodawane do buforowanych danych dźwięku, które są odtwarzane przez obiekt Sound. Tablica bajtów w tym buforze jest strumieniem wartości zmiennoprzecinkowych z zakresu od -1 do 1. Każda wartość zmiennoprzecinkowa reprezentuje amplitudę jednego kanału (lewego lub prawego) próbki dźwięku. Dźwięk jest próbkowany z częstotliwością 44100 próbek na sekundę. Każda próbka zawiera lewy i prawy kanał jako dane zmiennoprzecinkowe w tablicy bajtów, z przeplotem.

W funkcji modułu obsługi należy użyć metody ByteArray.writeFloat() w celu zapisania właściwości data zdarzenia sampleData . Przykład: poniższy kod generuje falę sinusoidalną:

var mySound:Sound = new Sound(); 
mySound.addEventListener(SampleDataEvent.SAMPLE_DATA, sineWaveGenerator); 
mySound.play(); 
function sineWaveGenerator(event:SampleDataEvent):void 
{ 
    for (var i:int = 0; i < 8192; i++) 
    { 
        var n:Number = Math.sin((i + event.position) / Math.PI / 4); 
        event.data.writeFloat(n); 
        event.data.writeFloat(n); 
    } 
}

Po wywołaniu metody Sound.play() aplikacja rozpoczyna wywoływanie modułu obsługi zdarzenia, żądając danych próbek dźwięku. Aplikacja wysyła zdarzenia w miarę odtwarzania dźwięku do czasu zakończenia dostarczania danych lub do czasu wywołania metody SoundChannel.stop() .

Opóźnienie tego zdarzenia jest uzależnione od platformy i może zostać zmienione w przyszłych wersjach programu Flash Player i środowiska AIR. Nie należy z góry zakładać opóźnienia — zamiast tego należy je obliczyć. W celu obliczenia opóźnienia należy użyć poniższej formuły:

(SampleDataEvent.position / 44.1) - SoundChannelObject.position

Dla właściwości data obiektu SampleDataEvent należy udostępnić od 2048 do 8192 próbek (dla każdego wywołania detektora zdarzenia). W celu zapewnienia najlepszego działania należy udostępnić jak najwięcej próbek (maksymalnie 8192). Im mniejsza liczba próbek zostanie udostępniona, tym większe jest prawdopodobieństwo, że podczas odtwarzania będą występowały kliknięcia i trzaski. Może do tego dochodzić na różnych platformach i może występować w różnych sytuacjach — np. w przypadku zmiany wielkości przeglądarki. Kod, który działa na danej platformie po udostępnieniu 2048 próbek, może nie działać tak samo dobrze na innej platformie. Jeśli wymagane jest jak najniższe opóźnienie, należy rozważyć możliwość wybierania ilości danych przez użytkownika.

Jeśli udostępniona zostanie liczba próbek mniejsza niż 2048 (na wywołanie detektora zdarzenia sampleData ), wówczas działanie aplikacji zatrzyma się po odtworzeniu pozostałych próbek. Następnie obiekt SoundChannel wywołuje zdarzenie SoundComplete.

Modyfikowanie dźwięku z danych mp3

Metoda Sound.extract() służy do wyodrębniania danych z obiektu Sound. Dane można wykorzystywać (i modyfikować) w celu zapisania w strumieniu dynamicznym innego obiektu Sound przeznaczonego do odtworzenia. Przykład: poniższy kod wykorzystuje bajty załadowanego pliku MP3 i przekazuje je przez funkcję filtru upOctave() :

var mySound:Sound = new Sound(); 
var sourceSnd:Sound = new Sound(); 
var urlReq:URLRequest = new URLRequest("test.mp3"); 
sourceSnd.load(urlReq); 
sourceSnd.addEventListener(Event.COMPLETE, loaded); 
function loaded(event:Event):void 
{ 
    mySound.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound); 
    mySound.play(); 
} 
function processSound(event:SampleDataEvent):void 
{ 
        var bytes:ByteArray = new ByteArray(); 
        sourceSnd.extract(bytes, 8192); 
        event.data.writeBytes(upOctave(bytes)); 
} 
function upOctave(bytes:ByteArray):ByteArray 
{ 
    var returnBytes:ByteArray = new ByteArray(); 
    bytes.position = 0; 
    while(bytes.bytesAvailable > 0) 
    { 
        returnBytes.writeFloat(bytes.readFloat()); 
        returnBytes.writeFloat(bytes.readFloat()); 
        if (bytes.bytesAvailable > 0) 
        { 
            bytes.position += 8; 
        } 
    } 
    return returnBytes; 
}

Ograniczenia dotyczące generowanych dźwięków

Jeśli detektor zdarzenia sampleData jest używany z obiektem Sound, wówczas jedynymi innymi metodami Sound, jakie są aktywne, są metody Sound.extract() i Sound.play() . Wywołanie innych metod lub właściwości powoduje wygenerowanie wyjątku. Wszystkie metody i właściwości obiektu SoundChannel są nadal aktywne.