用Web Audio API做个简易电子琴

前言

Web Audio API 提供了在浏览器中进行音频处理和合成的能力,使得我们可以创建各种类型的音频应用程序。在这篇文档中,我们将使用 Web Audio API 来创建一个简易小电子琴

什么是Web Audio API

Web Audio API提供了一组在web上操作音频的API,使用户可以在音频上下文(AudioContext)中进行音频操作。提供了相比html <audio>标签更丰富、更复杂的音频处理能力,甚至可以通过波形生成器进行音频的创作。<audio>的功能比较类似于<img>,AudioContext则比较类似于canvasContext,二者在不同的场景有不同的用途。

理解Web Audio API

现实生活中的场景

首先我们先看看,现实生活中的我们听到的音频是怎么来的,我们这里以一个边弹边唱的吉他手为例,他的接线大概是这样的

我们知道声音的本质都是波形。演奏者通过拨吉他弦,可以产生一种类似正弦波的波形,这里吉他的音波之后经过失真效果器处理,音波会作为电信号输入到效果器的电路中,将吉他波形处理成带失真的方波在输入给音响,音响接受到的声波就是电吉他的铮铮乍、铮铮乍的声音。

话筒则是通过振膜采集演唱者的声音的振动,将其转化为电信号输入给音响。手机播放的音频则直接将存储好的音频信号输入给音响。

音响则最后负责将所有声波合到一起,放大后播放出来,这样我们就听到了又有伴奏又有吉他又有歌声的音频了

Web Audio的场景

Web Audio API则是用模拟的方式完成了这些工作(和现实生活中的合成器/电子琴非常像,用数字模拟而非电信号处理)。

Web Audio具有模块化路由的特点。在一个个音频节点(AudioNode)上操作进行基础的音频,它们连接在一起构成音频路由图。我们依然用弹唱的场景举例,如下图

这里用到的节点分别如下

AudioContext/OfflineAudioContext

音频上下文,所有音频的控制和处理,都在Context的基础上进行,类比canvas的ctx。AudioContext会实时的在硬件上渲染音频,而OfflineAudioContext则是会尽可能快的将音频计算成一个AudioBuffer作为结果

OscillatorNode

OscillatorNode 接口表示一个振荡器(或者说一个信号发生器),它产生一个周期的波形信号,是一个音频源节点。这个模块会生成一个指定频率的波形信号(即一个固定的音调)。同时也提供了setPeriodicWave可以自定义波形,我们可以通过自定义波形直接模拟出失真过后的吉他声音,这里的OscillatorNode作用可以相当于吉他+效果器一起。

GainNode

GainNode 表示音量的变化,是一个音频处理接节点。因为OscillatorNode创造的是规律持续的波形,但吉他的声音并不是持续不断的,所以需要GainNode来控制具体的声音表现。

MediaStreamSourceNode

是一个音频源节点,是MediaStream(比如一个摄像头或者麦克风)的一部分,这里可以用来接受麦克风输入。

AudioBufferSourceNode

也是一个音频源节点,用来播放存在内存中的音频数据(AudioData),这里可以用来播放伴奏。

AudioDestinationNode

音频图形在特定情况下的最终输出地址,对于AudioContext通常是输出到扬声器(类比与音响),而OfflineAudioContext则输出到音频记录节点(类比输入到录音机里去了)

在此之外,就像吉他有Delay(延时)、Compressor(压缩)等众多效果器一样,Web Audio API也有众多的其他node来实现各种各样的作用,具体可以查看文档

做个简易合成器

具体实现

接下来我们就用Web Audio做一个小电子琴,非常简单。首先我们需要先创建好所需的context与node,并且把它们连起来

JavaScript 复制代码
const audioCtx = new AudioContext();

// 创建节点
const oscillator = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();

// 将波形发生器接到gainNode上,然后将gainNode连接到destination
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);

然后设定波形发生器,让他播放声音,这里就播放一个正弦波

JavaScript 复制代码
 oscillator.type = 'sine'; // 波形是正弦波
 
 oscillator.start(audioCtx.currentTime); // 开始生成波形
 gainNode.gain.setValueAtTime(0, audioCtx.currentTime); // 把声音关掉,先不要出声

之后我们只需要在每次按下琴键时候,给oscillator指定对应的频率,然后把gainNode打开播放出声音来,就像按下了一个对应音的琴键一样

JavaScript 复制代码
// C大调每个音对应的频率
const toneFrqList =  [ /* do */ 261.63, /* re */ 293.66, 329.63, 349.23, 392.0, 440.0,
  493.88,
];

export const play = async (n = 0) => {
  gainNode.gain.cancelScheduledValues(audioCtx.currentTime); // 清除掉gainNode之前的操作,防止声音卡顿
  
  // 指定频率
  oscillator.frequency.setValueAtTime(toneFrqList[n], audioCtx.currentTime); 
  
  // 发出声音
  gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.01); 
  // 在1秒内渐弱,模拟琴键声音渐小的样子
  gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 1);
};

Demo

code.juejin.cn/pen/7350217...

相关推荐
Eiceblue9 小时前
通过 C# 将 HTML 转换为 RTF 富文本格式
开发语言·c#·html
_OP_CHEN11 小时前
前端开发实战深度解析:(一)认识前端和 HTML 与开发环境的搭建
前端·vscode·html·web开发·前端开发
喂自己代言11 小时前
HTML ``元素:链接外部资源的关键角色与用法
css·html
H_ZMY14 小时前
微信小程序 mp-html:专为小程序设计的富文本渲染组件
微信小程序·小程序·html
Hilaku16 小时前
这 5 个冷门的 HTML 标签,能让你少写 100 行 JS
前端·javascript·html
samroom18 小时前
什么是MVVM以及HTML小案例
前端·html
百***812718 小时前
【HTML+CSS】使用HTML与后端技术连接数据库
css·数据库·html
xiaoxue..20 小时前
深入理解浏览器渲染流程:从HTML/CSS/JS到像素呈现
前端·javascript·css·html
会篮球的程序猿1 天前
html+canvas+thikphp 可视化工具拖拽、编辑生成JSON,渲染成海报图片 完全自定义,支持选择,文字背景色
前端·html·json
极客先躯1 天前
在 IntelliJ IDEA 中打开 HTML 到浏览器
java·html·intellij-idea