本文由Mark Brown和Josh Wedekind进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!
Web Audio API允许开发人员使用JavaScript在浏览器中利用强大的音频处理技术,而无需插件。 除了实时定义和处理基于文件的音频源外,它还可以基于各种波形来合成声音。 这对于经常在低带宽网络上使用的Web应用程序很有用。
在本教程中,我将通过介绍一些更有用的方法向您介绍Web Audio API。 我将演示如何将其用于加载和播放mp3文件以及向用户界面( demo )添加通知声音。
如果您喜欢这篇文章,并且想更深入地探讨这个主题,那么我将为SitePoint Premium制作一个由5部分组成的截屏视频系列,名为“ 您还没听说过!”!
我可以使用Web Audio API做什么?
生产中API的用例多种多样,但最常见的包括:
- 实时音频处理,例如将混响添加到用户的语音中
- 产生游戏音效
- 向用户界面添加通知声音
在本文中,我们最终将编写一些代码来实现第三个用例。
浏览器是否支持良好?
Chrome,Edge,Firefox,Opera和Safari支持Web Audio。 就是说,在编写Safari时,Safari认为该浏览器功能是实验性的,并且需要webkit
前缀。
使用API
Web Audio API的入口点是一个称为AudioContext的全局构造函数。 实例化后,它提供了用于定义符合AudioNode接口的各种节点的方法。 这些可以分为三类:
- 源节点–例如MP3源,合成源
- 效果节点–例如平移
- 目标节点–由
AudioContext
实例公开为destination
; 这表示用户的默认输出设备,例如扬声器或耳机
可以使用connect方法将这些节点链接为多种组合。 这是使用Web Audio API构建音频图的一般想法。
资料来源: MDN
这是将MP3文件转换为AudioBufferSourceNode并通过AudioContext
实例的destination
节点播放它的示例:
请参阅CodePen上的SitePoint ( @SitePoint ) 使用Web Audio API播放MP3文件的笔。
产生音频
除了通过AudioBufferSourceNode
支持录制的音频AudioBufferSourceNode
,Web Audio API还提供了另一个名为OscillatorNode的源节点。 它允许针对指定波形生成频率。 但这实际上意味着什么?
在高水平上,频率确定以Hz为单位的声音的音高。 频率越高,音高越高。 除了自定义波形, OscillatorNode
还提供了一些预定义的波形,可以通过实例的type
属性来指定它们:
资料来源: Omegatron / Wikipedia
-
'sine'
–听起来类似于吹口哨 -
'square'
–通常用于与旧的视频游戏机合成声音 -
'triangle'
–正弦波和方波的混合体 -
'sawtooth'
–产生强烈的嗡嗡声
这是一个示例,说明如何使用OscillatorNode实时合成声音:
请参阅CodePen上的SitePoint ( @SitePoint ) 使用OscillatorNode生成 Pen的声音 。
OscillatorNode如何使Web受益?
与代码合成声音的能力将导致有效载荷比使用文件小得多。 这对于在从2G到4G的各种带宽上保持应用程序的奇偶校验非常重要。 无法保证移动数据连接的速度,特别是在新兴市场中。
在2G或3G上使用移动互联网的用户中有48%无法感知2G和3G服务之间的任何差异。
爱立信, 不断变化的移动宽带格局
为了证明这一点,我记录了上面的OscillatorNode
示例,并使用允许相同音质的比特率将其编码为MP3文件。 生成的文件为10 KB,根据Chrome Dev Tools的网络限制功能,通过常规2G连接加载将需要2.15秒的时间。 在这种情况下,程序化方法无疑是赢家。
使用OscillatorNode发出通知声音
让我们在真实示例中使用OscillatorNode
。 我在文章开头提到,我们将通知声音添加到用户界面。 如果打开此CodePen ,则会看到一个消息传递应用程序UI。 单击发送按钮后,将出现一条通知,通知我们该消息已发送。 该样板包含我们感兴趣的两个部分: 一个称为context
的AudioContext
实例,以及一个名为playSound
的函数。
开始之前,单击“ 叉子”按钮。 这将创建样板副本,您可以在其中保存更改。
值得一提的是,我已经在Chrome和Firefox中对此进行了测试,因此您应该使用其中一种浏览器。
在playSound
,声明一个名为oscillatorNode
playSound
的变量,并为其分配context.createOscillator()
的返回值:
const oscillatorNode = context.createOscillator();
接下来,让我们配置节点。 将其type
属性设置为'sine'
,将frequency.value
属性设置为150
:
oscillatorNode.type = 'sine';
oscillatorNode.frequency.value = 150;
要通过扬声器或耳机播放正弦波,请调用oscillatorNode.connect
,并将其传递给context.destination
节点。 最后,让我们呼唤oscillatorNode.start
,其次是oscillatorNode.stop
,传递到它的参数context.currentTime + 0.5
; 根据AudioContext's
硬件调度时间戳,这将在500毫秒后停止声音。 现在,我们的playSound
方法如下所示:
function playSound() {
const oscillatorNode = context.createOscillator();
oscillatorNode.type = 'sine';
oscillatorNode.frequency.value = 150;
oscillatorNode.connect(context.destination);
oscillatorNode.start();
oscillatorNode.stop(context.currentTime + 0.5);
}
保存更改并单击“ 发送”后 ,我们将听到通知音。
介绍GainNode
不用说,这非常扎眼。 为什么不使用效果节点使声音听起来更令人愉悦? GainNode是效果节点的一个示例。 增益是改变输入信号幅度的一种方式,在我们的情况下,它使我们能够控制音频源的音量。
在oscillatorNode
gainNode
的声明下方,声明另一个名为gainNode
变量,并为其分配context.createGain()
的返回值:
const gainNode = context.createGain();
在oscillatorNode
gainNode
的配置下,将gainNode
的gain.value
属性设置为0.3。 这将以原始音量的30%播放声音:
gainNode.gain.value = 0.3;
最后,要将GainNode
添加到我们的音频图中, gainNode
传递给oscillatorNode.connect
gainNode
,然后调用gainNode.connect
,我们将传递context.destination
:
function playSound() {
const oscillatorNode = context.createOscillator();
const gainNode = context.createGain();
oscillatorNode.type = 'sine';
oscillatorNode.frequency.value = 150;
gainNode.gain.value = 0.3;
oscillatorNode.connect(gainNode);
gainNode.connect(context.destination);
oscillatorNode.start();
oscillatorNode.stop(context.currentTime + 0.5);
}
保存更改并单击“ 发送”后 ,我们将听到声音更安静地播放。
用AudioParam混合事物
您可能已经观察到,为了设置OscillatorNode
的频率和GainNode
的增益,我们必须设置一个名为value
的属性。 签订合同的原因是gain
和frequency
都是AudioParam 。 该界面不仅可以用于设置特定值,还可以用于计划的,逐渐变化的值。 AudioParam
公开了许多方法和属性,但是三个重要的方法是:
-
setValueAtTime
–在给定时间立即更改值 -
linearRampToValueAtTime
–计划在给定的结束时间内逐步线性变化的值 -
exponentialRampToValueAtTime
–计划值的逐渐,指数变化。 与恒定的线性变化相反,随着调度程序接近结束时间,指数变化将以更大的增量增加或减少。 这可能是更可取的,因为它听起来更人耳
现在,我们将以指数方式增加频率和增益。 为了使用exponentialRampToValueAtTime
方法,我们需要安排一个先验事件。 用对oscillatorNode.frequency.value
节点oscillatorNode.frequency.value
的调用来替换oscillatorNode.frequency.value
oscillatorNode.frequency.setValueAtTime
。 传递相同的150
Hz频率,并通过传递context.currentTime
作为第二个参数立即对其进行调度:
oscillatorNode.frequency.setValueAtTime(150, context.currentTime);
在setValueAtTime
调用下方,调用oscillatorNode.frequency.exponentialRampToValueAtTime
setValueAtTime
,其值为500
Hz。 从排定的开始时间开始排定0.5
秒:
oscillatorNode.frequency.exponentialRampToValueAtTime(500, context.currentTime + 0.5);
保存并单击“ 发送”后 ,您会听到频率随着播放的进行而增加。
总结一下,用与我们的OscillatorNode
频率相同的方式调用gainNode.gain.setValueAtTime
替换gainNode.gain.value
的设置:
gainNode.gain.setValueAtTime(0.3, context.currentTime);
要淡出声音,请在0.5
秒内以指数方式将增益提高到0.01
:
function playSound() {
const oscillatorNode = context.createOscillator();
const gainNode = context.createGain();
oscillatorNode.type = 'sine';
oscillatorNode.frequency.setValueAtTime(150, context.currentTime);
oscillatorNode.frequency.exponentialRampToValueAtTime(500, context.currentTime + 0.5);
gainNode.gain.setValueAtTime(0.3, context.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, context.currentTime + 0.5);
oscillatorNode.connect(gainNode);
gainNode.connect(context.destination);
oscillatorNode.start();
oscillatorNode.stop(context.currentTime + 0.5);
}
点击“ 保存并发送”后 ,您会听到我们的通知声音随着时间的推移变得越来越安静。 现在,我们听起来更人性化了。
这是完成的演示。
请参阅CodePen上的SitePoint ( @SitePoint ) 使用OscillatorNode发出的笔通知声音 。
重播源节点
在结束本文之前,重要的一点是要注意那些对API有所了解的人的困惑。 要在声音播放完毕后再次播放,写这样似乎很有意义:
oscillatorNode.start();
oscillatorNode.stop(context.currentTime + 0.5);
oscillatorNode.start(context.currentTime + 0.5);
oscillatorNode.stop(context.currentTime + 1);
完成此操作后,我们将观察到抛出InvalidStateError
,并且消息cannot call start more than once
。
AudioNode
的创建成本AudioNode
,因此Web Audio API的设计鼓励开发人员在需要时重新创建音频节点。 在我们的例子中,我们将不得不再次调用playSound
函数。
结论
希望您喜欢使用Web Audio API进行声音合成的入门。 我们已经展示了它的许多用例之一,尽管网站和Web应用程序上通知声音的增加是一个有趣的UX问题,它将随着时间的流逝而得到回答。
如果您想了解有关Web Audio API的更多信息,我将为SitePoint Premium制作一个由5部分组成的截屏视频系列,名为“ 您还没听说过!”。 。 现在可以观看第一集。
您是否在网页和应用程序中使用Web Audio API? 我很想在下面的评论中听到您的经验和用例。
From: https://www.sitepoint.com/web-audio-api-add-sound-to-web-page/