利用HTML5 Web Audio API给网页JS交互增加声音

转自张鑫旭老师博客 原文地址

一、庞然的HTML5 Web Audio API

首先务必要弄清这一点,本文这里所说的HTML5 Web Audio API和HTML5 元素完全不是一个东西,其体量也完全不是一个等级的,HTML5 Web Audio API接口的丰富程度和体量可以和HTML canvas API相提并论,其能实现的功能也非常令人瞠目。

HTML5 Web Audio API可以让我们无中生有创造声音,而且是各种音调的声音,换句话说,我们通过JavaScript就会创建一个完整的音乐出来,类似卡农将有固定的音乐,或是通过一些随机算法创建随机的音乐都都可以由前端开发工程师来完成(例如这个使用Web Audio API创建多个经典游戏背景音乐的案例),如果再配合一点人工智能的东西,我们说不定可以造出一个人工智能音乐生成工具。

当然其功能绝不仅限于这一点,我们还可以:

对简单或复杂的声音进行混合;
精确控制声音的密度和节奏;
内置淡入/淡出,颗粒噪点,音调控制等效果;
灵活的处理在音频流的声道,使它们成为拆分和合并;
处理从音频或视频的媒体元素的音频源;
使用MediaStream的getUserMedia()方法事实处理现场输入的音频,例如变声;
立体音效,可以支持多种3D游戏和沉浸式环境;
利用卷积引擎,创建各类线性音效,例如小/大房间、大教堂、音乐厅、洞穴、隧道、走廊、森林、圆形剧场等。尤其适用于创建高质量的房间效果。
高效的实时的时域和频分析,配合CSS3或Canvas或webGL可以实现音乐可视化支持;
以及其他多种音频波形算法控制,几乎就是把一个音频编辑类软件搬到web上。
但是对大多数的Web开发人员,我们并不需要和音频打交道这么深,因为毕竟不是做音乐网站的,此时,那些很高级的HTML5 Web Audio API功能就离我们实际工作的价值有些远,如果贸然花大量时间去深入学习其实是一件投入产出比很低的事情。当然,我这种担心实际上是多余的,“贸然花大量时间去深入学习?”搞反了吧,其实真实的现状是开发人员对此鸟都不鸟,看都不看。一来因为毕竟不火嘛,二来资料少看不懂嘛,三来自己项目很少有声音打交道,学了也白学。

考虑到这种现状,如果本文内容洋洋洒洒讲各种api,估计很多人瞟两眼就直观把页面关掉了,所以接下来我们从一个最简单最小的而且非常实用的案例来慢慢解开HTML5 Web Audio API的面纱。

二、HTML5 Web Audio API给网页交互增加声音

先来看实例效果,您可以狠狠地点击这里:鼠标hover按钮无中生有播放声音demo

当我们鼠标hover下图所示的按钮的时候,在非IE浏览器下,就会播放出类似电子琴琴键按下的声音,而且每次hover的时候,音调都会发生有规律的变化:
下面这句话是重点,demo页面中播放的声音是硬件自动生成的,不是调用现成的mp3音频播放出来的。

换种说法就是:无需任何音频文件,只需要几行JS代码,我们就能让网页发出各种各样的音调。

10年前,flash炫酷网页风兴起的时候,交互音效是非常普遍的,可以说是flash酷站必备元素。只是后来flash衰落了,而web对于多媒体资源的支持长久以来是比较弱的,于是Web网站全部都是安安静静的。在移动端,H5广告营销性质的网页都是音频用的比较多,但大多都是作为背景音乐使用的,交互时候其实用的并不多。我想,可能与大多数开发并不知道HTML5 Web Audio API可以直接弄出声音,知识的广度局限了技术的选型。

于是我就想到,HTML5 Web Audio API提及的人不多,使用并不火,并不一定是因为这个技术本身的局限或者使用场景不多,而是具有较大影响力的人,社区或企业并没有在这一块身先士卒进行推动。很多企业的官网、产品宣传页,广告营销性质的专题活动非常讲求炫酷,音视频层出不穷,很显然(参考flash时代),交互音效也其实是非常欢迎的,只是技术眼界的局限认为需要专门的mp3/wav音频调用成本高而不使用罢了。

HTML5 Web Audio API可以直接产生声音,并且可以随意控制音调,时长以及淡入淡出等效果,更强大更灵活。而这个功能点是HTML5 Web Audio API中最简单最基本也是最实用的,没有理由不给web开发带来交互音效热潮。

分享一个改过的张鑫旭大神的demo,类似于一个电子钢琴的感觉,随便玩玩吧。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
    <button id="button">经过我</button>
</body>
<script>
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
(function () {
    if (!window.AudioContext) { 
        alert('当前浏览器不支持Web Audio API');
        return;
    }

    // 按钮元素
    var eleButton = document.getElementById('button');

    // 创建新的音频上下文接口
    var audioCtx = new AudioContext();

    // 发出的声音频率数据,表现为音调的高低
    var arrFrequency = [196.00, 220.00, 246.94, 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25, 587.33, 659.25, 698.46, 783.99, 880.00, 987.77, 1046.50];

    // 音调依次递增或者递减处理需要的参数
    var start = 0, direction = 1;



    // 按下数字键的时候触发
    $('body').keydown( function (event) {
            // 当前频率
            var frequency = arrFrequency[event.which - 48];
            // 如果到头,改变音调的变化规则(增减切换)
            // if (!frequency) {
            //     direction = -1 * direction;
            //     start = start + 2 * direction;
            //     frequency = arrFrequency[start];
            // }
            // // 改变索引,下一次hover时候使用
            // start = start + direction;

            // 创建一个OscillatorNode, 它表示一个周期性波形(振荡),基本上来说创造了一个音调
            var oscillator = audioCtx.createOscillator();
            // 创建一个GainNode,它可以控制音频的总音量
            var gainNode = audioCtx.createGain();
            // 把音量,音调和终节点进行关联
            oscillator.connect(gainNode);
            // audioCtx.destination返回AudioDestinationNode对象,表示当前audio context中所有节点的最终节点,一般表示音频渲染设备
            gainNode.connect(audioCtx.destination);
            // 指定音调的类型,其他还有square|triangle|sawtooth
            oscillator.type = 'sine';
            // 设置当前播放声音的频率,也就是最终播放声音的调调
            oscillator.frequency.value = frequency;
            // 当前时间设置音量为0
            gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
            // 0.01秒后音量为1
            gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.01);
            // 音调从当前时间开始播放
            oscillator.start(audioCtx.currentTime);
            // 1秒内声音慢慢降低,是个不错的停止声音的方法
            gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 1);
            // 1秒后完全停止声音
            oscillator.stop(audioCtx.currentTime + 1);
        })
})();
</script>
</html>

原文地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值