loading

WebAudio API


webAudio API

webAudio API接口可以用来实现音乐可视化、音频剪辑、修声、语音、去声等等强大的操作

webAudioAPI接口关系图:

AudioContext

AudioContext是所有音频操作的前提,一个类似Canvas的ctx的上下文对象

var ac = new (window.AudioContext ||  window.webkitAudioContext || window.mozAudioContext || window.msAudioContext) 
//由于API兼容性问题,需要在创建时加上后缀

AudioBufferSourceNode

创建音频源 方法(1)

这种方式是通过请求方式播放音乐

 var ac = new (window.AudioContext ||  window.webkitAudioContext || window.mozAudioContext || window.msAudioContext)();
        let url = './Kalimba.mp3';
//通过 fetch请求本地文件,返回样式设置为arraybuffer
        fetch(url,{
            responseType:'arraybuffer'
        })
        .then(res => {
          //将返回的数据转成arrayBuffer数据,并返回
          return res.arrayBuffer();
        })
        .then(res =>{
            //使用ac.decodeAudioData(arrayBuffer, succ(buffer), err)方法音频解码,获取成功后调用第一个回调并返回buffer解码数据,失败则调用最后个回调
            ac.decodeAudioData(res,(buffer)=>{
                //创建bufferSource
                let BufferSource = ac.createBufferSource();
                //将返回的数据给它
                BufferSource.buffer = buffer;
                //直接连接音频聚集地
                BufferSource.connect(ac.destination);
                //开始播放
                BufferSource[BufferSource.start ? 'start' : 'noteOn'](0);
            },(err)=>{console.log(err);})
        })

MediaElementAudioSourceNode

创建音频源 方法(2)

这种方式是通过 DOM元素 播放音乐

   <input type="button" value="播放" onclick='music.play()'>  //点击播放音乐   
   <input type="button" value="停止" onclick="music.pause()"> //点击停止音乐
   <script>
       var ac = new (window.AudioContext ||  window.webkitAudioContext || window.mozAudioContext || window.msAudioContext);
	//创建音乐DOM元素
       let music = new Audio('./Kalimba.mp3');
	//通过 DOM元素创建音频源
       let source = ac.createMediaElementSource(music);
	//直接连接音频聚集地
       source.connect(ac.destination);
</script>

使用input[type=file]创建 (可以本地获取)

var audioCtx = new window.AudioContext();
     var audioInput = document.getElementById("uploader"); //HTML语句:<input type="file" id="uploader" />
     audioInput.onchange = function() {
       //文件长度不为0则真的选中了文件,因为用户点击取消也会触发onchange事件。
       if (audioInput.files.length !== 0) {
         files = audioInput.files[0]; //得到用户选取的文件 //文件选定之后,马上用FileReader进行读入
         fr = new FileReader();
         fr.onload = function(e) {
           var fileResult = e.target.result; //文件读入完成,进行解码
           audioCtx.decodeAudioData(
             fileResult,
             function(buffer) {
               let source = audioCtx.createBufferSource();
               source.buffer = buffer; //将解码出来的数据放入source中 //转到播放和分析环节
               source.connect(audioCtx.destination);
               source.start(0);
             },
             function(err) {
               alert("!Fail to decode the file"); //解码出错
             }
           );
         };
         fr.onerror = function(err) {
           alert("!Fail to read the file"); //文件读入出错
         };
         fr.readAsArrayBuffer(files); //同样的,ArrayBuffer方式读取
       }
     };

GainNode

gain是在音乐播放之前处理声音大小的中间件

这里使用DOM元素方式来演示 , 请求方式的设置也和它一样

<input type="button" value="播放" onclick='music.play()'>  //点击播放音乐   
<input type="button" value="停止" onclick="music.pause()"> //点击停止音乐
<input type="range" max="100" min="0" value="60" oninput="setGain(this)"> //控制音乐播放声音
    <script>
        var ac = new (window.AudioContext ||  window.webkitAudioContext || window.mozAudioContext || window.msAudioContext);
		//创建音乐DOM元素
        let music = new Audio('./Kalimba.mp3');
		//通过 DOM元素创建音频源
        let source = ac.createMediaElementSource(music);
		//Gain连接destination
		let gain = ac.createGain();
		gain.connect(ac.destination);
		//必须连接Gain , 不再是连接destination了,否则音频没有经过gain处理,效果不会生效
        source.connect(gain);
		//设置gain.gain.value 的值,跟随input的value改变,实现改变声音大小
		function setGain(that)
        {   
            gain.gain.value = that.value/that.max;
        }
	</script>

analyserNode

这个节点可以实现音频的可视化,是一个可视化中必不可少的重要步骤

//创建Analyser
var analyser = ac.createAnalyser();
//设置fftSize大小
analyser.fftSize = 512;
//链接destination Gain节点,随之Gain节点到终点去
analyser.connect(gain);
//创建Uint8Array数据,并运用frequencyBinCount 来获取fft的一半
var arr = new Uint8Array(analyser.frequencyBinCount);
//然后使用getByFrequencyData来获取范围频域
analyser.getByteFrequencyData(arr);
//最后配合Canvas和requestAnimationFrame(callback)动画函数来实现可视化;

var ctx = document.querySelector("canvas").getContext("2d");
     ctx.canvas.width = document.body.clientWidth;
     var width = ctx.canvas.width,
       height = ctx.canvas.height;
     window.onresize = function() {
       ctx.canvas.width = document.body.clientWidth;
       width = document.body.clientWidth;
       let line = ctx.createLinearGradient(0, 0, 0, height);
       line.addColorStop(1, "red");
       line.addColorStop(0.5, "yellow");
       line.addColorStop(0, "green");
       ctx.fillStyle = line;
     };
     let line = ctx.createLinearGradient(0, 0, 0, height);
     line.addColorStop(1, "red");
     line.addColorStop(0.5, "yellow");
     line.addColorStop(0, "green");
     ctx.fillStyle = line;
     function draw(Data) {
       ctx.clearRect(0, 0, width, height);
       var w = width / 128;
       for (let i = 0; i < Data.length; i++) {
         ctx.fillRect(
           w * i,
           height - (Data[i] / 256) * height,
           (width / Data.length) * 1.5,
           Data[i]
         );
       }
     }
     var ac = new (window.AudioContext ||
       window.webkitAudioContext ||
       window.mozAudioContext ||
       window.msAudioContext)();
     //创建gain 来控制声音大小
     let gain = ac.createGain();
     //链接音频终点
     gain.connect(ac.destination);
     //创建analyser 来实现可视化
     let analyser = ac.createAnalyser();
     analyser.fftSize = 512;
     //链接gain
     analyser.connect(gain);
     //获取音乐数据
     fetch("./music/Kalimba.mp3", {
       responseType: "arraybuffer"
     })
       .then(res => res.arrayBuffer())
       .then(res => {
         ac.decodeAudioData(res, buffer => {
           let bufferSource = ac.createBufferSource();
           bufferSource.buffer = buffer;
           bufferSource.connect(analyser);
           bufferSource[bufferSource.start ? "start" : "noteOn"](0);
         });
       });
     (function() {
       //创建数据
       var arr = new Uint8Array(analyser.frequencyBinCount);
       //解决各浏览器的兼容性问题
       requestAnimationFrame =
         window.requestAnimationFrame ||
         window.webkitRequestAnimationFrame ||
         window.mozRequestAnimationFrame;
       //创建动画函数
       function animate() {
         //获取频域
         analyser.getByteFrequencyData(arr);
         draw(arr);
         //循环
         requestAnimationFrame(animate);
       }
       //启动动画函数
       requestAnimationFrame(animate);
     })();

     function setGain(that) {
       gain.gain.value = +that.value / +that.max;
     }

文章作者: Jing Hong
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Jing Hong !
 上一篇
HTML5 HTML5
一、H5 拖拽JS 里拖拽三事件, onmousedown onmousemove onmouseup 是实现交互性效果,根据鼠标的移动位置让标签元素联动 而 H5 拖拽也可以实现但更简单,实际例子: 百度图片识别,qq 邮箱文件提交,百度
2019-09-16
下一篇 
Chrome Devtools Chrome Devtools
Chrome Devtools 使用技巧1.网页可编辑(1)document.designMode = ‘on’(2)打开任何网站,在网址栏输入:可手机端javascdy.setAttribute(‘contentEditable’,’tr
2019-09-11
  目录