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!
评论
 上一篇
HTML5HTML5
一、H5 拖拽JS 里拖拽三事件, onmousedown onmousemove onmouseup 是实现交互性效果,根据鼠标的移动位置让标签元素联动 而 H5 拖拽也可以实现但更简单,实际例子: 百度图片识别,qq 邮箱文件提交,百度
2019-09-16
下一篇 
JS中Buffer数据详解JS中Buffer数据详解
元数据处理序言随着WebSocket、WebAudio、Ajax2等广泛应用,前端方面只要是处理大数据或者想提高数据处理性能,那一定是少不了 ArrayBuffer对象 同时在浏览器当中处理二进制数据的需求也在不断的增加,有时需要字节数组、
2019-09-16
  目录