Web Audio 基础与实例

介绍 Web Audio 一个强大的音频处理系统

Hex 为您分享 / Github: @hex-ci

目录


  • Web Audio 是什么
  • 音频上下文
  • 音频源
  • 音频处理
  • 兼容性

Web Audio 是什么


Web Audio 是一套在 Web 上处理音频的 API

使用这套 API 可以实现很多功能
比如:音乐可视化、音色合成器、动态混音、声音特效、
3D空间音频、均衡器、环境混响等

可以应用在音乐播放器、电子音乐软件、游戏音效、音乐游戏、直播互动等领域

音频上下文 AudioContext


AudioContext 为音频处理提供一个上下文环境
他也是一个中央控制器
控制着音频路由图中的各个音频模块


处理音频都需要创建一个 AudioContext 实例,可全局共享
音频节点需要包含在 AudioContext 中
每个音频节点只能关联一个 AudioContext

音频节点 AudioNode


音频节点是音频路由图中的基本单位
音频节点通过它们的输入输出相互连接
形成一个链或者一个简单的网


音频节点可以分为三类:
Source Node:能产生音频的节点,只有输出,没有输入
Process Node:对音频进行处理的节点,有输入和输出
Destination Node:通常为音频播放设备,如扬声器

音频路由图

许多音频节点相互连接,构建了一个路由图,就是所谓的音频路由图

音频路由图

一个简单的音频播放示例:


            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 进行播放
          

音频源

Web 中的音频源包括:

  • audio DOM 节点
  • 网络加载的音频文件
  • 实时音频流(WebRTC、麦克风等)
  • 能产生音频信号的音频节点(如:OscillatorNode)

从 <audio> 标签创建音频源

网络加载的音频文件,需要将其转换成音频源节点,才能连接到路由图中
比如我们经常使用的 <audio> 标签,它是不能直接连接到其它音频节点的
需要这样:


            const ac = new AudioContext();

            const $audio = document.querySelector('#audio');

            // 从 <audio> 创建一个音频源节点
            const sourceNode = ac.createMediaElementSource($audio);

            sourceNode.connect(/* 其它音频节点 */);
          

使用 HTTP 请求加载音频数据

使用 HTTP 请求,将二进制的音频数据下载到本地后
再创建一个音频源节点,例如这样:


            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();
              });
          

制造白噪声

除了从网络/本地加载音频文件外,
我们还可以自己创建一个 buffer 丢给 source.buffer 来制造一些声音
比如下面的这个示例,使用随机函数生成一个白噪声音频:

使用内置振荡器产生声音

OscillatorNode 是一个振荡器节点,它可以产生一个周期信号

他有四种基本类型:

  • 方波 square
  • 正弦波 sine
  • 锯齿波 sawtooth
  • 三角波 triangle

例子:


            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();
          

使用内置振荡器产生声音

演示:

音频流

使用音频流来创建一个音频源节点
常见的音频流由麦克风、WebRTC 产生

通过 ac.createMediaStreamSource() 方法
从音频流创建一个音频源节点

下面是一个简单的录音可视化效果:

查看示例

音频处理


介绍几个常用的音频分析处理相关的 API:

  • AnalyseNode
  • BiquadFilterNode
  • ConvolverNode

AnalyseNode

AnalyserNode 对音频信号进行实时的快速傅立叶变换(FFT)
得到音频的时域/频域数据,用于实现时域分析、频域分析、音频可视化等

用法与示例:


            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);
          

AnalyseNode

绘制一首音乐的波形:

AnalyseNode

简单的音乐播放动效:

BiquadFilterNode

BiquadFilterNode 是一个双二阶数字滤波器
滤波器的作用是对特定频率的输入信号进行增强/减弱
通常用来控制音调、做均衡器

用法与示例:


            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);
          

BiquadFilterNode

均衡器演示:

BiquadFilterNode

所有的滤波器类型及对应的参数说明:

ConvolverNode

ConvolverNode 对音频信号进行线性卷积运算
将特定的脉冲信号与音频进行卷积运算后
会获得畸变效果,可以用来做环境混响效果

用法与示例:


            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);
          

ConvolverNode

混响效果演示:

兼容性

THE END

谢谢!







参考资料:

  1. MDN Web Audio API 文档
  2. Web Audio 简易教程