在编写创意代码时,并没有严格意义上的对错。只要你考虑到了安全性、性能和可访问性,就可以采用适合自己的风格。在本文中,我们将分享一些最佳实践 —— 使用 Web Audio API 的指导原则和知识技巧。
加载音频 / 音频文件
使用 Web Audio API 加载声音主要有四种方式,但具体应该选用哪种,可能会让人有些困惑。
在处理文件时,你可以从 HTMLMediaElement
(即 <audio>
或 <video>
元素)中获取,也可以加载文件并将其解码到缓冲区。这两种处理方式都是可行的,不过,在处理完整的长音轨时,常用前者;而在处理较短、类似样本的音轨时,则更常用后者。
HTMLMediaElement
具有开箱即用的流媒体支持。当浏览器判定在播放结束前能够加载完文件的剩余部分时,音频就会开始播放。在 使用Web Audio API 教程中,你可以看到一个关于如何将其与 Web Audio API 配合使用的示例。
不过,如果使用缓冲节点,你将会拥有更多控制权。虽然你必须请求这个文件,然后等待它加载完成(这篇进阶文章 展示了一种很好的操作方法),但后续就能直接访问数据了,这意味着你可以实现更精确的操作。
如果你打算处理来自用户摄像头或麦克风的音频,可以通过 媒体捕捉与媒体流 API 以及媒体流音频源节点(MediaStreamAudioSourceNode
)接口来访问它。这对于网络实时通信(WebRTC
)以及你可能想要录制或者分析音频的情况很有帮助。
最后一种方式是生成你自己的声音,这可以通过使用振荡器节点(OscillatorNode
)或者创建一个缓冲区并填充数据来实现。如需了解有关使用振荡器和缓冲区创建声音的更多信息,请查看 创建你自己乐器的教程。
跨浏览器与历史版本支持
Web Audio API 规范在不断发展,和网络上的大多数事物一样,在跨浏览器一致性方面存在一些问题。在这里,我们将探讨解决跨浏览器问题的一些可选方案。
有一个名为 standardized-audio-context 的 npm
软件包,它能在各浏览器中稳定创建 API
功能,并在发现问题时填补漏洞。该软件包一直在不断开发中,并努力跟上当前的规范。
你也可以根据使用场景,选择使用一些库。作为一个功能全面的库,howler.js 是个不错的选择。它支持跨浏览器,并且提供了一组实用的功能子集。尽管它没有充分利用 Web Audio API 自带的全部过滤器和其他效果,但你可以实现大多数你想实现的功能。
如果你正在寻求声音创作或者更侧重于乐器方面的选择,那么 tone.js 是一个很棒的库。它提供了高级的调度功能、合成器以及各种效果,还有基于 Web Audio API 构建的直观的音乐抽象概念。
R-audio 出自英国广播公司的研发部,是一个 React
组件库,旨在为 “网络音频提供一个更直观的声明式接口”。如果你习惯编写 JSX
(JavaScript XML
,一种 JavaScript
的语法扩展),那它或许值得一看。
自动播放策略
浏览器已经开始实施自动播放策略,通常可以概括为:
从用户手势中创建或恢复上下文。
在实践中这意味着什么呢?用户手势指的是由用户发起的事件,通常是 click
事件。浏览器提供商一致决定,不应允许网络音频上下文自动播放音频,而应该由用户来启动播放。这是因为自动播放音频可能真的很烦人且具有侵扰性。我们该如何应对这种情况呢?
当你创建一个音频上下文(离线或在线均可)时,它创建出来时会带有一种状态,该状态可以是 suspended
(暂停态)、running
(运行态)或 closed
(关闭态)。
在使用 AudioContext
时,如果你在 click
事件中创建音频上下文,那么其状态应该会自动被设置为 running
。以下是一个在点击事件内部创建上下文的简单示例:
const button = document.querySelector("button");
button.addEventListener(
"click",
() => {
const audioCtx = new AudioContext();
// Do something with the audio context
},
false,
);
然而,如果在用户手势操作之外创建上下文,其状态将被设置为 suspended
,并且需要在用户交互之后才会启动它。我们在这里可以使用同样的点击事件示例,检测上下文的状态,如果它处于暂停态,就使用 resume()
方法来启动它。
const audioCtx = new AudioContext();
const button = document.querySelector("button");
button.addEventListener(
"click",
() => {
// check if context is in suspended state (autoplay policy)
if (audioCtx.state === "suspended") {
audioCtx.resume();
}
},
false,
);
当然,你可能使用的是离线音频上下文(OfflineAudioContext
),在这种情况下,你可以通过 startRendering()
方法恢复处于暂停状态的音频上下文。
用户控制
如果你的网站或应用程序包含声音,你应该允许用户对其进行控制,否则,它又会变得很烦人。这可以通过播放 / 停止以及音量 / 静音控制来实现。使用 Web Audio API 介绍了如何做到这一点。
如果你有用于开启和关闭音频的按钮,在这些按钮上使用 ARIA role="switch"
属性是个不错的选择,这样可以向辅助技术表明按钮的确切用途,从而使应用程序更具可访问性。这里有一个 如何使用它的示例。
在使用 Web Audio API 时,你会用到许多不断变化的值,并且希望让用户能够控制这些值,这时,<input type="range">
通常就是一个不错的选择,因为你可以使用 step
属性来设置最小值、最大值以及增量。
音频参数设值
有两种操作音频节点(AudioNode
)值的方法,这些音频节点本身是音频参数(AudioParam
)接口类型的对象。第一种方式是通过属性直接设置值。例如,如果我们想要更改增益节点(GainNode
)的增益值,如下所示:
gainNode.gain.value = 0.5;
这样会将音量设置为原来的一半。不过,如果你正在使用音频参数中任何已定义的方法来设置这些值,那么这些方法的优先级将会更高。例如,如果你想让增益值在两秒内提升到 1
,你可以这样做:
gainNode.gain.setValueAtTime(1, audioCtx.currentTime + 2);
它会覆盖上一个示例(理应如此),即便它在你的代码中出现的位置更靠后。
考虑到这一点,如果你的网站或应用程序需要进行定时和调度操作,那么最好使用 AudioParam
的相关方法来设置值。如果确定不需要进行这类操作,那么使用值属性来设置也是可以的。
评论0
暂时没有评论