通过使用
SoundMixer.computeSpectrum()
方法,应用程序可以读取当前所播放的波形的原始声音数据。如果当前播放多个 SoundChannel 对象,
SoundMixer.computeSpectrum()
方法将显示混合在一起的每个 SoundChannel 对象的组合声音数据。
声音数据是作为 ByteArray 对象(包含 512 个字节的数据)返回的,其中的每个字节包含一个介于 -1 和 1 之间的浮点值。这些值表示所播放的声音波形中的点的波幅。这些值是分为两个组(每组包含 256 个值)提供的,第一个组用于左立体声声道,第二个组用于右立体声声道。
如果将
FFTMode
参数设置为
true
,
SoundMixer.computeSpectrum()
方法将返回频谱数据,而非波形数据。频谱显示按声音频率(从最低频率到最高频率)排列的波幅。可以使用快速傅立叶变换 (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,采样率就减小一半,因此,值 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);
}
此示例先加载并播放一个声音文件,然后在播放声音的同时侦听将触发
onEnterFrame()
方法的
Event.ENTER_FRAME
事件。
onEnterFrame()
方法先调用
SoundMixer.computeSpectrum()
方法,后者将声音波形数据存储在
bytes
ByteArray 对象中。
声音波形是使用矢量绘图 API 绘制的。
for
循环将循环访问第一批 256 个数据值(表示左立体声声道),然后使用
Graphics.lineTo()
方法绘制一条从每个点到下一个点的直线。第二个
for
循环将循环访问下一批 256 个值,此时按相反的顺序(从右到左)对它们进行绘制。生成的波形图可能会产生非常有趣的镜像图像效果,如以下图像中所示。
|
|
|