本文由Mark BrownJosh 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前缀。

我可以使用audio-api吗? 来自caniuse.com的主要浏览器对audio-api功能的支持数据。

使用API

Web Audio API的入口点是一个称为AudioContext的全局构造函数。 实例化后,它提供了用于定义符合AudioNode接口的各种节点的方法。 这些可以分为三类:

  • 源节点–例如MP3源,合成源
  • 效果节点–例如平移
  • 目标节点–由AudioContext实例公开为destination ; 这表示用户的默认输出设备,例如扬声器或耳机

可以使用connect方法这些节点链接为多种组合。 这是使用Web Audio API构建音频图的一般想法。

使用AudioContext构建音频图
资料来源: MDN

这是将MP3文件转换为AudioBufferSourceNode并通过AudioContext实例的destination节点播放它的示例:

请参阅CodePen上的SitePoint@SitePoint使用Web Audio API播放MP3文件的笔。

产生音频

除了通过AudioBufferSourceNode支持录制的音频AudioBufferSourceNode ,Web Audio API还提供了另一个名为OscillatorNode的源节点。 它允许针对指定波形生成频率。 但这实际上意味着什么?

在高水平上,频率确定以Hz为单位的声音的音高。 频率越高,音高越高。 除了自定义波形, OscillatorNode还提供了一些预定义的波形,可以通过实例的type属性来指定它们:

OscillatorNode支持的内置波形
资料来源: 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。 单击发送按钮后,将出现一条通知,通知我们该消息已发送。 该样板包含我们感兴趣的两个部分: 一个称为contextAudioContext实例,以及一个名为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的配置下,将gainNodegain.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的属性。 签订合同的原因是gainfrequency都是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/

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐