简言
记录下Web Audio API接口的介绍。
Web Audio API 提供了在 Web 上控制音频的一个非常有效通用的系统,允许开发者来自选音频源,对音频添加特效,使音频可视化,添加空间效果(如平移),等等。
Web Audio API
Web Audio API 使用户可以在音频上下文(AudioContext)中进行音频操作。
基本音频操作通过音频节点执行,这些节点连接在一起形成音频路由图。即使在单个上下文中,也可支持多个具有不同类型通道布局的音源。这种模块化设计为创建具有动态效果的复杂音频功能提供了灵活性。这种模块化设计提供了灵活创建动态效果的复合音频的方法。
音频节点(audio node)通过它们的输入输出相互连接,形成一个链或者一个简单的网。一般来说,这个链或网起始于一个或多个音频源。
音频源可以提供一个片段一个片段的音频采样数据(以数组的方式),也可以是音频或视频的文件读出来的,又或者是音频流(MediaStreamAudioSourceNode)。
这些节点的输出可以连接到其他节点的输入上,然后新节点可以对接收到的采样数据再进行其他的处理,再形成一个结果流。
声音处理完成之后,可以连接到一个目的地(AudioContext.destination),这个目的地负责把声音数据传输给扬声器或者耳机。注意,只有当用户期望听到声音时,才需要进行最后一个这个连接。
web audio流程如下:
- 使用 AudioContext 创建音频上下文。
- 在音频上下文里创建音频源,音频源可以是上面说的那三种情况。
- 对音频进行处理(当然也可以不处理),处理需要创建效果节点,例如混响、双二阶滤波器、平移、压缩等。
- 为音频选择一个目的地,例如你的系统扬声器
- 连接源到效果器,对目的地进行效果输出。
Web Audio API 接口
Web Audio API 共有一系列接口和相关的事件。
- AudioContext — AudioContext 接口代表由音频模块构成的音频处理图。音频上下文控制其所包含节点的创建和音频处理、解码。使用其他接口前你必需创建一个音频上下文,一切操作都在这个环境里进行。
- AudioNode — 音频节点 接口是一个音频处理模块,包含了音频源节点、音频输出、音量控制节点等。
- AudioParam — AudioParam 接口代表音频相关的参数,比如一个 AudioNode的参数。它可以设置为特定值或值的变化,并且可以在指定的时间之后以指定模式变更。
- ended结束事件 — 当媒体播放停止时,会触发ended事件。
- OscillatorNode — OscillatorNode 接口代表一种随时间变化的波形,比如正弦波形或三角波形。类型是AudioNode,功能是音频处理模块,可以产生指定频率的波形。
- AudioBuffer — AudioBuffer 代表内存中的一段音频数据,可以通过AudioContext.decodeAudioData()方法从音频文件创建,也可以通过AudioContext.createBuffer()方法从原始数据创建。当音频数据被解码成这种格式之后,就可以被放入一个AudioBufferSourceNode中使用。
- AudioBufferSourceNode — AudioBufferSourceNode 表示由内存音频数据组成的音频源,音频数据存储在AudioBuffer中。这是一个作为音频源的AudioNode。
- MediaElementAudioSourceNode — MediaElementAudioSourceNode 接口表示由 HTML5 <audio>或<video>元素生成的音频源。这是一个作为音频源的AudioNode。
- MediaStreamAudioSourceNode — MediaStreamAudioSourceNode 接口表示由 WebRTC MediaStream(如网络摄像头或麦克风)生成的音频源。这是一个作为音频源的AudioNode。
- BiquadFilterNode — BiquadFilterNode 接口表示一个简单的低阶滤波器。它是一个AudioNode,可以表示不同种类的滤波器、调音器或图形均衡器。BiquadFilterNode 总是只有一个输入和一个输出。
- ConvolverNode — ConvolverNode 接口是一个AudioNode,对给定的 AudioBuffer 执行线性卷积,通常用于实现混响效果。
- DelayNode — DelayNode 接口表示延迟线;是AudioNode 类型的音频处理模块,使输入的数据延时输出。
- DynamicsCompressorNode — DynamicsCompressorNode 提供了一个压缩效果,当多个音频在同时播放并且混合的时候,可以通过它降低音量最大的部分的音量来帮助避免发生削波和失真。
- GainNode — GainNode 接口用于音量变化。它是一个 AudioNode 类型的音频处理模块,输入后应用增益 效果,然后输出。
- StereoPannerNode — StereoPannerNode 接口表示一个简单立体声控制节点,用来左右移动音频流(左右声道处理)。
- WaveShaperNode — WaveShaperNode 接口表示一个非线性的扭曲。它是AudioNode类型,可以利用曲线来对信号进行扭曲。除了一些效果明显的扭曲,还常被用来给声音添加温暖的感觉(暖调处理)。
- PeriodicWave — 用来定义周期性的波形,可被用来重塑 OscillatorNode的输出。
- AudioDestinationNode — AudioDestinationNode 定义了最后音频要输出到哪里,通常是输出到你的扬声器。
- MediaStreamAudioDestinationNode — MediaStreamAudioDestinationNode 定义了使用 WebRTC 的MediaStream(只包含单个 AudioMediaStreamTrack)应该连接的目的地,AudioMediaStreamTrack 的使用方式和从getUserMedia()中得到MediaStream相似。这个接口是AudioNode类型的音频目的地。
- AnalyserNode — AnalyserNode 表示一个可以提供实时频率分析与时域分析的切点,这些分析数据可以用做数据分析和可视化。如果你想从音频里提取时间、频率或者其他数据,你需要 AnalyserNode
- ChannelSplitterNode — ChannelSplitterNode 可以把输入流的每个声道输出到一个独立的输出流(通道分离)。
- ChannelMergerNode — ChannelMergerNode 用于把一组输入流合成到一个输出流。输出流的每一个声道对应一个输入流(通道合并)。
- AudioListener — 代表场景中正在听声音的人的位置和朝向。
- PannerNode — PannerNode 用于表示场景是声音的空间行为。它是AudioNode类型的音频处理模块,这个节点用于表示右手笛卡尔坐标系里声源的位置信息,运动信息(通过一个速度向量表示),方向信息(通过一个方向圆锥表示)。
- ScriptProcessorNode — ScriptProcessorNode 接口用于通过 JavaScript 代码生成,处理,分析音频。它是一个AudioNode类型的音频处理模块,但是它与两个缓冲区相连接,一个缓冲区里包含当前的输入数据,另一个缓冲区里包含着输出数据。每当新的音频数据被放入输入缓冲区,就会产生一个AudioProcessingEvent 事件,当这个事件处理结束时,输出缓冲区里应该写好了新数据。
- audioprocess事件 — 当一个 Web Audio API ScriptProcessorNode已经准备好进行处理时,这个事件回调会被调用。
- AudioProcessingEvent 事件 — 当ScriptProcessorNode的输入流数据准备好了时,AudioProcessingEvent事件会产生。
- OfflineAudioContext — OfflineAudioContext 离线音频上下文也是音频上下文AudioContext,也表示把AudioNode连接到一起的一个音频处理图。但是,与一个标准的音频上下文相比,离线上下文不能把音频渲染到扬声器,仅仅是把音频渲染到一个缓冲区。
- complete — Complete 事件,当离线音频上下文被终止时产生。
- OfflineAudioCompletionEvent 事件 — OfflineAudioCompletionEvent表示上下文被终止时的事件。
示例
音频可视化:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>可视化</title><style>#canvas,#canvas2 {border: 1px solid #000;}</style>
</head>
<h1>声音可视化</h1>
<div><audio controls autoplay loop crossorigin="anonymous"><source src="./2789078374.mp3" type="audio/mpeg">Your browser does not support the audio element.</audio><h2>可视化图形</h2><canvas id="canvas"></canvas><canvas id="canvas2"></canvas><button id="btn">生成</button>
</div><body><script>const canvasDom = document.getElementById("canvas");const canvasW = 1000const canvasH = 256canvasDom.width = canvasW;canvasDom.height = canvasH;const canvasCtx = canvasDom.getContext("2d");const canvasDom2 = document.getElementById("canvas2");canvasDom2.width = canvasW;canvasDom2.height = canvasH;const canvasCtx2 = canvasDom2.getContext("2d");const btn = document.getElementById("btn");let audioCtx = nulllet analyserlet sourcebtn.addEventListener("click", () => {if (audioCtx == null) {audioCtx = new (window.AudioContext || window.webkitAudioContext)()// 创建 AnalyserNode节点 analyser = audioCtx.createAnalyser()const distortion = audioCtx.createWaveShaper()// 连接声源 source = audioCtx.createMediaElementSource(document.querySelector('audio'))source.connect(analyser)analyser.connect(audioCtx.destination);}analyser.fftSize = 2048let bufferLength = analyser.frequencyBinCountconst dataArray = new Uint8Array(bufferLength)analyser.getByteTimeDomainData(dataArray)//要捕获数据,你需要使用 AnalyserNode.getFloatFrequencyData() 或 AnalyserNode.getByteFrequencyData() 方法来获取频率数据,// 用 AnalyserNode.getByteTimeDomainData() 或 AnalyserNode.getFloatTimeDomainData() (en-US) 来获取波形数据。let drawVisual;canvasCtx.clearRect(0, 0, canvasW, canvasH);// 波形图function draw() {analyser.getByteTimeDomainData(dataArray)canvasCtx.fillStyle = "rgb(200, 200, 200)";canvasCtx.fillRect(0, 0, canvasW, canvasH);var sliceWidth = (canvasW * 1.0) / bufferLength;canvasCtx.lineWidth = 2;canvasCtx.strokeStyle = "rgb(0, 0, 0)";canvasCtx.beginPath();canvasCtx.moveTo(0, canvasH / 2);canvasCtx.lineTo(canvasW, canvasH / 2);canvasCtx.stroke()canvasCtx.beginPath();let x = 0for (let i = 0; i < bufferLength; i++) {let v = dataArray[i] / 128.0;let y = (v * canvasH) / 2;if (i === 0) {canvasCtx.moveTo(x, y);} else {canvasCtx.lineTo(x, y);}x += sliceWidth;canvasCtx.stroke();}drawVisual = requestAnimationFrame(draw);}draw()// 柱形图function drawBar() {analyser.getByteTimeDomainData(dataArray)canvasCtx2.fillStyle = "rgb(0,0,0)";canvasCtx2.fillRect(0, 0, canvasW, canvasH);let barWidth = canvasW / bufferLength * 2.5;let x = 0for (let i = 0; i < bufferLength; i++) {let barHeight = dataArray[i] / 128.0 / 2 * canvasH;canvasCtx2.fillStyle = 'rgb(' + (barHeight + 100) + ',50,50)';canvasCtx2.fillRect(x, canvasH - barHeight, barWidth, barHeight);x += barWidth + 1;}requestAnimationFrame(drawBar);}drawBar()})</script>
</body></html>
使用 file://打开的话会报cors,使用http服务打开。
结语
结束了。