本文翻译自MDN上的《Web Audio APIの利用》,这是HTML5中的Web Audio API的一个入门教程。原文是英文,但有日本同志翻译的日文版。我更熟悉日文,因此主要根据日文版翻译成简体中文,也会对照英文版的。node
Web Audio API提供给你一个简单却强大的机制,你能够利用它去实现与操做web应用内的音频内容。经过它,在网页中你也能够进行混音、音效、平移等各类复杂的音频处理功能的开发。这篇文章主要想经过两个简单的例子来讲明Web Audio API的基础使用方法。git
Web Audio API并非替代<audio> 标签的东西,换句话说Web Audio API实际上是对<audio> 标签功能上的补充。两者的关系能够类比<img>标签与<canvas> 标签。具体改选用哪一个取决于你的目的是什么。若是只是为了简单地控制音频的播放的话,<audio>标签更适合吧。可是若是有更复杂的音频处理需求的话,就必须使用Web Audio API。github
Web Audio API的一个强大之处是它没有严格的[发出声音的数目的限制]。例如,一秒内能够同时发出32个声音或64个声音,但这并非上限。CPU的处理能力足够的话,1000多种声音也能够不通过压缩直接播放。若是这样发展下去的话,几年以后的中高端声卡的负荷会大大下降的吧。web
PS:补充点背景知识,这里提到的32,64指的是复音数。复音数指MIDI乐曲在一秒钟内发出的最大声音数目。关于复音数和MIDI乐曲能够百度一下。声卡硬件会限制复音数,部分软件使用CPU实现声音播放的也会限制复音数。但理论上只要CPU处理能力够强复音数是不受限的。因此上段说起Web Audio Api是软件,但它没有复音数限制,因此说到只要CPU处理能力够强,将来或许可以下降对中高端声卡性能的需求chrome
为了展现Web Audio API的用法,咱们编写了一些例子,这些例子会不断地增长更新。请你们发扬开源
精神为项目添加用例或者提出更好的改善意见!canvas
PS:这些例子最好在最新版chrome中运行segmentfault
首先介绍一下 Voice-change-O-matic 。这是一个有变声及声音可视化功能的网页应用,且有一些变声效果与可视化效果可供选择。虽然这个应用还有许多能够改善的地方,但也不失为综合使用Web Audio API的许多功能的一个好例子。(能够在这里运行 Voice-change-O-matic)浏览器
PS:上面的这个例子我运行没效果啊,不知道怎么玩
*PS:感谢vino24补充的,该例子须要https,在chrome下可运行网络
为了理解Web Audio而编写的另外一个例子就是这个Violent Theremin。这是一个简单的应用,它容许你经过鼠标指针的移动来改变频率和音量。另外,鼠标移动过程还有迷幻光彩的视觉效果。(Violent Theremin的源码在这里)架构
备注:下面列举的大多数的代码片断都在Violent Theremin中有使用。
Web Audio API的架构设计使得它可以轻松实现模块路由,其中包括对上下文中的音频内容的操做。基本的音频编辑可使用audio node进行。但这些节点相互能够链接起来,能够构成一个节点图。多个音源或者不一样种类的频道最终均可以对应到一个上下文中。这样模块化的设计是为了提供足够灵活的特性以便开发能够动态改变效果的复杂的音频编辑功能。
audio node有入口和出口,多个节点构成相似链表同样的结构。从一个或者多个音源出发,通过一个或者多个处理节点,最终输出到输出节点(输出终端,通常是扬声器)。(若是有需求的话,也能够不指定输出节点。例如,想把音频数据用图表的形式展示的场合等。)web audio的一个简单的典型的流程类是下面这样子:
建立AudioContext对象
在AudioContext对象内设置音源,例如<audio>标签,震动发声器,音频流
建立effect node(效果节点)。例如reverb, biquad filter, panner, compressor(这些都是音频特效)
选择音频的最终输出节点。例如,你的电脑的扬声器
音频通过效果节点处理后,而后输出到下一个节点,这些节点链接起来
首先,为了构建audio节点图,咱们首先要建立建立AudioContext对象。最简单的方法就像这样:
var audioCtx = new AudioContext();
备注:虽然能够在一个document中建立多个AudioContext对象,但这恐怕没什么卵用。
可是,Webkit/Blink内核的浏览器不须要前缀,Firefox(desktop/mobile/OS)的浏览器可能须要前缀,因此为了兼容性考虑,最好写成这样:
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
经过建立的AudioContext对象的方法,咱们能够进行各类各样的操做。最初进行的就是,准备要播放的音源。下面列出的东西均可以做为音源:
使用震动发声器与JavaScript建立音源的状况:使用AudioContext.createOscillator这个方法建立OscillatorNode。以后就能够利用震动发声器作音源了。
使用原始的PCM数据的状况:若是是能够识别的特定的格式的话(mp3之类的),使用AudioContext的特定的decode方法,来得到PCM数据。详细状况能够看这些,AudioContext.createBuffer()、AudioContext.createBufferSource()、AudioContext.decodeAudioData() 。
使用<video>标签或者<audio>标签等HTML元素的状况:具体状况能够看这个,AudioContext.createMediaElementSource()
从WebRTC MediaStream(WebRTC媒体流)输入音频源的状况:可使用麦克风或者Web摄像头。具体状况看这个,AudioContext.createMediaStreamSource()
简单地把震动发声器做为音源,使用gain节点控制音量,这就构成我咱们接下来要说的例子:
oscillator = audioCtx.createOscillator(); var gainNode = audioCtx.createGain();
备注:若是要播放音乐文件(mp3之类的),通常要利用XHR载入文件数据,那以后建立BufferSource。在这个示例Voice-change-O-matic有代码。
备注:Scott Michaud封装了载入和解码音频的代码,开源了一个库,叫AudioSampleLoader。使用这个的话,XHR以及buffer的操做都会变得异常简单。
要想音源(输入)经过扬声器(输出)播放出来,就必需要把二者链接起来。将被链接的节点做为参数,调用原来节点的的connect方法就能够创建节点间的链接。大多数类型的节点对象都拥有这个方法。
关于标准的输出节点能够参考,AudioContext.destination。标准的输出节点一般是设备的扬声器。把oscillator链接到gainNode上,gainNode的输出链接到标准输出上,代码以下:
oscillator.connect(gainNode); gainNode.connect(audioCtx.destination);
但若是像Voice-change-O-matic同样,比较复杂的状况的话。须要像下面同样将多个节点链接起来,造成一张图。:
source = audioCtx.createMediaStreamSource(stream); source.connect(analyser); analyser.connect(distortion); distortion.connect(biquadFilter); biquadFilter.connect(convolver); convolver.connect(gainNode); gainNode.connect(audioCtx.destination);
上面的代码建立出的audio图以下:
多个节点能够同时链接同一个节点。也可让多个音源经过一个效果节点,达到混音的效果。
备注:Firefox 32 以上版本,在Firefox开发工具中Web Audio编辑器了。有了它以后大大提升了对audio节点图进行debug的效率。
建立完audio节点图后,就能够经过设定audio节点的属性值或者调用方法来调整节点的效果。下面的例子,咱们来设定下震动发声器的音调,使用Hz这个单位,以下:
oscillator.type = 0; // sine wave,正弦波 oscillator.frequency.value = 2500; // value in hertz oscillator.start();
在Violent Theremin这个程序中,设定了音量与周波数的最大值,以下:
var WIDTH = window.innerWidth; var HEIGHT = window.innerHeight; var maxFreq = 6000; var maxVol = 1; var initialFreq = 3000; var initialVol = 0.5; // set options for the oscillator oscillator.type = 0; // sine wave oscillator.frequency.value = initialFreq; // value in hertz oscillator.start(); gainNode.gain.value = initialVol;
加下来是随着鼠标的移动,按照设定改变周波数。鼠标指针的X坐标和Y坐标以及周波数和音量的最大值,这些决定了最终输出声音的周波数和音量。代码以下:
// Mouse pointer coordinates var CurX; var CurY; // Get new mouse pointer coordinates when mouse is moved // then set new gain and putch values document.onmousemove = updatePage; function updatePage(e) { CurX = (window.Event) ? e.pageX : event.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft); CurY = (window.Event) ? e.pageY : event.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop); oscillator.frequency.value = (CurX/WIDTH) * maxFreq; gainNode.gain.value = (CurY/HEIGHT) * maxVol; canvasDraw(); }
canvasDraw()是一个每次鼠标移动都会调用的方法。每次调用这个方法,都会在鼠标指针位置所在的地方,把输出音频的周波数和音量用不一样大小和不一样颜色表现(画)出来。
function random(number1,number2) { var randomNo = number1 + (Math.floor(Math.random() * (number2 - number1)) + 1); return randomNo; } var canvas = document.querySelector('.canvas'); canvas.width = WIDTH; canvas.height = HEIGHT; var canvasCtx = canvas.getContext('2d'); function canvasDraw() { rX = CurX; rY = CurY; rC = Math.floor((gainNode.gain.value/maxVol)*30); canvasCtx.globalAlpha = 0.2; for(i=1;i<=15;i=i+2) { canvasCtx.beginPath(); canvasCtx.fillStyle = 'rgb(' + 100+(i*10) + ',' + Math.floor((gainNode.gain.value/maxVol)*255) + ',' + Math.floor((oscillator.frequency.value/maxFreq)*255) + ')'; canvasCtx.arc(rX+random(0,50),rY+random(0,50),rC/2+i,(Math.PI/180)*0,(Math.PI/180)*360,false); canvasCtx.fill(); canvasCtx.closePath(); } }
按下静音按钮后,会执行下面的函数。经过把Gain节点与前面链接的节点切断,使得声音的输出消失。再按一次按钮,就会恢复节点之间的链接,使得声音恢复输出。
var mute = document.querySelector('.mute'); mute.onclick = function() { if(mute.id == "") { gainNode.disconnect(audioCtx.destination); mute.id = "activated"; mute.innerHTML = "Unmute"; } else { gainNode.connect(audioCtx.destination); mute.id = ""; mute.innerHTML = "Mute"; } }
在 Web Audio API中其余还有不少的种类的节点可使用。建立节点、节点与节点之间链接起来,造成节点图,以后经过属性和方法来改变声音。从这些点来看,因此节点的使用方式都差很少。
下面,咱们概要地看一下几个节点。各个节点的详细状况能够在Web_Audio_API中看。
经过AudioContext.createWaveShaper这个方法,能够建立WaveShaper节点。
var distortion = audioCtx.createWaveShaper();
要想让这个对象工做,必须给予与决定波形的函数。经过将这个函数应用于输入的波形,WaveShaper节点能够扭曲声音。对新手来讲,一开始写出这个函数是很困难的吧。经过在网络上搜索,选用合适的方案就行了。下面是一个发布在Stack Overflow上的例子:
function makeDistortionCurve(amount) { var k = typeof amount === 'number' ? amount : 50, n_samples = 44100, curve = new Float32Array(n_samples), deg = Math.PI / 180, i = 0, x; for ( ; i < n_samples; ++i ) { x = i * 2 / n_samples - 1; curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) ); } return curve; };
在Voice-Change-O-Metic这个例子中,建立了一个叫作distortion的WaveShaper节点,提供了必要的音频扭曲效果。代码以下:
source.connect(analyser); analyser.connect(distortion); distortion.connect(biquadFilter); ... distortion.curve = makeDistortionCurve(400);
双二阶过滤器的内部有多个配置项目。能够经过AudioContext.createBiquadFilter这个方法建立。
var biquadFilter = audioCtx.createBiquadFilter();
在Voice-Change-o-Metic这个例子中,使用的是典型的lowshelf 过滤器。这是为了提供一个基本的低音増幅效果:
biquadFilter.type = "lowshelf"; biquadFilter.frequency.value = 1000; biquadFilter.gain.value = 25;
在这个例子中能够设定过滤器的种类,周波数,甚至gain的值。若是是lowshelf过滤器的话,能够提供一个比指定周波数低25dB的低音増幅。
使用Web Audio API的话,能够作到音频的可视化与立体化(例如音频平移等)。关于这些,咱们在其余的文档中说明。
终于完了。
翻译技术文章远比想象的要困难,特别是遇到不少陌生的某个领域下的专有词汇。
日语真是神奇,不少硬是用片假名套英文的状况,呵呵呵,让我想起了,特律风。
文中难免有错的地方,但愿你们能指出来,帮助文章更好,谢谢。
感谢,@说说说说