Chrome 49 中的网络音频更新

克里斯·威尔逊
Chris Wilson

Chrome 一直在努力地不断改进对 Web Audio API 的支持。在 Chrome 49(2016 年 2 月发布的 Beta 版,预计在 2016 年 3 月推出稳定版)中,我们更新了几项功能以跟踪规范,还新增了一个节点。

deckAudioData() 现在返回一个 promise

AudioContext 上的 decodeAudioData() 方法现在会返回 Promise,从而启用基于 Promise 的异步模式处理。decodeAudioData() 方法始终将成功和错误回调函数作为参数:

context.decodeAudioData( arraybufferData, onSuccess, onError);

但现在,您可以改为使用标准 promise 方法来处理解码音频数据的异步性质:

context.decodeAudioData( arraybufferData ).then(
        (buffer) => { /* store the buffer */ },
        (reason) => { console.log("decode failed! " + reason) });

虽然在单个示例中这看起来更为冗长,但 promise 可以使异步编程变得更简单且更一致。为实现兼容性,根据规范,成功和错误回调函数仍受支持。

离线音频上下文现在支持挂起()和恢复()

乍一看,在 OfflineAudioContext 上拥有挂起()似乎似乎很奇怪。毕竟,suspend() 已添加到 AudioContext 以支持将音频硬件置于待机模式,这在渲染到缓冲区的场景中似乎毫无意义(这当然是 OfflineAudioContext 的用途)。不过,此功能的要点是一次仅构建部分“得分”,以最大限度地减少内存用量。您可以在渲染期间创建更多节点。

例如,贝多芬的《月光奏响》包含大约 6,500 条音。每个“音符”可能至少解构为几个音频图节点(例如 AudioBuffer 和一个增益节点)。如果您想要使用 OfflineAudioContext 将整个七半分钟渲染到缓冲区中,您可能不想一次创建所有这些节点。而是可以分块创建:

var context = new OfflineAudioContext(2, length, sampleRate);
scheduleNextBlock();
context.startRendering().then( (buffer) => { /* store the buffer */ } );

function scheduleNextBlock() {
    // create any notes for the next blockSize number of seconds here
    // ...

    // make sure to tell the context to suspend again after this block;
    context.suspend(context.currentTime + blockSize).then( scheduleNextBlock );

    context.resume();
}

这样,您就可以尽可能减少在渲染开始时需要预先创建的节点数,并减少内存需求。

IIRFilterNode

该规范为想要自行创建确切指定的无限脉冲响应的发烧友添加了一个节点:IIRFilterNode。此过滤器是对 BiquadFilterNode 的补充,但允许完整指定过滤器响应参数(而不是针对类型、频率、Q 等而言,BiquadFilterNode 易于使用的 AudioParams)。IIRFilterNode 可以精确指定之前无法创建的过滤器,例如单阶过滤器;但是,使用 IIRFilterNode 需要对 IIR 过滤器的运作方式有一定的了解,并且不像 BiquadFilterNodes 一样可调度。

之前的更改

我还想提一下之前实施的几项改进:在 Chrome 48 中,BiquadFilter 节点自动化开始以音频速率运行。为了做到这一点,此 API 根本没有更改,但这意味着您的滤波器扫描听起来会更流畅。此外,在 Chrome 48 中,我们通过返回要连接的节点向 AudioNode.connect() 方法添加了链接。这样可以更轻松地创建节点链,如下示例所示:

sourceNode.connect(gainNode).connect(filterNode).connect(context.destination);

就先这样吧,继续摇滚吧!