使用動態產生的音效

Flash Player 10 以及更新的版本,Adobe AIR 1.5 以及更新的版本

備註: 從 Flash Player 10 和 Adobe AIR 1.5 開始引進了使用動態產生音訊的功能

您不要載入或串流已有的聲音,也可以動態產生音效資料。當您為 Sound 物件的 sampleData 事件指定事件偵聽程式時,可以產生音效資料 (sampleData 會定義於 flash.events 套件的 SampleDataEvent 類別中)。在這個環境中,Sound 物件並不會從檔案載入聲音資料,而是做為透過指定給此事件的函數而串流給它之聲音資料的通訊端。

當您將 sampleData 事件偵聽程式加入至 Sound 物件時,這個物件會定期要求資料以加入至聲音緩衝。這項緩衝包含 Sound 物件要播放的資料。當您呼叫 Sound 物件的 play() 方法時,這個方法會在要求新的聲音資料時傳送 sampleData 事件 (只有在 Sound 物件尚未從檔案載入 MP3 資料時才適用)。

SampleDataEvent 物件包含 data 屬性。您可以在自己的事件偵聽程式中,將 data 物件設定為 ByteArray 物件。您對這個物件設定的位元組陣列會加入 Sound 物件播放的緩衝聲音資料。緩衝區中的位元組陣列是浮點值從 -1 到 1 的串流。每個浮點值都表示聲音樣本某一聲道 (左或右) 的振幅。對聲音進行取樣時,取樣頻率是每秒 44,100 個樣本。每個樣本都包含左右聲道,並插入做為位元組陣列中的浮點資料。

您可以在自己的處理常式函數中,使用 ByteArray.writeFloat() 方法將 data 屬性設定為 sampleData 事件。例如,下列程式碼會產生正弦波:

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); 
    } 
}

呼叫 Sound.play() 時,應用程式會開始呼叫您的事件處理常式,要求聲音樣本資料。當聲音播放時,應用程式會持續傳送事件,直到您停止提供資料或呼叫 SoundChannel.stop() 為止。

事件的延遲因平台而異,而且在未來發行的 Flash Player 和 AIR 中可能會變更。請勿依賴特定的延遲,建議您計算所需的延遲。若要計算延遲,請使用下列公式:

(SampleDataEvent.position / 44.1) - SoundChannelObject.position

每次呼叫事件偵聽程式時,提供給 SampleDataEvent 物件之 data 屬性的樣本數範圍可以從 2048 到 8192。為了達到最佳效能,請盡可能提供多個樣本 (最高可達 8192 個樣本)。您提供越少的樣本,播放時越可能發生喀嚓聲和爆音。這個行為可能因平台而異,而且會發生於各種情況,例如調整瀏覽器大小時。您撰寫的程式碼在只提供 2048 個樣本時可能適用於某個平台,但該程式碼在不同平台上執行時可能會不盡理想。如果您需要最低的延遲,請考慮讓使用者可選取資料量。

如果在每次呼叫 sampleData 事件偵聽程式時,您提供的樣本數少於 2048,應用程式就會在播放剩餘的樣本之後停止,SoundChannel 物件接著會傳送 SoundComplete 事件。

修改 MP3 資料的聲音

您可以使用 Sound.extract() 方法從 Sound 物件擷取資料,然後再使用 (及修改) 該資料,以寫入至其它 Sound 物件的動態串流供播放之用。例如,下列程式碼會使用已載入之 MP3 檔案的位元組,並透過濾鏡函數 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; 
}

所產生之聲音的限制

當您搭配 Sound 物件使用 sampleData 事件偵聽程式時,所啟用的其它 Sound 方法只有 Sound.extract()Sound.play()。呼叫任何其它方法或屬性都會產生例外。SoundChannel 物件的所有方法和屬性仍然會啟用。