探索 Web Audio API:构建强大的网页音频应用
1. Web Audio API 简介
Web Audio API 是用于创建网页音频应用的行业标准工具,它为网页上的音频控制提供了强大而通用的系统。借助该 API,开发者能够生成声音、选择音频源、添加音效、创建可视化效果以及在沉浸式环境中渲染音频场景。对于专注于音频处理和网页编程的人员来说,Web Audio API 正变得越来越重要,逐渐成为不可或缺的工具。
虽然已有一些关于 Web Audio API 的小型指南和正式规范,但缺乏一本面向广大学生、研究人员和开发者的详细书籍。而且,很多现有指南都已过时,例如,不少指南仍提及已被弃用的 ScriptProcessorNode ,却未涉及能极大扩展 Web Audio API 功能的 AudioWorkletNode 。
2. 书籍内容概述
本书提供了使用 Web Audio API 的权威且具指导性的内容,涵盖了所有基本特性,并为各个方面提供了易于实现的代码示例。同时,书中解释了背后的理论,帮助读者理解设计选择和核心音频处理概念,还涉及了高级概念,使读者能够掌握构建在浏览器中运行的复杂音频应用的技能。
2.1 书籍结构
书籍的结构如下,分为七个部分,中间由六个简短的插叙部分隔开,大多数部分包含多个章节。这种组织方式使得书籍可以按顺序阅读,除极少数情况外,Web Audio API 的功能都会在各自的章节中详细介绍和解释,然后才会在其他章节的代码示例中使用。
- 第一部分 :单章内容,概述 Web Audio API 的存在原因、功能和结构。包含 “Hello World” 应用的源代码,这是使用 Web Audio API 实现基本功能的最简单程序,并在此基础上展示了更多核心特性。
- 第二部分 :关于如何使用预定源生成声音,每个预定源都有单独的章节,包括振荡器、音频缓冲区源和常量源节点。
- 第三部分 :聚焦于音频参数,包含两章,分别介绍参数的调度和设置,以及音频参数的连接和调制。
- 第四部分 :涉及源节点和目标节点,除了预定源和默认目标外,还包括音频流的分析和可视化、音频的加载和录制以及离线音频处理等章节。
- 第五部分 :专注于音频效果,包括延迟、滤波、波形整形、动态范围压缩和混响等章节。除滤波章节涉及两个相关节点( BiquadFilterNode 和 IIRFilterNode )外,每个章节都介绍了效果的背景和相关音频节点的详细信息。
- 第六部分 :处理空间音频,包含三章。第一章介绍 Web Audio API 中多声道音频的处理方式,并引入用于分割多声道音频流和合并多个音频流为多声道音频流的音频节点。另外两章分别讨论立体声平移和空间渲染。
- 第七部分 :充分发挥 Web Audio API 的强大功能,通过音频工作线程实现。第一章详细解释音频工作线程,并通过源代码示例介绍其所有特性。最后一章回顾了前面章节的许多源代码示例,展示了如何使用音频工作线程实现替代(在某些方面更好)的实现方式。
2.2 代码示例
书中提供了丰富的代码示例,涵盖了从简单的 “Hello World” 应用到复杂的音频处理和效果实现。以下是部分代码示例:
// Hello World Application, generating sound
// 示例代码 1:简单声音生成
// 这里可以使用 Web Audio API 创建音频上下文并播放声音
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime); // 440 Hz
gainNode.gain.setValueAtTime(0.5, audioContext.currentTime);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 2); // 播放 2 秒
// Oscillator.html and Oscillator.js
// 示例代码 2:振荡器使用
// 创建一个振荡器节点并设置其属性
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'square'; // 方波
oscillator.frequency.setValueAtTime(220, audioContext.currentTime);
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
oscillator.start(audioContext.currentTime);
2.3 资源
- 所有代码示例可在 https://github.com/joshreiss/Working-with-the-Web-Audio-API 获取。
- 相关的 YouTube 视频可在 https://tinyurl.com/y3mtauav 找到。
- 广泛使用的 Web Audio API 文档: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
- Web Audio API 规范: www.w3.org/TR/webaudio/
2.4 图表说明
书中包含了许多图表,用于帮助理解 Web Audio API 的各种概念和操作。以下是部分图表的简要说明:
| 图表编号 | 图表名称 | 说明 |
| ---- | ---- | ---- |
| 1.1 | 最简单的音频上下文 | 展示了一个基本的音频上下文结构 |
| 1.2 | 复杂的音频路由图 | 对噪声应用包络、滤波器组、失真和混响的音频路由图 |
| 2.1 | 两个采样正弦波 | 频率分别为 3 Hz 和 7 Hz 的采样正弦波,在 10 Hz 采样频率下看起来相同 |
2.5 编码约定
书中使用了以下约定:
- 斜体 :常用于表示新术语。
- 等宽字体 :用于源代码和 JavaScript 或 HTML 术语。根据上下文,有时也使用纯文本表示编程方面的一般概念。
- 数学符号 :括号通常用于表示离散整数样本的函数,如 x[n] ;括号用于表示连续时间的函数,如 x(t) 。方程通常不编号。
- 术语和约定 :大多使用 Web Audio API 文档中的术语和约定,音频信号被称为音频流,所有操作都在音频图中进行。将 Web Audio 处理的 128 个样本帧块简称为处理 128 个样本。
- 代码规范 :代码示例通常可以直接运行,无需依赖外部库或依赖项。采用简单的编码准则,减少每个源代码示例中的文本量,例如,除非必要,否则不使用分号;简单的循环和函数通常以单行形式呈现;不使用 getElementByID() 方法,而是依赖元素 ID 作为全局变量;除非需要,否则不使用 EventListeners 。
以下是一个简单的代码示例,展示了编码约定的使用:
// 简单的音量控制示例
Volume.oninput = () => VolumeNode.gain.value = Volume.value;
2.6 音频生成流程
mermaid 流程图展示使用预定源生成声音的基本流程:
graph LR
A[创建音频上下文] --> B[选择预定源]
B --> C{振荡器}
B --> D{音频缓冲区源}
B --> E{常量源节点}
C --> F[设置参数]
D --> F
E --> F
F --> G[连接到目标节点]
G --> H[播放声音]
综上所述,Web Audio API 为开发者提供了丰富的功能和可能性,通过本书的学习,开发者可以系统地掌握其使用方法,构建出各种复杂而有趣的网页音频应用。无论是音频处理的初学者还是有经验的开发者,都能从书中获得有价值的知识和技能。
3. 音频参数操作
3.1 调度和设置参数
音频参数的调度和设置是控制音频效果的重要手段。可以通过特定的方法来安排参数的变化,实现音频的动态控制。例如,可以使用 setValueAtTime 、 linearRampToValueAtTime 等方法来设置参数在不同时间点的值。
// 示例代码 3:参数调度和设置
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
// 调度增益参数的变化
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(0.5, audioContext.currentTime + 2);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
3.2 连接音频参数和调制
音频参数之间可以相互连接,实现调制效果。例如,将一个低频振荡器(LFO)连接到另一个振荡器的频率参数上,就可以实现频率调制(FM)效果。
// 示例代码 4:频率调制(FM)
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const carrier = audioContext.createOscillator();
const modulator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
modulator.connect(carrier.frequency);
carrier.connect(gainNode);
gainNode.connect(audioContext.destination);
carrier.type = 'sine';
carrier.frequency.setValueAtTime(440, audioContext.currentTime);
modulator.type = 'sine';
modulator.frequency.setValueAtTime(5, audioContext.currentTime);
modulator.start(audioContext.currentTime);
carrier.start(audioContext.currentTime);
modulator.stop(audioContext.currentTime + 5);
carrier.stop(audioContext.currentTime + 5);
3.3 音频参数操作流程
mermaid 流程图展示音频参数操作的基本流程:
graph LR
A[创建音频上下文] --> B[创建音频节点]
B --> C[设置初始参数]
C --> D[调度参数变化]
D --> E[连接参数进行调制]
E --> F[播放音频]
4. 音频效果实现
4.1 延迟效果
延迟效果是音频处理中常见的效果之一,可以通过 DelayNode 来实现。延迟效果可以模拟回声等效果。
// 示例代码 5:延迟效果
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const delayNode = audioContext.createDelay();
const gainNode = audioContext.createGain();
oscillator.connect(delayNode);
delayNode.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
delayNode.delayTime.setValueAtTime(0.5, audioContext.currentTime);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
4.2 滤波效果
滤波效果可以通过 BiquadFilterNode 或 IIRFilterNode 来实现。滤波效果可以去除不需要的频率成分,或者增强特定频率的声音。
// 示例代码 6:低通滤波效果
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const filterNode = audioContext.createBiquadFilter();
const gainNode = audioContext.createGain();
oscillator.connect(filterNode);
filterNode.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
filterNode.type = 'lowpass';
filterNode.frequency.setValueAtTime(200, audioContext.currentTime);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
4.3 波形整形效果
波形整形效果可以通过 WaveShaperNode 来实现。波形整形可以改变音频信号的波形,实现失真等效果。
// 示例代码 7:波形整形效果
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const waveShaperNode = audioContext.createWaveShaper();
const gainNode = audioContext.createGain();
oscillator.connect(waveShaperNode);
waveShaperNode.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
// 定义波形整形曲线
function makeDistortionCurve(amount) {
let n_samples = 44100;
let curve = new Float32Array(n_samples);
let deg = Math.PI / 180;
for (let i = 0; i < n_samples; ++i) {
let x = i * 2 / n_samples - 1;
curve[i] = (3 + amount) * x * 20 * deg / (Math.PI + amount * Math.abs(x));
}
return curve;
}
waveShaperNode.curve = makeDistortionCurve(40);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
4.4 动态范围压缩效果
动态范围压缩效果可以通过 DynamicsCompressorNode 来实现。动态范围压缩可以减少音频信号的动态范围,使声音更加平稳。
// 示例代码 8:动态范围压缩效果
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const compressorNode = audioContext.createDynamicsCompressor();
const gainNode = audioContext.createGain();
oscillator.connect(compressorNode);
compressorNode.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
compressorNode.threshold.setValueAtTime(-50, audioContext.currentTime);
compressorNode.knee.setValueAtTime(40, audioContext.currentTime);
compressorNode.ratio.setValueAtTime(12, audioContext.currentTime);
compressorNode.attack.setValueAtTime(0, audioContext.currentTime);
compressorNode.release.setValueAtTime(0.25, audioContext.currentTime);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
4.5 混响效果
混响效果可以通过 ConvolverNode 来实现。混响效果可以模拟不同的声学环境,使声音更加逼真。
// 示例代码 9:混响效果
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const convolverNode = audioContext.createConvolver();
const gainNode = audioContext.createGain();
oscillator.connect(convolverNode);
convolverNode.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
// 加载冲激响应文件
fetch('reverb_ir.wav')
.then(response => response.arrayBuffer())
.then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
.then(audioBuffer => {
convolverNode.buffer = audioBuffer;
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
});
4.6 音频效果实现流程
| 效果类型 | 实现节点 | 关键参数 |
|---|---|---|
| 延迟 | DelayNode | delayTime |
| 滤波 | BiquadFilterNode 、 IIRFilterNode | type 、 frequency 等 |
| 波形整形 | WaveShaperNode | curve |
| 动态范围压缩 | DynamicsCompressorNode | threshold 、 knee 等 |
| 混响 | ConvolverNode | buffer |
mermaid 流程图展示音频效果实现的基本流程:
graph LR
A[创建音频上下文] --> B[创建音频源]
B --> C[选择音频效果节点]
C --> D{延迟}
C --> E{滤波}
C --> F{波形整形}
C --> G{动态范围压缩}
C --> H{混响}
D --> I[设置参数]
E --> I
F --> I
G --> I
H --> I
I --> J[连接到目标节点]
J --> K[播放音频]
4. 空间音频处理
4.1 多声道音频处理
在 Web Audio API 中,可以使用 ChannelSplitterNode 和 ChannelMergerNode 来处理多声道音频。 ChannelSplitterNode 可以将多声道音频流分割成多个单声道流, ChannelMergerNode 可以将多个单声道流合并成多声道音频流。
// 示例代码 10:多声道音频处理
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const splitter = audioContext.createChannelSplitter(2);
const merger = audioContext.createChannelMerger(2);
const gainNode = audioContext.createGain();
oscillator.connect(splitter);
splitter.connect(merger, 0, 0);
splitter.connect(merger, 0, 1);
merger.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
4.2 立体声平移
立体声平移可以通过 StereoPannerNode 来实现。通过调整 pan 参数,可以控制声音在左右声道之间的位置。
// 示例代码 11:立体声平移
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const panner = audioContext.createStereoPanner();
const gainNode = audioContext.createGain();
oscillator.connect(panner);
panner.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
panner.pan.setValueAtTime(0.5, audioContext.currentTime);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
4.3 空间渲染
空间渲染可以通过 PannerNode 来实现。 PannerNode 可以模拟声音在三维空间中的位置和方向,实现更加逼真的音频效果。
// 示例代码 12:空间渲染
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const panner = audioContext.createPanner();
const gainNode = audioContext.createGain();
oscillator.connect(panner);
panner.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioContext.currentTime);
panner.panningModel = 'HRTF';
panner.positionX.setValueAtTime(1, audioContext.currentTime);
panner.positionY.setValueAtTime(0, audioContext.currentTime);
panner.positionZ.setValueAtTime(0, audioContext.currentTime);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 5);
4.4 空间音频处理流程
| 处理类型 | 实现节点 | 关键参数 |
|---|---|---|
| 多声道音频处理 | ChannelSplitterNode 、 ChannelMergerNode | 声道数 |
| 立体声平移 | StereoPannerNode | pan |
| 空间渲染 | PannerNode | panningModel 、 positionX 等 |
mermaid 流程图展示空间音频处理的基本流程:
graph LR
A[创建音频上下文] --> B[创建音频源]
B --> C[选择空间音频处理节点]
C --> D{多声道音频处理}
C --> E{立体声平移}
C --> F{空间渲染}
D --> G[设置参数]
E --> G
F --> G
G --> H[连接到目标节点]
H --> I[播放音频]
Web Audio API 提供了丰富的功能和工具,通过对音频参数的操作、音频效果的实现以及空间音频的处理,开发者可以构建出各种复杂而逼真的网页音频应用。无论是简单的声音播放还是复杂的音频交互系统,Web Audio API 都能满足需求。

694

被折叠的 条评论
为什么被折叠?



