1. 首页

Web Audio API简介

Web Audio API让我们在浏览器中制造一些还不错的声音。这使你的站点,应用,游戏变得更加有趣吸引人。你还可以制造一些像鼓机或者合成器这样特别的音乐应用。在本文中,我们将学习通过Web Audio API做一些简单有趣的项目。

入门

让我们了解一些专业术语。在Web Audio API中,所有的音频操作都是在一个audio上下文中。每个基础的声音操作通过使用链接在一起的音频节点所展现的,从而形成音频路由图。在播放任何声音之前,你需要创建这个音频的上下文。这非常类似于创建canvas元素内部绘制的上下文。下面是我们如何创建一个音频上下文的方法:


var context = new (window.AudioContext || window.webkitAudioContext)();

Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文文档
一个帮助开发者成长的社区,你想要的,在这里都能找到

Safari需要一个webkit前缀支持AudioContext,所以你应该使用上面这行代替new AudioContext();

通常,Web Audio API的工作流程如下所示:

创建源->连接过滤器节点->连接目标

下面有三种类型的来源:

  1. 振荡器 – 数字计算声音

  2. 音频样本 – 从音频/视频文件中获取

  3. 音频流 – 从网络摄像头或者麦克风中的音频

从振荡器开始介绍

一个振荡器是重复的波形。它具有频率,峰值振幅。除了它的频率和振幅以外,振荡器最重要的特色之一是它的波形。四种最常见的振子波是正弦波,三角波,方波,锯齿波。

Web Audio API简介

也可以自定义波形。不同的形状适用于不同的合成技术。他们提供不同的从光滑到刺耳的声音。

Web Audio API用 OscillatorNode来代表重复的波形。我们可以使用上述展示的波形。为此,我们分配value属性值如下:


OscillatorNode.type = 'sine'|'square'|'triangle'|'sawtooth';

你也可以创建一个自定义的波形。你可以使用setPeriodicWave()方法来创建一个波形。可以自动的设置一个定制类型。我们来听听不同的波形产生的不同的声音:

看看这个CodePen例子

通常的波形运用傅里叶变换自定义波形。如果你想要学习更多自定义的波形(比如,怎样制作警笛)。你可以学习这个优秀的资源中学习。

运行振荡器

Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文文档
一个帮助开发者成长的社区,你想要的,在这里都能找到

我们来一起试试制造一些噪音。这是我们所需要做的:

  1. 我们需要创建一个Web Audio API上下文

  2. 在上下文中创建一个振荡器节点

  3. 选择波形类型

  4. 设置频率

  5. 将振荡器链连接目标

  6. 启动振荡器

让我们转化这些步骤转化为代码吧。


var context = new (window.AudioContext || window.webkitAudioContext)(); var oscillator = context.createOscillator(); oscillator.type = 'sine'; oscillator.frequency.value = 440; oscillator.connect(context.destination); oscillator.start();

记录我们如何定义一个音频上下文。Safari浏览器需要webkit前缀。所以我们得让它跨浏览器兼容。

然后我们创建一个振荡器并设置一个波形。默认值是正弦型,所以你可以跳过这一行,我只是想添加它使其更加清晰,更加容易更新。我们可以将频率值设置440HZ,即A4音符(也是默认值)。这些音符从C0到B8的频率都是在16.35到7902.13HZ的范围之间。在这篇文章中,我们将看一个播放一些不同的音符的例子

现在,当我们知道所有这些之后,我们也可以调节音量。为此,我们需要在上下文中创建一个gain节点,将其连在链中,还有连接gain节点连接到目标。


var gain = context.createGain(); oscillator.connect(gain); gain.connect(context.destination); var now = context.currentTime; gain.gain.setValueAtTime(1, now); gain.gain.exponentialRampToValueAtTime(0.001, now + 0.5); oscillator.start(now); oscillator.stop(now + 0.5);

现在你对使用振荡器有一些了解,这是一个很好的练习。这个Codepen链接有振荡器的设置代码。尝试来做一个简单的应用程序,在屏幕上下移动光标来改变音量,左右移动来改变频率。

Web Audio API的计时

创建一个音频软件很重要的事情之一是管理时间。对于这里需要的精度,使用一个JavaScript时钟不是最佳的实践。因为它不够精确。然而,Web Audio API附带了一个currentTime属性,这是需要不断增加的双硬件时间戳,可用于调度音频播放。当音频上下文建立之后,它是从0开始的。尝试运行一下console.log(context.currentTime)查看时间戳。

例如,如果你想要立马播放振荡器,应该立马运行oscillator.start(0)(你可以省略0,因为0是默认值)。然而,你可能想让它从现在开始一秒钟,播放两秒钟,然后停止。下面是如何实现的:


var now = context.currentTime; oscillator.play(now + 1); oscillator.stop(now + 3);

这里有两种方法在这提及的。

AudioParam.setValueAtTime(value, startTime)方法在精确时间计划更改变化的值。例如,你想要在一秒之内改变振荡器的频率值:


oscillator.frequency.setValueAtTime(261.6, context.currentTime + 1);

但是,如果想要立刻改变值,也可以使用.setValueAtTime(value, context.currentTime)。你可以通过修改值的属性设置AudioParam。但是,如果它们与自动化事件(使用AudioParam方法的事件)同时发生,则任何的值被忽略而不抛出异常。

AudioParam.exponentialRampToValueAtTime(value, endTime) 方法用来持续的值的变化。这段代码将在一秒钟之内以指数形式减少振荡器的音量。这是一个平稳停止声音的好办法。


gain.gain.exponentialRampToValueAtTime(0.001, context.currentTime + 1);

我们不能使用0作为值,因为需要一个正值,所以我们可以用一个很小的值进行代替。

创建一个Sound类

一旦停止一个振荡器,就无法重新启动它。你没有做错任何事情,这是Web Audio API优化性能的功能。我们可以做的是创建一个声音类来,负责创建一个振荡器节点,播放和停止声音。这个方法我们可以多次调用声音。这里将使用ES6的语法:


class Sound { constructor(context) { this.context = context; } init() { this.oscillator = this.context.createOscillator(); this.gainNode = this.context.createGain(); this.oscillator.connect(this.gainNode); this.gainNode.connect(this.context.destination); this.oscillator.type = 'sine'; } play(value, time) { this.init(); this.oscillator.frequency.value = value; this.gainNode.gain.setValueAtTime(1, this.context.currentTime); this.oscillator.start(time); this.stop(time); } stop(time) { this.gainNode.gain.exponentialRampToValueAtTime(0.001, time + 1); this.oscillator.stop(time + 1); } }

Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文文档
一个帮助开发者成长的社区,你想要的,在这里都能找到

我们将上下文传递给构造函数,因此我们可以在用一个上下文中,创建该Sound类的所有实例。然后有一个init方法,可以创建振荡器和所有必要的滤波器节点,连接它们,等等。play方法接受值(将要播放的音符的频率)还有播放时间。但首先,它创建了一个振荡器,每当我们调用该play方法就会发生这种情况。stop方法在一秒内指数减少了音量,直到它完全停止振荡器 。因此,每当我们需要再次播放这个声音时,我们需要再次创建一个新的Sound类并调用play方法。现在我们来播放一些音符:


let context = new (window.AudioContext || window.webkitAudioContext)(); let note = new Sound(context); let now = context.currentTime; note.play(261.63, now); note.play(293.66, now + 0.5); note.play(329.63, now + 1); note.play(349.23, now + 1.5); note.play(392.00, now + 2); note.play(440.00, now + 2.5); note.play(493.88, now + 3); note.play(523.25, now + 3.5);

将在相同的上下文中播放C D E F G A B C。如果你想要知道这些音符的频率,你可以在这里找到它们。

了解所有这些,使我们能够建立木琴一样的东西!创建了一个新的Sound实例并播放。你可以查看例子并尝试自己制作一个练习。

看看由Greg Hovanesyan(@gregh)创建的例子木琴,在CodePen上

我已经创建了一个小广场,包含所有需要的HTML和CSS,以及创建的Sound类。使用该data-frequency属性获取声音值。 试试这个

使用录制的声音

现在,你已经用振荡器构建了一些东西,让我们来看看如何处理一个录制的声音。使用振荡器很难再现一些声音。在很多情况下,为了使用真实的声音必须要使用一些录音。可以是.mp3,.ogg,.wav格式等等。有关详细信息,请完整的表格 提供的更多的信息。我喜欢使用.mp3格式,因为轻巧,广泛的支持,还有非常好的音质。

你不能通过图像一样通过URL获取声音。我们必须运行一个XMLHttpRequest 来获取文件,解码数据,并且存入缓冲区。

Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文文档
一个帮助开发者成长的社区,你想要的,在这里都能找到


class Buffer { constructor(context, urls) { this.context = context; this.urls = urls; this.buffer = []; } loadSound(url, index) { let request = new XMLHttpRequest(); request.open('get', url, true); request.responseType = 'arraybuffer'; let thisBuffer = this; request.onload = function() { thisBuffer.context.decodeAudioData(request.response, function(buffer) { thisBuffer.buffer[index] = buffer; updateProgress(thisBuffer.urls.length); if(index == thisBuffer.urls.length-1) { thisBuffer.loaded(); } }); }; request.send(); }; loadAll() { this.urls.forEach((url, index) => { this.loadSound(url, index); }) } loaded() { // what happens when all the files are loaded } getSoundByIndex(index) { return this.buffer[index]; } }

让我们来看看构造函数。我们在Sound类中接收上下文。接收到将要加载到的URLa列表,以及缓冲区的空数组。

我们有两种方法:loadSound和loadAll。loadAll循环遍历URL列表并且调用loadSound方法,传递索引也非常重要。无论首先加载是哪个请求,这样我们通过缓冲的声音放入数组的正确元素之中。这也让我们来看看最后一个加载的请求是哪个,这意味着完成缓冲区时会加载。

然后你可以调用loaded() 方法,这样可以做一些隐藏加载指示器的事情。最后,getSoundByIndex(index)方法通过索引从缓冲区得到声音进行回放。

decodeAudioData方法有一个较新的基于Promise的语法,但是它在Safari中不起作用:


context.decodeAudioData(audioData).then(function(decodedData) { // use the decoded data here });

然后我们必须为声音创建一个类。现在我们有完整的声音类处理用于录音中:


class Sound() { constructor(context, buffer) { this.context = context; this.buffer = buffer; } init() { this.gainNode = this.context.createGain(); this.source = this.context.createBufferSource(); this.source.buffer = this.buffer; this.source.connect(this.gainNode); this.gainNode.connect(this.context.destination); } play() { this.setup(); this.source.start(this.context.currentTime); } stop() { this.gainNode.gain.exponentialRampToValueAtTime(0.001, this.context.currentTime + 0.5); this.source.stop(this.context.currentTime + 0.5); } }

构造函数接收上下文和缓冲区。我们通过调用createBufferSource()方法创建,而不是像之前用过的createOscillator 。缓冲区通过getSoundByIndex()方法获得音符(缓冲区数组的元素)。现在我们不是使用振荡器创建一个缓冲源,而是设置缓冲区,然后连接目标(或者gain节点还有其它滤波器)。


let buffer = new Buffer(context, sounds); buffer.loadAll(); sound = new Sound(context, buffer.getSoundByIndex(id)); sound.play();

现在,我们必须创建一个缓冲区实例并调用loadAll方法,加载所有声音到缓冲区中去。我们还有getSoundById方法来获取需要的声音得方法,因此我们将声音给Sound类和调用play()方法。该id可以存储在你可以播放声音的按钮属性中。

这有一个使用缓冲区,录音,音符等的项目:

看看这个Pen The Bluesman – 你可以演奏蓝调 (Web Audio API) 是Greg Hovanesyan (@gregh)在 CodePen上制作的。

你可以使用这个例子作为参考,但是除了你自己的练习,这里还有一个我创建的小广场。这里有所有必要的HTML,CSS,还有一些我在真实的电吉上录的音符的URL链接。试试编写自己的代码吧!

介绍过滤器

Web Audio API允许你添加不同的筛选器节点在声源和目标之间。BiquadFilterNode是一个简单的低阶滤波器,可以控制频率这一部分,哪部分需要加强还是减弱。这让你建立一个均衡器应用和其他效果。这里有八种的双二阶滤波器:高通,低通,带通,低架,高架,高峰,缺口和全通。

高通是一个也可以传递更高频率的过滤器,但是会衰减信号的低频分量。低通通过较低频率,但衰减较高频率。它们也被称为“低切”和“高切”滤波器,因为它解释了信号发生了什么。

高架低架 是用于控制声音的低音和高音的滤波器,它们用于强调或减少高于或低于给定频率的信号。

你将找到Q属性的BiquadFilterNode接口,这代表 Q Factor的双重接口。品质因数或Q Factor控制带宽,影响频率高低。Q Factor越低,带宽越宽,意味着影响的频率越多。Q Factor越高,带宽越窄。

你可以找到更多的滤波器的信息,这里。但我们已经可以构建参数均衡器。它是一个均衡器,可以完全控制频率,带宽和gain节点。

让我们创建一个参数均衡器。

看看这个pen例子

我们来看看怎样运用在声音的失真上。如果你想要的制作一个听起来像电吉他的声音,这就是失真效应。我们使用 WaveShaperNode 接口来代表一个非线性失真器。我们需要做的是创建一条曲线来代表信号,扭曲并产生特定的声音。我们不必花一些时间创建曲线,我们已经做好了。我们也可以调整失真量:

看看这个CodePen例子

后记

现在你已经了解如何建立Web Audio API,我建议你试试它制作一些自己的项目吧!

这里有一些处理Web音频的库:

  • Pizzicato.js – Pizzicato旨在通过Web Audio API简化您创建和操作声音的方式

  • webaudiox.js – webaudiox.js是一个助手,将让你轻松的使用WebAudio API

  • howler.js – 现代网络的Javascript音频库

  • WAD – 使用HTML5的Web Audio API进行动态合成声音。这很像为了你耳朵的jQuery

  • Tone.js – 用于在浏览器中制作交互式音乐的Web Audio框架

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文来源于网络,其版权属原作者所有,如有侵权,请与小编联系,谢谢!

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:Web Audio API简介

链接:https://www.javascriptc.com/2021.html

原文链接:https://www.zcfy.cc/article/introduction-to-web-audio-api

« [译] 冲冠一怒为代码:论程序员与负能量
如何在项目中创建一个ESLint插件?»
Flutter 中文教程资源

相关推荐

QR code