-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathweb-audio.html
More file actions
527 lines (423 loc) · 16.4 KB
/
Copy pathweb-audio.html
File metadata and controls
527 lines (423 loc) · 16.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Web Audio 基础与实例</title>
<meta name="description" content="A framework for easily creating beautiful presentations using HTML">
<meta name="author" content="Hakim El Hattab">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/black.css" id="theme">
<link rel="stylesheet" href="css/default.css">
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="lib/css/zenburn.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match(/print-pdf/gi) ? 'css/print/pdf.css' : 'css/print/paper.css';
document.getElementsByTagName('head')[0].appendChild(link);
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
<style>
kbd {
display: inline-block;
color: rgb(175, 175, 255);
}
</style>
</head>
<body>
<div class="reveal">
<div class="slides">
<section class="center">
<h2>Web Audio 基础与实例</h2>
<p class="sub">介绍 Web Audio 一个强大的音频处理系统</p>
<p>
<small><a href="https://codeigniter.org.cn" target="_blank">Hex</a> 为您分享 / Github: <a href="https://github.com/hex-ci" target="_blank">@hex-ci</a></small>
</p>
</section>
<section>
<h3>目录</h3>
<br>
<ul>
<li>Web Audio 是什么</li>
<li>音频上下文</li>
<li>音频源</li>
<li>音频处理</li>
<li>兼容性</li>
</ul>
</section>
<section>
<h3>Web Audio 是什么</h3>
<br>
<p>
Web Audio 是一套在 Web 上处理音频的 API
</p>
<div class="fragment">
<p>
使用这套 API 可以实现很多功能<br>
比如:音乐可视化、音色合成器、动态混音、声音特效、<br>
3D空间音频、均衡器、环境混响等
</p>
</div>
<div class="fragment">
<p>
可以应用在音乐播放器、电子音乐软件、游戏音效、音乐游戏、直播互动等领域
</p>
</div>
</section>
<section>
<h3>音频上下文 AudioContext</h3>
<br>
<p>
AudioContext 为音频处理提供一个上下文环境<br>
他也是一个中央控制器<br>
控制着<kbd>音频路由图</kbd>中的各个音频模块
</p>
<br>
<div class="fragment">
<p>
处理音频都需要创建一个 AudioContext 实例,可全局共享<br>
<kbd>音频节点</kbd>需要包含在 AudioContext 中<br>
每个<kbd>音频节点</kbd>只能关联一个 AudioContext
</p>
</div>
</section>
<section>
<h4>音频节点 AudioNode</h4>
<br>
<p>
音频节点是<kbd>音频路由图</kbd>中的基本单位<br>
音频节点通过它们的输入输出相互连接<br>
形成一个链或者一个简单的网
</p>
<br>
<div class="fragment">
<p>
音频节点可以分为三类:<br>
<kbd>Source Node</kbd>:能产生音频的节点,只有输出,没有输入<br>
<kbd>Process Node</kbd>:对音频进行处理的节点,有输入和输出<br>
<kbd>Destination Node</kbd>:通常为音频播放设备,如扬声器
</p>
</div>
</section>
<section>
<h4>音频路由图</h4>
<p>
许多音频节点相互连接,构建了一个路由图,就是所谓的音频路由图
</p>
<div>
<img style="max-height: 70vh" data-src="images/web-audio/1.jpg" alt="">
</div>
</section>
<section>
<h4>音频路由图</h4>
<p>
一个简单的音频播放示例:
</p>
<pre><code class="hljs js" data-trim>
const ac = new AudioContext()
const $audio = document.querySelector('#audio');
const sourceNode = ac.createMediaElementSource($audio); // 从 audio 标签创建一个音频源节点
const gainNode = ac.createGain(); // 创建一个增益节点
gainNode.gain.value = 0; // 将增益设置为 0(相当于音量设置为 0)
$audio.addEventListener('play', () => {
gainNode.gain.exponentialRampToValueAtTime(1, 1); // 在 1 秒的时间内指数增长到 1,实现一个播放渐入效果
});
sourceNode.connect(gainNode); // 音频源节点连接到增益节点
gainNode.connect(ac.destination); // 增益节点连接到 destination 进行播放
</code></pre>
</section>
<section>
<h3>音频源</h3>
<p>
Web 中的音频源包括:
</p>
<ul>
<li>
audio DOM 节点
</li>
<li>
网络加载的音频文件
</li>
<li>
实时音频流(WebRTC、麦克风等)
</li>
<li>
能产生音频信号的音频节点(如:OscillatorNode)
</li>
</ul>
</section>
<section>
<h4>从 <audio> 标签创建音频源</h4>
<p>
网络加载的音频文件,需要将其转换成音频源节点,才能连接到路由图中<br>
比如我们经常使用的 <audio> 标签,它是不能直接连接到其它音频节点的<br>
需要这样:
</p>
<pre><code class="hljs js" data-trim>
const ac = new AudioContext();
const $audio = document.querySelector('#audio');
// 从 <audio> 创建一个音频源节点
const sourceNode = ac.createMediaElementSource($audio);
sourceNode.connect(/* 其它音频节点 */);
</code></pre>
</section>
<section>
<h4>使用 HTTP 请求加载音频数据</h4>
<p>
使用 HTTP 请求,将二进制的音频数据下载到本地后<br>
再创建一个音频源节点,例如这样:
</p>
<pre><code class="hljs js" data-trim>
const ac = new AudioContext();
const source = ac.createBufferSource();
source.connect(ac.destination);
fetch('xxx.mp3')
.then(res => res.arrayBuffer())
.then(async buffer => {
// 将解码后的数据(AudioBuffer)加载到了 source.buffer 属性中
source.buffer = await ac.decodeAudioData(buffer);
source.start();
});
</code></pre>
</section>
<section>
<h4>制造白噪声</h4>
<p>
除了从网络/本地加载音频文件外,<br>
我们还可以自己创建一个 buffer 丢给 source.buffer 来制造一些声音<br>
比如下面的这个示例,使用随机函数生成一个白噪声音频:
</p>
<iframe width="80%" height="400" src="https://codepen.io/_hex_/full/zYPgZPR" title="example"></iframe>
</section>
<section>
<h4>使用内置振荡器产生声音</h4>
<p>
OscillatorNode 是一个振荡器节点,它可以产生一个周期信号
</p>
<p>
他有四种基本类型:
</p>
<ul>
<li>
方波 square
</li>
<li>
正弦波 sine
</li>
<li>
锯齿波 sawtooth
</li>
<li>
三角波 triangle
</li>
</ul>
<p>
例子:
</p>
<pre><code class="hljs js" data-trim>
const ac = new AudioContext();
const oscillator = ac.createOscillator();
// type 可能的值为 square, sine, sawtooth, triangle 默认为 sine
oscillator.type = 'square';
oscillator.frequency.value = 440; // 不能直接给 frequency 赋值,可以设置其 value
oscillator.connect(ac.destination);
oscillator.start();
</code></pre>
</section>
<section>
<h4>使用内置振荡器产生声音</h4>
<p>演示:</p>
<iframe width="80%" height="500" src="https://codepen.io/_hex_/full/WNXVjrE" title="example"></iframe>
</section>
<section>
<h4>音频流</h4>
<p>
使用音频流来创建一个音频源节点<br>
常见的音频流由麦克风、WebRTC 产生<br>
</p>
<div class="fragment">
<p>
通过 ac.createMediaStreamSource() 方法<br>
从音频流创建一个音频源节点
</p>
<p>
下面是一个简单的录音可视化效果:
</p>
<a href="https://codepen.io/_hex_/full/OJOKgBr" target="_blank">查看示例</a>
</div>
</section>
<section>
<h3>音频处理</h3>
<br>
<p>介绍几个常用的音频分析处理相关的 API:</p>
<ul>
<li>AnalyseNode</li>
<li>BiquadFilterNode</li>
<li>ConvolverNode</li>
</ul>
</section>
<section>
<h4>AnalyseNode</h4>
<p>
AnalyserNode 对音频信号进行实时的快速傅立叶变换(FFT)<br>
得到音频的时域/频域数据,用于实现时域分析、频域分析、音频可视化等
</p>
<p>
用法与示例:
</p>
<pre><code class="hljs js" data-trim>
const ac = new AudioContext();
// 创建一个 AnalyserNode
const analyser = ac.createAnalyser();
// fftSize 指定要进行 FFT 的采样数据的窗口大小,它的值必须是 2 的非零整数倍
analyser.fftSize = 2048;
// analyser.frequencyBinCount 是时域/频域数据的长度,它是 fftSize 的一半
// 因为实时音频信号的傅立叶变换具有对称性,只需要获取一半数据即可
const dataArray = new Uint8Array(analyser.frequencyBinCount);
// analyser.getByteTimeDomainData(dataArray) 方法将数据填充到 8 位无符号整型数组中
analyser.getByteTimeDomainData(dataArray);
</code></pre>
</section>
<section>
<h4>AnalyseNode</h4>
<p>
绘制一首音乐的波形:
</p>
<iframe width="80%" height="500" src="https://codepen.io/_hex_/full/NWwVrwP" title="example"></iframe>
</section>
<section>
<h4>AnalyseNode</h4>
<p>
简单的音乐播放动效:
</p>
<iframe width="80%" height="500" src="https://codepen.io/_hex_/full/GRObBpx" title="example"></iframe>
</section>
<section>
<h4>BiquadFilterNode</h4>
<p>
BiquadFilterNode 是一个双二阶数字滤波器<br>
滤波器的作用是对特定频率的输入信号进行增强/减弱<br>
通常用来控制音调、做均衡器
</p>
<p>
用法与示例:
</p>
<pre><code class="hljs js" data-trim>
const ac = new AudioContext();
// 创建一个双二阶滤波器
const filter = ac.createBiquadFilter();
// 他有 4 个关键的参数:type, frequency, Q, gain
filter.type = 'peaking'; // 设置类型为峰值滤波器
filter.Q.value = 1; // 峰值滤波器的带宽
filter.frequency.value = 1000; // 中心频率
filter.gain.value = 5; // 增益,单位 db
// ...
source.connect(filter);
filter.connect(ac);
</code></pre>
</section>
<section>
<h4>BiquadFilterNode</h4>
<p>
均衡器演示:
</p>
<iframe width="80%" height="600" src="https://res.cdn.changbaimg.com/!/web-audio-demo/1.4/index.html#/biquad-filter" title="example" style="background-color: #fff;"></iframe>
</section>
<section>
<h4>BiquadFilterNode</h4>
<p>
所有的滤波器类型及对应的参数说明:
</p>
<div>
<img style="max-height: 70vh" data-src="images/web-audio/2.png" alt="">
</div>
</section>
<section>
<h4>ConvolverNode</h4>
<p>
ConvolverNode 对音频信号进行线性卷积运算<br>
将特定的脉冲信号与音频进行卷积运算后<br>
会获得畸变效果,可以用来做环境混响效果
</p>
<p>
用法与示例:
</p>
<pre><code class="hljs js" data-trim>
const ac = new AudioContext();
// 解码加载好的冲激信号
const impulse = ac.decodeAudioData(arrayBuffer);
// 创建一个卷积器节点
const convolver = ac.createConvolver();
// buffer: AudioBuffer 类型,一个冲激信号(必须是 .wav 格式的文件)
convolver.buffer = impulse;
source.connect(convolver);
convolver.connect(ac.destination);
</code></pre>
</section>
<section>
<h4>ConvolverNode</h4>
<p>
混响效果演示:
</p>
<iframe width="80%" height="500" src="https://res.cdn.changbaimg.com/!/web-audio-demo/1.4/index.html#/convolver" title="example" style="background-color: #fff;"></iframe>
</section>
<section>
<h3>兼容性</h3>
<div>
<img style="max-height: 70vh" data-src="images/web-audio/3.png" alt="">
</div>
</section>
<section style="text-align: left;">
<h1>THE END</h1>
<p>谢谢!</p>
<p>
<br>
<br>
<br>
<br>
<br>
<br>
<small>
参考资料:
<ol>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API" target="_blank">MDN Web Audio API 文档</a></li>
<li><a href="https://www.feishu.cn/docs/doccndPOo08N5Dmc53KJxjhcEsh" target="_blank">Web Audio 简易教程</a></li>
</ol>
</small>
</p>
</section>
</div>
</div>
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: false,
width: '100%',
height: '100%',
// margin: 100,
transition: 'slide',
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/zoom-js/zoom.js', async: true },
{ src: 'plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>