存取原始聲音資料

Flash Player 9 以及更新的版本,Adobe AIR 1.0 以及更新的版本

SoundMixer.computeSpectrum() 方法可讓應用程式讀取目前正在播放的聲音波形之原始聲音資料。如果目前有一個以上的 SoundChannel 物件正在播放, SoundMixer.computeSpectrum() 方法就會顯示每個混合在一起的 SoundChannel 物件所結合而成的聲音資料。

聲音資料將以包含 512 位元組資料的 ByteArray 物件傳回,每個物件都包含介於 -1 到 1 的浮點值。這些值都代表正在播放的聲音波形中的點振幅。這些值會以兩個 256 群組傳送,第一個群組是供左立體聲道使用,而第二個群組則是供右立體聲道使用。

如果 FFTMode 參數設定為 true SoundMixer.computeSpectrum() 方法便會傳回頻譜資料,而不是波形資料。頻譜會從最低頻率到最高頻率,顯示依聲音頻率排列的振幅。快速傅利葉轉換 (Fast Fourier Transform,FFT) 可用來將聲音波形資料轉換為頻譜資料。產生的頻譜值範圍從 0 到大約 1.414 (2 的平方根)。

下圖會比較當 FFTMode 參數設定為 true 以及設定為 false 時, computeSpectrum() 方法所傳回的資料。其資料用於此圖的聲音包含左聲道中大聲的低音以及右聲道中的鼓擊聲。
檢視完整大小的圖形
由 SoundMixer.computeSpectrum() 方法傳回的值
A.
fftMode=true

B.
fftMode=false

computeSpectrum() 方法也可以傳回以較低的位元速率重新取樣的資料。一般而言,這雖然無法得到詳細資料,但可獲得較平滑的聲音波形資料或頻率資料。 stretchFactor 參數會控制取樣 computeSpectrum() 方法資料的速率。當 stretchFactor 參數設定為預設值 0 時,聲音資料的取樣速率為 44.1 kHz。stretchFactor 參數的後繼值可依次將速率減半,因此值為 1 會指定 22.05 kHz 的速率,而值為 2 則會指定 11.025 kHz 的速率,依此類推。使用較高的 stretchFactor 值時, computeSpectrum() 方法仍然會傳回每個立體聲道 256 個位元組。

SoundMixer.computeSpectrum() 方法具有某些限制:

  • 因為來自麥克風或 RTMP 串流的資料無法穿越全域 SoundMixer 物件,所以 SoundMixer.computeSpectrum() 方法將不會從這些來源傳回資料。

  • 如果正在播放的一或多個聲音是來自目前內容安全執行程序之外的來源,則安全性限制將會導致 SoundMixer.computeSpectrum() 方法擲回錯誤。如需有關 SoundMixer.computeSpectrum() 方法之安全性限制的詳細資訊,請參閱 載入和播放聲音時的安全性考量 將載入的媒體當做資料加以存取

但在 AIR 應用程式中,應用程式安全執行程序中的內容 (使用 AIR 應用程式所安裝的內容) 沒有這些安全性限制。

建立簡單的聲音視覺化檢視器

下列範例會使用 SoundMixer.computeSpectrum() 方法,顯示隨著每個影格變化的聲音波形圖表:

import flash.display.Graphics; 
import flash.events.Event; 
import flash.media.Sound; 
import flash.media.SoundChannel; 
import flash.media.SoundMixer; 
import flash.net.URLRequest; 
 
const PLOT_HEIGHT:int = 200; 
const CHANNEL_LENGTH:int = 256; 
 
var snd:Sound = new Sound(); 
var req:URLRequest = new URLRequest("bigSound.mp3"); 
snd.load(req); 
 
var channel:SoundChannel; 
channel = snd.play(); 
addEventListener(Event.ENTER_FRAME, onEnterFrame); 
snd.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete); 
 
var bytes:ByteArray = new ByteArray(); 
 
function onEnterFrame(event:Event):void 
{ 
    SoundMixer.computeSpectrum(bytes, false, 0); 
     
    var g:Graphics = this.graphics; 
     
    g.clear(); 
    g.lineStyle(0, 0x6600CC); 
    g.beginFill(0x6600CC); 
    g.moveTo(0, PLOT_HEIGHT); 
     
    var n:Number = 0; 
         
    // left channel 
    for (var i:int = 0; i < CHANNEL_LENGTH; i++)  
    { 
        n = (bytes.readFloat() * PLOT_HEIGHT); 
        g.lineTo(i * 2, PLOT_HEIGHT - n); 
    } 
    g.lineTo(CHANNEL_LENGTH * 2, PLOT_HEIGHT); 
    g.endFill(); 
     
    // right channel 
    g.lineStyle(0, 0xCC0066); 
    g.beginFill(0xCC0066, 0.5); 
    g.moveTo(CHANNEL_LENGTH * 2, PLOT_HEIGHT); 
     
    for (i = CHANNEL_LENGTH; i > 0; i--)  
    { 
        n = (bytes.readFloat() * PLOT_HEIGHT); 
        g.lineTo(i * 2, PLOT_HEIGHT - n); 
    } 
    g.lineTo(0, PLOT_HEIGHT); 
    g.endFill(); 
} 
 
function onPlaybackComplete(event:Event) 
{ 
    removeEventListener(Event.ENTER_FRAME, onEnterFrame); 
}

此範例會先載入和播放聲音檔案,然後偵聽 Event.ENTER_FRAME 事件,此事件將會在聲音播放時觸發 onEnterFrame() 方法。 onEnterFrame() 方法會從呼叫 SoundMixer.computeSpectrum() 方法開始,它會將聲音波形資料儲存在 bytes ByteArray 物件中。

聲音波形會使用向量繪圖 API 進行標繪。 for 迴圈會循環第一個 256 資料值,以代表左立體聲道,並使用 Graphics.lineTo() 方法從每個點繪製線條到下一個點。第二個 for 迴圈會循環下一組的 256 值,這一次會以反轉順序,並且從右至左進行標繪。產生的聲音波形標繪可能會出現有趣的鏡像效果,如下列影像所示。