JS | Web Audio API (上) 你的音谱

“如毒似魅,如解似仙。程序世界,代码纷纷,web audio是流经存在的邂逅。九十刹那为一念,一念中一刹那经九百生灭,盘舞环形地来寻你。"
—— 题记

正文


Web Audio简介

Web Audio API为控制网页的音频提供了强有力的后盾,允许开发人员为音频添加效果,创建音频可视化等等。

源自网络.png

百科:音频和声音

百度百科

百度百科

Web audio的内容和用途

Web Audio API包含通过audio context操控音频,不同类型的源也可以被一个环境支持,并允许模块路由。利用audio nodes(连接一起形成了audio routing graph)执行操作,模块的设计为创建复杂音频功能提供灵活性。

根据英文解释,它是在audio context里操控音乐的发生,无论是一首或多首,都可以在一个audio context里搞定,相当于为audio的控制设置了一个环境,我们在这个操控室里统筹音乐。环境有了,用什么来操作,audio nodes,相当于各种操纵杆。也有这么一个比喻说,“想象卡拉OK设备,DVD机相当于音频音源,音响相当于音频播放设备,混响器(主要用于把你的声音与背景音乐合成最终输出到音响上)相当于音频处理模块”,然后各个模块通过电线连接,最终接在音响上。

Web audio的工作流程
  1. 创建音频环境(audio context)
  2. 在音频环境里,创建源 —— 比如<audio>, oscillator, stream
  3. 创建效果节点,比如reverb, biquad filter, panner, compressor
  4. 选择音频的最终输出口,比如扬声器
  5. 连接 源——效果——目的地(输入——处理——输出)
图例.png

部分属性方法解释

AudioContext

音频上下文对象,相当于声音容器,处理音频的前提环境

var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx = new AudioContext();
audioCtx.decodeAudioData(audioData, function(decodedData) {
  // use the decoded data here
});

或者利用promise:

audioCtx.decodeAudioData(audioData).then(function(decodedData) {
  // use the decoded data here
});
AudioNode

用于表示像音频源的节点(例如,HTML <audio>或<video>元素,振荡器节点等),音频目的地,中间处理模块(例如像BiquadFilterNode或ConvolverNode)或音量控制(如GainNode)。

官方图例.png

AudioNode具有输入和输出,每个都有一定数量的通道。零输入但有一个或多个输出的AudioNode称为源节点(source node)。不同节点的音频处理是不同的,总之,节点解读其输入,进行一些音频相关处理,并为其输出生成新的值,或者简单的让音频通过(例如,在 AnalyserNode
里,其中处理的结果被单独访问)

连接不同的节点可以组成一个处理图(* processing graph *),同样包含在 AudioContext
中。一般来说,处理节点继承AudioNode的方法和属性,但会在顶部定义自身功能。有关更多详细信息,请参阅各个节点页面,如 Web Audio API 首页所列。

  • ** AudioNode.connect()
    **
    允许将当前节点的输出连接到目的,可以是音频节点(将声音数据定向到指定节点),或AudioParam
    ,以便节点的输出数据随时间自动更改该参数的值。
var destinationNode = AudioNode.connect(destination, outputIndex, inputIndex);
AudioNode.connect(destination, outputIndex);

** AudioBufferSourceNode **

操作audioBuffer对象里的音频数据,把audioBuffer中的数据转化为音频信号,作为音频源,零输入,一个输出,属于Audio Node。输出的通道数量对应着音频缓冲区的通道数量。如果没有任何的缓冲区,也就是说,如果AudioBufferSourceNode 的值为null,输出为包含静音的一个通道。一个 AudioBufferSourceNode
只可以播放一次;常说,AudioBufferSourceNodes 有个“射后不管”模式,一劳永逸:一旦开始,所有节点的引用都可以被删除,并且自动回收。

官方图例.png
  • ** AudioBufferSourceNode.buffer
    **
    音频缓冲区,表示播放的音频集,当被设置值为null的时候,会被定义为静音单声道。
var source = audioCtx.createBufferSource();
// from audioCtx.createBuffer, or audioCtx.decodeAudioData
source.buffer = myBuffer;
  • ** AudioBufferSourceNode.start()
    **
    音乐的开始播放。AudioBufferSourceNode.start()仅对应一个。如果再次播放,需要另创建一个AudioBufferSourceNode 。这些节点是很容易创建的,AudioBuffers 也能够反复利用。

  • ** AudioBufferSourceNode.stop()
    **
    音乐的停止播放。AudioBufferSourceNode.stop()是被允许暂停多个音乐。最近的声音将会替代原先的,没有完全到缓冲区的末尾。

AnalyserNode

能提供实时频率以及时间域分析信息的节点,它是一个AudioNode,将音频流从输入传递到输出,允许获取和处理生成的数据,并创建音频可视化。
拥有一个输出,一个输出,尽管输出没有链接,节点也会工作。

官方图例.png
var audioCtx = new AudioContext();
var analyser = audioCtx.createAnalyser();
var bufferLength = analyser.frequencyBinCount;
  • ** AnalyserNode.getByteFrequencyData() **
    将当前数据频率复制转化为Uint8Array

    如果数组具有比AnalyserNode.frequencyBinCount更少的元素,则会删除多余的元素。如果它具有比所需要的更多的元素,则忽略多余的元素。
var audioCtx = new AudioContext();
var analyser = audioCtx.createAnalyser();
var dataArray = new Uint8Array(analyser.frequencyBinCount); // Uint8Array should be the same length as the frequencyBinCount 
analyser.getByteFrequencyData(dataArray); // fill the Uint8Array with data returned from getByteFrequencyData()

举个简单的例子,结合音频链路和代码:

  1. 创建上下文,audio context;
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx;
// var source;
try {
    audioCtx = new AudioContext();
    console.log('support');
} catch (e) {
    alert('Your browser does not support AudioContext!');
    console.log(e);
}
console.log(audioCtx).png
  1. 利用方法createBufferSource()创建audioBufferSourceNode音频源对象;
source = audioCtx.createBufferSource();
console.log(source)
  1. 完成获取需要播放的音频数据后,利用decodeAudioData()解码数据;
var request = new XMLHttpRequest();
    
    //初始化 HTTP 请求参数, 配置请求类型,文件路径等
    request.open('GET', 'audio/music.mp3', true);

    // 配置数据返回类型,从服务器取回二进制数据
    request.responseType = 'arraybuffer';

    // 获取完成,对音频进一步操作,解码
    request.onload = function() {
        var audioData = request.response;
        audioCtx.decodeAudioData(audioData, function(buffer) {
            ……
        },
        function(e) { console.log("Error with decoding audio data" + e.err); });
    };
  1. audioBufferSourceNode对象的buffer属性接收audioBuffer数据
source.buffer = buffer;
console.log(buffer)
  1. 通过connect()将audioBufferSourceNode对象连接到audioContext的desitination(speakers)
source.connect(audioCtx.destination);
  1. 从最开始播放
source.start(0);

附简单例子最终代码:


// create environment -- audio context
// define variables

var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx;
var source;
try {
    audioCtx = new AudioContext();
    console.log('support');
            console.log(audioCtx)
    
} catch (e) {
    alert('Your browser does not support AudioContext!');
    console.log(e);
}

// use XHR to load an audio track, and
// decodeAudioData to decode it and stick it in a buffer.
// Then we put the buffer into the source

var getData = function() {
    // create audio node to play the audio in the buffer
    source = audioCtx.createBufferSource();
            console.log(source)

    // 请求
    var request = new XMLHttpRequest();
    
    //初始化 HTTP 请求参数, 配置请求类型,文件路径等
    request.open('GET', 'audio/music.mp3', true);

    // 配置数据返回类型,从服务器取回二进制数据
    request.responseType = 'arraybuffer';

    // 获取完成,对音频进一步操作,解码
    request.onload = function() {
        var audioData = request.response;
        audioCtx.decodeAudioData(audioData, function(buffer) {
            source.buffer = buffer;

            source.connect(audioCtx.destination);
            source.loop = true;
        },
        function(e) { console.log("Error with decoding audio data" + e.err); });
    };

    // 发送一个 HTTP 请求
    request.send();
};

// play audio
getData();
source.start(0);

【零零碎碎,通过一点点阅读官方英文文档,与部分中文文档的理解整理,web audio实现了跟音频的通信,会耗硬件资源,适用性没有canvas那么广,或许这也是中文文档并不多的原因,音乐世界,趣味无穷。震撼于它跟canvas结合制造的效果,欲知后事如何,且听下回分解吧~】

参考文章:
https://developer.mozilla.org/en-US/docs/Web_Audio_API/Using_Web_Audio_API
https://github.com/wendellvian/blog/wiki/%E9%87%8D%E6%96%B0%E8%AE%A4%E8%AF%86Audio%E4%B9%8B%E7%9C%8B%E5%BE%97%E8%A7%81%E7%9A%84%E9%9F%B3%E4%B9%90_20160725
http://www.ayqy.net/blog/web-audio-api%E8%A7%A3%E6%9E%90/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容