65.9K
CodeProject 正在变化。 阅读更多。
Home

我们在Microsoft Flight Simulator中如何使用Web Audio API创建动态声音

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2015 年 7 月 17 日

CPOL

8分钟阅读

viewsIcon

10443

本教程是《飞行街机》系列教程的第二篇——该系列旨在展示 Web 平台以及新版 Microsoft Edge 浏览器和 EdgeHTML 渲染引擎的可能性。

音频 vs. 音频

Web Audio API 出现之前,HTML5 为我们提供了 <audio> 元素。现在回想起来可能有些困难,但在 <audio> 元素出现之前,我们在浏览器中播放声音的最佳选择是使用插件!<audio> 元素确实令人兴奋,但它的功能非常单一。它本质上是一个没有视频的视频播放器,非常适合播放音乐或播客等长音频,但却不适合游戏的需求。我们不得不忍受(或找到变通方法)循环播放问题、并发声音限制、卡顿以及对声音数据本身的完全无法访问。

幸运的是,我们的耐心得到了回报。<audio> 元素可能存在的不足,Web Audio API 都能够弥补。它为我们提供了前所未有的声音控制能力,非常适合从游戏到复杂的音频编辑等各种用途。所有这些都通过一个简洁且非常有趣的 API 实现,并且得到了很好的支持。

更具体地说,Web Audio 可以让您访问声音的原始波形数据,并允许您对其进行操作、分析、失真或以其他方式进行修改。它对于音频来说,就像 Canvas API 对于像素一样。您可以深入且几乎不受限制地访问声音数据。这非常强大!

本教程是《飞行街机》系列教程的第二篇——该系列旨在展示 Web 平台以及新版 Microsoft Edge 浏览器和 EdgeHTML 渲染引擎的可能性。本文的交互式代码和示例也位于:http://www.flightarcade.com/learn/

飞行声音

即使是《飞行模拟》的 早期版本,也努力通过声音来重现飞行的感觉。最重要的声音之一是引擎的动态音高,它会随着油门的变化而改变音高。我们知道,当我们为 Web 重新构想这款游戏时,静态的引擎噪音会显得非常单调,因此引擎噪音的动态音高是 Web Audio 的一个显而易见的选择。

不太明显(但可能更有趣)的是我们的飞行教练的声音。在《飞行街机》的早期迭代中,我们播放的教练声音与录制时完全相同,听起来像是从录音棚里传出来的!我们注意到,我们开始将这个声音称为“旁白”,而不是“教练”。不知何故,这种完美的声音打破了游戏的沉浸感。让如此完美的声音伴随着嘈杂的驾驶舱噪音似乎不太对。因此,在这种情况下,我们使用 Web Audio 对教练语音进行了一些简单的失真处理,以增强学习飞行的真实感!

文章最后有一个教练音频的示例。在下面的部分中,我们将详细介绍我们如何使用 Web Audio API 来创建这些声音。

使用 API:AudioContext 和 Audio Sources

任何 Web Audio 项目的第一步都是创建一个 AudioContext 对象。一些浏览器(包括 Chrome)仍然需要此 API 的前缀,因此代码如下所示:

然后您需要声音。您实际上可以使用 Web Audio API 从头开始生成声音,但对我们来说,我们想加载一个预录制的音频源。如果您已经有了 HTML <audio> 元素,您可以使用它,但很多时候您不会。毕竟,如果您拥有 Web Audio,谁还需要 <audio> 元素呢?最常见的情况是,您只需通过 HTTP 请求直接将音频下载到缓冲区中。

现在我们有了一个 AudioContext 和一些音频数据。下一步是让这些东西协同工作。为此,我们需要...

AudioNodes

您使用 Web Audio 所做的几乎所有事情都通过某种 AudioNode 来完成,它们有多种不同的类型:有些节点用作音频源,有些用作音频输出,有些用作音频处理器或分析器。您可以将它们链接在一起以实现有趣的功能。

您可以将 AudioContext 视为一个声音舞台。它包含的各种乐器、放大器和扬声器都将是不同类型的 AudioNodes。使用 Web Audio API 就像将所有这些东西连接在一起(例如,将乐器连接到效果踏板,再将踏板连接到放大器,然后连接到扬声器等)。

嗯,为了对我们新获得的 AudioContext 音频源做些有趣的事情,我们需要首先将音频数据封装为一个源 AudioNode。

Playback

就是这样。我们有了一个源。但在播放它之前,我们需要将其连接到一个目标节点。为了方便起见,AudioContext 提供了一个默认的目标节点(通常是您的耳机或扬声器)。连接后,只需调用 start 和 stop 即可。

值得注意的是,您只能对每个源节点调用一次 start()。这意味着“暂停”不被直接支持。一旦源停止,它就失效了。幸运的是,源节点是廉价的对象,设计易于创建(记住,音频数据本身是单独的缓冲区)。因此,如果您想恢复暂停的声音,可以创建一个新的源节点,并使用时间戳参数调用 start()。AudioContext 具有一个内部时钟,您可以使用它来管理时间戳。

引擎声音

以上就是基础知识,但我们到目前为止所做的一切(简单的音频播放)都可以通过旧的 <audio> 元素实现。对于《飞行街机》,我们需要做一些更动态的事情。我们希望音高随着引擎速度而变化。

使用 Web Audio(没有它几乎不可能!)这实际上非常简单。源节点有一个 rate 属性,它会影响播放速度。要提高音高,只需提高播放速率。

引擎声音还需要循环播放。这也很容易(它也有一个属性)。

但有一个陷阱。许多音频格式(尤其是压缩音频)以固定大小的帧存储音频数据,而且大多数情况下,音频数据本身不会“填满”最后一个帧。这可能导致音频文件的末尾出现微小的间隙,并在循环播放这些音频文件时导致单击或卡顿。标准的 HTML 音频元素不提供对此类间隙的任何控制,这对于依赖循环音频的网络游戏来说可能是一个很大的挑战。

幸运的是,使用 Web Audio API 进行无缝音频播放非常简单。只需为循环播放部分的音频的开始和结束设置时间戳即可(请注意,这些值相对于音频源本身,而不是 AudioContext 时钟)。

教练的声音

到目前为止,我们所做的一切都使用了一个源节点(我们的音频文件)和一个输出节点(我们早期设置的声音目标,可能是您的扬声器),但 AudioNodes 可以用于更多用途,包括声音处理或分析。在《飞行街机》中,我们使用了两种节点类型(ConvolverNode 和 WaveShaperNode)来使教练的声音听起来像是通过扬声器播放的。

卷积

来自 W3C 规范

卷积是一个数学过程,可以应用于音频信号以实现许多有趣的高质量线性效果。通常,这种效果用于模拟声学空间,如音乐厅、大教堂或露天圆形剧场。它还可以用于复杂的滤波效果,例如来自壁橱内部的模糊声音、水下的声音、通过电话的声音,或者通过老式扬声器箱播放的声音。这种技术在主要电影和音乐制作中非常常用,并被认为具有极高的通用性和高质量。

卷积基本上结合了两种声音:要处理的声音(教练的声音)和一种称为脉冲响应的声音。脉冲响应确实是一种声音文件,但它仅对这种卷积过程有用。您可以将其视为一种音频滤波器,旨在与另一种声音卷积时产生特定效果。结果通常比音频的简单数学处理要真实得多。

要使用它,我们创建一个卷积节点,加载包含脉冲响应的音频,然后连接节点。

波形整形

为了增加失真,我们还使用了一个 WaveShaper 节点。这种节点允许您对音频信号应用数学失真,以实现一些非常戏剧性的效果。失真被定义为一条曲线函数。这些函数可能需要一些复杂的数学。对于下面的示例,我们借鉴了我们 MDN 的朋友们提供的一个好函数。

请注意原始波形与应用了 WaveShaper 后的波形之间的显著差异。

上面的示例戏剧性地展示了您可以使用 Web Audio API 做多少事情。我们不仅在浏览器中对声音进行了非常戏剧性的更改,而且还在分析波形并将其渲染到 Canvas 元素中!Web Audio API 功能强大且用途广泛,而且坦率地说,非常有趣!

更多关于 JavaScript 的实践

微软在许多开源 JavaScript 主题上有大量的免费学习资源,我们的使命是利用 Microsoft Edge 创建更多资源。以下是一些您可以查看的资源:

以及一些入门的免费工具:Visual Studio CodeAzure 试用版,以及 跨浏览器测试工具——所有这些都可在 Mac、Linux 或 Windows 上使用。

© . All rights reserved.