[译] 听听雨声放放松!Web Audio API 入门(二)

2,004 阅读7分钟
原文链接: github.com

上一次我们使用WebAudioAPI制作了一个Web浏览器中的钢琴。

在大家的浏览器上可以正常演奏吧。

在钢琴的实现中将音源与最终输出直接连接了起来,这次来试试中间处理吧。

中间处理可以说是WebAudioAPI的功能中与HTML的Audio元素相比区别最大的部分了。

目录

有一些公开的Web站点,持续播放作为放松与集中精神的BGM的连绵的下雨声。

比如说下面这个。

www.rainymood.com/

下着阴郁的雨的天气,仅仅听着这样的声音是否觉得挺舒服的?

这次使用WebAudioAPI的中间处理,在像这样的雨声播放功能的基础上增加了音质变化。

在利用音频文件作为音源的AudioNode中,除了上次使用的AudioBufferSourceNode以外,还会使用MediaElementAudioSourceNode。

根据不同的适用音源与使用场景选择不同的AudioNode是很必要的。

  • 适合的音源:短音源

    (例:钢琴与打击乐器等单次音源)

    获得音频数据时,需要等待全部数据解码完成才能使用,与长音源相反。

  • 适合的使用场景:需要控制发声时刻的场合

    (例:游戏的効果音)

  • 其它特点:由于对象是一次性的,播放后需要重新生成。

  • 适合的音源:长音源

    (例:乐曲的音源、持续数十秒的音源)

    无需等待获取全部数据就可以开始播放。

  • 适合的使用场景:不注重准确的发生时刻,循环中不断播放的场合。

    (例:BGM)

    仅支持PC的场合。

    一些手机的浏览器也许可以控制audio元素,但并没有WebAudioAPI的相关功能。

  • 其它特点:生成对象后可以反复使用。

这一次使用持续较长时间的雨声作为音源。

需要不停的持续播放,根据这种情况选择MediaElementAudioSourceNode比较合适。

不过,对于那些不支持MediaElementAudioSourceNode的手机浏览器来说,就很遗憾了。

MediaElementAudioSourceNode,顾名思义,需要将HTML的audio与video元素作为音源来使用。在作为MediaElementAudioSourceNoded的音源使用时,也可以使用audio与video元素原本的功能。

也就是说,可使用播放、停止与循环、自动播放等功能,与单独使用audio/video元素时同样的操作。使用WebAudioAPI的中间处理给audio/video元素的音频加特效——这么想的话比较容易理解。

HTML

JS

var
    // 初始化AudioContext
    ctx = new AudioContext(),
    // 获得audio元素
    elAudio = document.getElementById('audio'),
    // 从AudioContext生成AudioNode
    // MediaElementAudioSourceNode: 将audio/video元素作为音源操作的AudioNode
    mediaElementSource = ctx.createMediaElementSource(elAudio);

首先与上次一样,直接与最终输出连接,播放一下试试!

与AudioBufferSourceNode不同,可以反复使用初次生成的AudioNode。使用audio元素的播放/停止命令来控制MediaElementAudioSourceNode的播放/停止。

HTML

Play / Stop

JS

// 连接表示音源的AudioNode与表示最终输出的AudioNode
mediaElementSource.connect(ctx.destination);
// 事件注册
var isPlaying = false;
elButton.addEventListener('click', function() {
    elAudio[!isPlaying ? 'play' : 'pause']();
    isPlaying = !isPlaying;
});

把上面的代码整合一下,加个下雨的背景图片。如下

源码(GitHub)

demo

雨下起来了唉O(∩_∩)O~~!不过这并没有进行中间处理,仅仅是使用audio元素进行播放而已。

那么是时候来让音量和音质变化了。

表示中间处理的AudioNode有很多,其中的属性是表示自身处理状态的,继承自AudioParam的对象。

AudioParam对象,有表示处理状态的balue属性,表示value初始值的defaultValue属性,还有其他各种方法。这些属性与方法对于继承自AudioParam的所有对象来说都可以进行操作。

不过需要注意的是继承自AudioParam的对象名称与AudioNode是不同的。

表示调整音量的AudioNode是GainNode。GainNode中的gain属性是继承自AudioParam的对象。

gain对象的defaultValue值为1,value属性的设定为在0与1间的浮点数,0表示静音,1表示原始音量,可以重载音量大小。

// 从AudioContext生成GainNode
// GainNode: 中间处理(调整音量)AudioNode
gain = ctx.createGain();
// 设定GainNode,对其连接的音源进行音量减半的处理
gain.gain.value = 0.5;

将GainNode与表示音源与最终输出的AudioNode相连接,就做好了以所设定的音量来播放音源的准备了。

// 表示音源的AudioNode与表示中间处理(调整音量)的AudioNode连接
mediaElementSource.connect(gain);
// 表示中间处理的AudioNode与表示最终输出的AudioNode连接
gain.connect(ctx.destination);

在滑杆(范围选择控件)上进行音量调节。如下

源码(GitHub)

demo

可以调节成一场安静的雨!

中间处理时可以进行多次连接。加上音量的调节后,也可以调整音质,使用低通滤波器与高通滤波器进行处理。

低通滤波器会滤掉比设定的频率值高的波,使低于设定值的波通过。高通滤波器则会滤掉比设定的频率值低的波,使高于设定值的波通过。

使用叫做BiquadFilterNode的AudioNode可以进行这些处理。

// 从AudioContext生成BiquadFilterNode
biquadFilter = ctx.createBiquadFilter();

BiquadFilterNode通过改变type属性可以对多种文件进行处理。

type属性的值为字符串,’lowpass’对应低通滤波器,、’highpass’对应高通滤波器。

也可以设定为其他字符串,这个只使用效果比较容易理解的这两个。

// 设定BiquadFilterNode进行低通滤波器的处理
biquadFilter.type = 'lowpass';

BiquadFilterNode有多个继承自AudioParam的对象,其中的frequency属性可以设定截止频率(単位:Hz)。

frequency对象的defaultValue属性为350,value属性最小值为10,最大值为音源采样频率的一半(PS:应该是根据奈奎斯特抽样定律)。

// BiquadFilterNode会发挥低通滤波器的功能,除去1000Hz频率以上的波
biquadFilter.frequency.value = 1000;

value属性的范围与前文所述,不能将这个范围以外的数字信号解调成模拟信号,并且这个范围不会超出人的听力范围(20~20000Hz)太多。

可以通过文件属性来确认音源采样速率,一般设定为44100Hz。

将这BiquadFilterNode与表示音源的AudioNode与表示最终输出的AudioNode相连接。这样一来,给播放的音源添加滤波器的处理就准备完成了。

// 表示音源的AudioNode与表示音量调节处理的AudioNode连接
mediaElementSource.connect(gain);
// 表示音量调节处理的AudioNode与表示滤波处理的AudioNode连接
gain.connect(biquadFilter);
// 表示滤波处理的AudioNode与表示最终输出的AudioNode连接
biquadFilter.connect(ctx.destination);

可以通过选择列表与滑杆来调节以上属性,如下。

源码(GitHub)

demo

在这个demo的源码中使用了disconnect方法,可以中断AudioNode之间的连接。

可以中断与参数中所指定的AudioNode的连接,在这里没有进行指定,中断了全部连接。

使用connect方法连接的AudioNode若没有用disconnect方法显在的中断连接的话会一直连接在一起,这是为了使一个AudioNode能与多个AudioNode进行连接。

在这个例子中:

  • BiquadFilter关闭时: GainNode → 最终输出
  • BiquadFilter设定为低通或高通滤波器时: GainNode → BiquadFilterNode → 最终输出

因此使用它们可以调整AudioNode之间的连接。

// 一次性中断GainNode与BiquadFilterNode的连接
gain.disconnect();
biquadFilter.disconnect();
// BiquadFilter关闭时
if (text === 'off') {
    // GainNode → 最终输出
    gain.connect(ctx.destination);
// BiquadFilter设定为低通或高通滤波器时
} else {
    // GainNode → BiquadFilterNode → 最終出力
    gain.connect(biquadFilter);
    biquadFilter.connect(ctx.destination);
}

这样,不仅加上了音量调节,也可以进行雨声音质的调整,调出低沉或清脆的声音。搞定!!

这次对雨声进行了类似拾音器的中间处理,比较容易理解,也可以对其它元素进行调整,比如延迟与发声方向等。

除此之外,如果把音源文件换成其它环境音与乐曲的话也具有同样的效果,请务必尝试一下。

那么回见!