HTML5 在做游戏方面越来越完善,虽然在性能上还是不尽如人意但做一些简单的游戏仍然是能满足大部分需求的。画面和音效作为游戏的重要元素两者缺一不可,HTML5的canvas作为画面的渲染等都已经很成熟了,在音效方面也有Web Audio API 作为支持。
这一篇文章主要简单介绍一下Web Audio API的应用。
初识HTML5音频
<audio>
应该是最为简单而且为人熟知的标签,一般用于在文档中表示音频内容,可以很简单的指定一个音频源。通常使用场景都是作为背景音乐、歌曲等播放。
虽然都是能达到播放音频的效果,但在作为游戏音效中有一个致命的问题就是频繁在停止和播放过程中切换会导致卡顿甚至播放没有声音等现象。对于一些打击音效来说使用<audio>
会导致画面和音效不同步时有发生。
AudioContext 是作为音频播放的基础。不同于 <Audio>
,其功能完全由 JavaScript 控制,在事件上的控制相比<Audio>
更完善因为它实现了EventTarget的接口,在音频源上可以利用AudioBuffer进行多音频编辑或者捕捉处理等,甚至能对音频进行混响、双二阶滤波器、平移、压缩处理。
使用 Web Audio API
Web Audio API最大的优点在于通过音频节点的输入输出相连,通常开始播放都是从一个或多个源。事实上,声音文件只是自身声音声频的记录,这些节点的输出可以链接到其他节点的输入,将这些声音流经过混合或修改后形成其他的流,常见的修改就是将样本乘以一个值,使其声音更加响亮或安静。
开始之前,先了解一下工作模式
- 创建音频上下文
- 在上下文中,创建音频源 —— 例如:
<audio>
、OscillatorNode、流 - 创建效果节点 —— 例如:混响、滤波器、平移、压缩
- 为音频选择一个终端,例如你的系统扬声器。
- 连接源到效果器,以及效果器到终端。
创建 AudioContext
AudioContext
是用于管理和播放所有声音。为了使Web Audio API有声音,创建一个或者多个音源并把他们连接到由 AudioContext
提供的终端,而且该连接不需要直接连接的,可以经过任何数量的 AudioNodes
充当音频信号的处理器。
一个 AudioContext
的实例可以支持多个音频输入和复杂的音频图形,所以很多时候我们只需创建一个实例即可。而且 AudioContext
的方法使 Web Audio API 变得十分有趣。
1 | // 初始化创建音频上下文 |
加载音频
Web Audio API 使用 AudioBuffer
作为短、中长度的音频源。而且都是通过 XMLHttpRequest
进行异步加载这些音频文件的。
Web Audio API 支持多种格式的加载,例如:WAV、MP3、ACC、OGG等。可以通过 MDN 提供的表格查看详情。
1 | var dogBarkingBuffer = null; |
由于音频文件的数据是二进制(非文本),所以要设置请求头的responseType
为arraybuffer
。
当异步加载完文件后需要利用 AudioContext.decodeAudioData()
进行解码,如果是原始数据(raw data)则使用 AudioContext.createBuffer()
,一旦放入 AudioBuffer
就可以通过传递放入到 AudioBufferSourceNode
进行播放。
当decodeAudioData
完成后,它会执行回调并且传递一个参数是一个已经解码了的AudioBuffer
音频数据。
播放音频
一旦一个或者多个 AudioBuffer
被加载完成,然后我们就可以准备播放这些音频了。接下来我们就能通过以下的代码来播放刚才加载的音频。
1 | function playSound(buffer) { |
在任何时间当用户按下键盘或者鼠标, playSound(buffer)
方法都是可以调用的。
而 start(time)
可以很方便地为游戏或者其他关键时间进行精确的声音播放。但首先要确保的是 AudioBuffer
已经预加载。(由于部分旧系统采用的是旧的API,所以播放需要使用noteOn(time)
,更多的API变更信息)
值得注意的是,在iOS上,用户进行第一次交互之前所有声音都是被设置为静音的。所以需要用户在屏幕上触摸一下才能正常工作。
播放时间处理
Web Audio API 允许开发人员可以精确地处理播放时间。下面我们设置一个简单的节奏音乐。
上面是一份4/4拍的谱子,其中每八分音符就播放一次踩钹,贝司和小鼓轮流播放。
假如我们已经缓冲了贝司、小鼓、踩钹的数据:
1 | for (var bar = 0; bar < 2; bar++) { |
在上面的例子里,我们在playSound
方法中是指定了时间进行播放的。
改变音量
在最基本的操作之一就是控制音量的大小,在Web Audio API中,我们可以利用 GainNode
作为处理器,然后再输出到终端。
1 | // 创建一个增益处理器 |
然后可以通过修改 gainNode.gain.value
的值来处理声音的大小。
1 | gainNode.gain.value = 0.5; // 0 静音 1 最大 |
音乐淡出淡入
音乐的淡出淡入现在基本上是一个播放器基本的功能而且在游戏中场景的切换也会伴随着背景音乐的改变,在 Web Audio API 的帮助下我们也能很轻易的实现歌曲的淡入淡出功能。
我们还是使用GainNode
去做到这一点。
1 | CrossfadePlaylistSample.play = function() { |
更多的处理器
Web Audio API 提供了众多的处理器,在本文简单的为大家介绍一下:
AnalyserNode
分析器,可以通过该处理器绘出波形图之类的视图效果。
BiquadFilterNode
滤波器,可以通过该处理器对音乐进行降噪、去人声等处理。
ChannelMergerNode
、ChannelSplitterNode
信道合并\分离处理器,对多个信道进行合并或分离,一般用于对某个信道的音源进行增益处理。
ConvolverNode
混响,主播们都需要。
DynamicsCompressorNode
削峰处理,一般对音源最响亮的部分进行压缩处理。多用于音乐或游戏多个音频同时播放,以帮助防止在多个声音一起播放和多路复用时可能发生的削波和失真。
DelayNode
延迟输出。
OscillatorNode
一个恒定的音调,在游戏中一般用来做一些持续性的响声如:愤怒小鸟中里面小鸟飞出去时候的“啊”!
PannerNode
空间处理器,可以使音频在多声道中从左到右,从右到左或者在其中一边播放。CS 的脚本声要用到。
不一一介绍的 MediaElementAudioSourceNode
、MediaStreamAudioDestinationNode
、[``]