# Web Audio API 是什么?
最近很迷恋Creative Coding
和 Generative Art
,可以让代码与艺术结合是我一直非常想要尝试去做的事情。这个领域在中国的资料比较稀少,最近在学习"MATT DESLAURIERS"一位Creative Coder
关于音频可视化领域的课程,在这个课程中了解到了Web Audio API,
,这是我之前在学习 JavaScript 时没有注意到的 API。
Web Audio API 是浏览器里面的一个用来处理和合成声音的 Javascript 接口。这个 API 是被设计用来编写游戏声音引擎,以及来完成我们在各种音乐制作软件中对声音的编辑和混缩。你可以在 Web Audio API 的[官方文档](Web Audio API)里获得详细的信息。
# 一、区分 Web Audio API 和 HTML5 Audio Tag
本文这里所说的Web Audio API
和HTML5 Audio Tag
元素并不是一个东西,其体量也完全不是一个等级的,两者的关系大概是下面这个样子的 👇

HTML5 的 audio 提供给开发人员一种对声音文件进行基本的读取,播放,暂停的功能, 同时还可以对声音文件的音量大小进行调整。但是 Web Audio API 是用于在浏览器里进行更为复杂的声音处理以及合成,其作用有:
- 对简单或复杂的声音进行混合;
- 精确控制声音的密度和节奏;
- 内置淡入/淡出,颗粒噪点,音调控制等效果;
- 灵活的处理在音频流的声道,使它们成为拆分和合并;
- 使用 MediaStream 的 getUserMedia()方法事实处理现场输入的音频,例如变声;
- 立体音效,可以支持多种 3D 游戏和沉浸式环境;
- 利用卷积引擎,创建各类线性音效,例如小/大房间、大教堂、音乐厅、洞穴、隧道、走廊、森林、圆形剧场等。尤其适用于创建高质量的房间效果。
- 高效的实时的时域和频分析,配合 CSS3 或 Canvas 或 webGL 可以实现音乐可视化支持;
- 以及其他多种音频波形算法控制,几乎就是把一个音频编辑类软件搬到 web 上。
# 二、音频上下文 AudioContext
# 👉 创建 AudioContext
要使用Web Audio API
, 第一步就是要创建一个AudioContext
。音频中的AudioContext
可以类比于canvas
中的canvas.getContext
。AudioContext
是一个声音的容器,其中包含了一系列用来处理音频的 API。
const audioContext = new AudioContext();
var AudioContext = window.AudioContext || window.webkitAudioContext; // 浏览器兼容方式
我们可以输出 audioContext 实例对象来看看包含什么 API


其 API 不仅来源于自身,也从其父接口 BaseAudioContext
继承方法和属性

上面的 API 又长又难记,但是对一个非专业音乐向的开发者来说只需了解一下即可。
# 👉 AuidoNode
在了解如何控制发出的声音前. 需要了解AudioNode
这个概念。
简单来说,所谓的音频处理其实就是标准的 IO 函数。从某个地方获取一个音频流(Input),经过实时计算处理后发送去某个地方(Destination),而这个处理也就是 Effect。

AudioContext
是用于管理和播放所有声音。使用 web audio api 来产生声音,创建一个或多个声音源,并将它们连接到由 AudioContext 示例提供的声音目的地。该连接不必直接连接,可以通过任意数量的中间 AudioNodes 来作为音频信号的处理模块。
例如吉他可以发出多种效果的声音,我们先把连着吉他的另一根线连在第一个效果器上,然后再把第一个效果器跟第二个效果器连起来,最后把第二个效果器跟音箱连起来。这样就通过串联来得到了两个声音效果。在 Web Audio API 中,我们也用同样的道理。每一个组件都是一个Audio Node,声音从第一个Audio Node流过第二个,第三个...直到最后一个Audio Node(通常是电脑的扬声器输出),以串联或者并联的方式来进行信号传输。
# 三、Web Audio API 如何控制声音
下面会通过两个小 demo 来演示 Web Audio API 是如何控制声音和音乐的播放
# 👉 Demo 1 控制声音

创建一个 AudioContext 实例,这是音频处理程序运行的环境
let audioCtx = new AudioContext();
创建一个振荡器,这是声音的源头
let oscillator = audioCtx.createOscillator();
创建一个增益节点(音量节点),用来调节音量的变化
let gainNode = audioCtx.createGain();
设置音量和振荡器参数
gainNode.gain.value = 0.5; // 音量 0~1
oscillator.type = "sine"; // 振荡器输出正弦波
oscillator.frequency.value = 200; // 振荡频率200Hz
各种连接,参照上面的流程图
oscillator.connect(gainNode); // 发生源振荡器连接音量
gainNode.connect(audioCtx.destination); //音量连接扬声器
开始发声
oscillator.start();
结束发声
oscillator.stop(audioCtx.currentTime + FADING_TIME); //现在起FADING_TIME秒后结束发声,没有FADING_TIME表示立刻结束
以上的 demo 中,整体大致都是这个流程:创建声源 → 中间处理程序 → 扬声器。当然如果不需要输出音效,就不需要连接到 audioCtx.destination 即可。
# 👉 Demo 2 控制音乐播放
下面通过一个小 demo 来看怎么使用 AudioContext 播放音乐。
const mp3 = "http://127.0.0.1:5500/public/tornado.mp3"; // mp3音源
const button = document.querySelector("button");
class Demo1 {
constructor() {
// 参数为balanced表示平衡音频输出延迟和资源消耗
this.audioContext = new AudioContext({ latencyHint: "balanced" });
}
// 获取音乐
async getMp3ArrayBuffer(url) {
return fetch(url).then((r) => r.arrayBuffer());
}
// 初始化音乐
async start() {
const musicArrayBuffer = await this.getMp3ArrayBuffer(mp3);
// audioContext.decodeAudioData 将音频的ArrayBuffer解码成AudioBuffer
const decodedAudioData = await this.decode(musicArrayBuffer);
this.play(decodedAudioData);
}
// 音频解码
async decode(arrayBuffer) {
return this.audioContext.decodeAudioData(arrayBuffer);
}
// 播放音乐
async play(decodedAudioData) {
const sourceNode = this.audioContext.createBufferSource();
sourceNode.buffer = decodedAudioData;
sourceNode.connect(this.audioContext.destination);
sourceNode.start(0);
}
}
button.onclick = () => new Demo1().start();
上面的代码看起来比较晦涩,其流程就是 :
- 通过 fetch 获取原始音频(ArrayBuffer)
- 通过
audioContext.decodeAudioData()
方法把音频数据转换成我们所需要的buffer
格式; - 使用
AudioBufferSourceNode
把解码后的数据挂载到音源上 - 通过
audioContext.destination
交由硬件播放
其中有三个关键点:
source
connect
destination
你可以试着以这种方式来理解这三个关键点:首先我们通过 audioContext.createBufferSource()
方法创建了一个「容器」 source
并装入接收进来的「水」 buffer
;其次通过「管道」 connect
把它和「出口」 destination
连接起来;最终「出口」 destination
「流」出来的就是我们所听到的音频了。不知道这么讲,大家有没有比较好理解。
# 文章总结
Web Audio API 的使用非常的灵活和广泛,我是刚接触这个方面。后期会讲述一下利用 Web Audio API 进行音频可视化和创意编程方面的内容。