处理动态生成的音频

可以动态生成音频数据,而不是加载或流式传输现有声音。在为 Sound 对象的 sampleData 事件分配事件侦听器时,可以生成音频数据。( sampleData 事件在 SampleDataEvent 类中定义。)在这种情况下,Sound 对象不从文件中加载声音数据。相反,它将用作声音数据的套接字,声音数据通过使用您分配给此事件的函数流入它。

在您将 sampleData 事件侦听器添加到 Sound 对象后,该对象将定期请求数据以添加到声音缓冲区。此缓冲区包含 Sound 对象要播放的数据。在调用 Sound 对象的 play() 方法时,它会在请求新的声音数据时调度 sampleData 事件。(只有在 Sound 对象尚未从文件加载 mp3 数据时,此操作才生效。)

SampleDataEvent 对象包含 data 属性。在事件侦听器中,将 ByteArray 对象写入此 data 对象。写入此对象的字节数组将添加到 Sound 对象播放的缓冲声音数据中。缓冲区中的字节数组是由从 -1 到 1 的浮点值组成的流。各浮点值均代表声音样本的一个声道(左声道或右声道)的幅度。声音按每秒 44,100 个样本进行采样。每个样本均包含左声道和右声道,在字节数组中以浮点数据的形式交错排列。

在处理函数中,使用 ByteArray.writeFloat() 方法写入 sampleData 事件的 data 属性。例如,以下代码将生成正弦波:

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

当您调用 Sound.play() 时,该应用程序将开始调用事件处理函数,并请求声音样本数据。在播放声音时,应用程序将继续发送事件,直至您停止提供数据或调用 SoundChannel.stop()

事件的滞后时间对于不同的平台会有所变化,并且在将来版本的 AIR 中也将改变。请不要依赖某个特定的滞后时间;而应计算出相应的滞后时间。若要计算滞后时间,请使用以下公式:

(SampleDataEvent.position / 44.1) - SoundChannelObject.position

向 SampleDataEvent 对象的 data 属性提供 2048 到 8192 个样本(对于每次事件侦听器调用)。为了获得最佳性能,请尽可能多地提供样本(最多可达 8192 个样本)。提供的样本越少,在播放过程中就越有可能出现单击和弹出事件。此行为对于不同的平台会有所不同,并且会在各种情况下发生。例如,在调整浏览器的大小时。在仅提供了 2048 个样本时,工作在某一个平台上的代码可能在运行于其他不同平台时将不能很好地工作。若要尽可能缩短滞后时间,请考虑允许用户选择数据量。

如果提供的样本少于 2048 个(每次 sampleData 事件侦听器调用),则应用程序将在播放完剩余的样本后停止。随后,它将调度 SoundComplete 事件。