web音頻流轉發之AudioNode

前言

上一章地址: web音頻流轉發之音頻源
下一張地址:web音頻流轉發之音視頻直播
在這一章我說幾個咱們須要用到的音頻處理模塊也就3個吧,包括咱們轉發流是須要用到的核心模塊。更多模塊請看MDN,或者看HTML5音頻API Web Audio也有一些中文講解,但願你們多多支持。javascript

概述

AudioNode:是一個處理音頻的通用模塊, 好比一個音頻源 (e.g. 一個 HTML <audio> or <video> 元素), 一個音頻地址或者一箇中間處理模塊 (e.g. 一個過濾器如 BiquadFilterNode, 或一個音量控制器如 GainNode).一個AudioNode 既有輸入也有輸出。輸入與輸出都有必定數量的通道。只有一個輸出而沒有輸入的 AudioNode 叫作音頻源(MDN的解釋)。下面我用簡單的代碼給你們解釋下html

let audioCtx = new window.AudioContext,
    //頻率及時間域分析器,聲音可視化就用這個
    analyser = audioCtx.createAnalyser(),
    //音量變動模塊
    gainNode = audioCtx.createGain(),
    //波形控制器模塊
    distortion = audioCtx.createWaveShaper(),
    //低頻濾波器模塊
    biquadFilter = audioCtx.createBiquadFilter(),
    //建立源
    source = audioCtx.createMediaStreamSource(stream);
    //經過connect方法從音頻源鏈接到AudioNode處理模塊,再鏈接到輸出設備,
    //當咱們修改前面的模塊時,就會影響到後面AudioNode,以及咱們最終聽見的聲音
    source.connect(analyser);
    analyser.connect(distortion);
    distortion.connect(biquadFilter);
    biquadFilter.connect(convolver);
    convolver.connect(gainNode);
    gainNode.connect(audioCtx.destination);

圖片描述

下面我就分別講解咱們須要用的幾個apijava

createAnalyser

下面簡單說一下它的方法和屬性,具體的使用在後面的demo中,說實話這些屬性我也不知道有有什麼用,可是咱們能經過方法取到咱們須要的數據,作音頻可視化。analyser中的數據會根據數據的不一樣會不停的變換,全部咱們須要用requestAnimationFrame函數,反覆獲取裏面的數據,而後進行繪圖。web

let analyser = audioCtx.createAnalyser();
    //頻域的FFT大小,默認是2048
    analyser.fftSize;
    //fftSize的一半
    analyser.frequencyBinCount;
    //快速傅立葉變化的最大範圍的雙精度浮點數
    analyser.maxDecibels;
    //最後一個分析幀的平均常數
    analyser.smoothingTimeConstant;
    //將當前頻域數據拷貝進Float32Array數組
    analyser.getFloatFrequencyData()
    //將當前頻域數據拷貝進Uint8Array數組
    analyser.getByteFrequencyData()
    將當前波形,或者時域數據拷貝進Float32Array數組
    analyser.getFloatTimeDomainData()
    //將當前波形,或者時域數據拷貝進 Uint8Array數組
    analyser.getByteTimeDomainData()

createGain

這個簡單到極點。。。canvas

let gainNode = audioCtx.createGain();
//修改value的大小,改變輸出大小,默認是1,0表示靜音
gainNode.gain.value = 1

createScriptProcessor

緩衝區音頻處理模塊,這個是咱們作直播的核心模塊,沒有這個模塊就作不到音頻流的轉發,音頻數據的延遲在除開網絡的影響下,這個模塊也佔一部分,固然要看本身的配置。AudioBuffer介紹segmentfault

/*
    第一個參數表示每一幀緩存的數據大小,能夠是256, 512, 1024, 2048, 4096, 8192, 16384,
      值越小一幀的數據就越小,聲音就越短,onaudioprocess 觸發就越頻繁。
      4096的數據大小大概是0.085s,就是說每過0.085s就觸發一次onaudioprocess,
      若是我要把這一幀的數據發送到其餘地方,那這個延遲最少就是0.085s,
      固然還有考慮發送過去的電腦處理能力,通常1024以上的數字,若是有變態需求的256也是能夠考慮的
    第二,三個參數表示輸入幀,和輸出幀的通道數。這裏表示2通道的輸入和輸出,固然我也能夠採集1,4,5等通道
*/
let recorder = audioCtx.createScriptProcessor(4096, 2, 2);
/*
  緩存區觸發事件,鏈接了createScriptProcessor這個AudioNode就須要在onaudioprocess中,
  把輸入幀的數據,鏈接到輸出幀,揚聲器纔有聲音
*/
recorder.onaudioprocess = function(e){
    let inputBuffer = e.inputBuffer, //輸入幀數據,AudioBuffer類型
        outputBuffer = e.outputBuffer; //輸出幀數據, AudioBuffer類型
     //第一種方式
     //將inputBuffer第0個通道的數據,複製到outputBuffer的第0個通道,偏移0個字節
     outputBuffer.copyToChannel(inputBuffer.getChannelData(0), 0, 0);
     //將inputBuffer第1個通道的數據,複製到outputBuffer的第1個通道,偏移0個字節
     outputBuffer.copyToChannel(inputBuffer.getChannelData(1), 1, 0);
     //第二中方式用循環
     for (var channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
          let inputData = inputBuffer.getChannelData(channel),
              outputData = outputBuffer.getChannelData(channel);
           for (var sample = 0; sample < inputBuffer.length; sample++) {
               outputData[sample] = inputData[sample];      
           }
        }
}

舉個栗子

下面我用input=file選擇一個本地音樂舉個栗子,採用哪一種音頻看本身喲api

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title></title>
    <link rel="stylesheet" href="">
</head>
<body>
    <canvas width="500px" height="500px">
        
    </canvas>
    <input type="file" name="" value="" placeholder="">
    <button type="button" class="add">音量+</button>
    <button type="button" class="lost">音量-</button>
</body>
<script type="text/javascript" charset="utf-8">
    let fileInput = document.querySelector('input'),
        add = document.querySelector('.add'), //音量+
        lost = document.querySelector('.lost'), //音量-
        audioCtx = new window.AudioContext, //建立環境
        analyser = audioCtx.createAnalyser(), //analyser分析器
        gainNode = audioCtx.createGain(), //控制音量大小
        recorder = audioCtx.createScriptProcessor(4096, 2, 2), //緩衝區音頻處理模塊
        canvas = document.querySelector('canvas'),
        canvasCtx = canvas.getContext('2d');
    fileInput.onchange = function(ev){
        let file = ev.target.files[0],
        fr = new FileReader();
        fr.readAsArrayBuffer(file);
        fr.onload = function(data){
            let result = data.target.result;
            //解碼ArrayBuffer
            audioCtx.decodeAudioData(result, getBuffer);
        };
    };

    //修改音量大小
    add.onclick = function(){
        gainNode.gain.value += 0.1;
    };
    lost.onclick = function(){
        gainNode.gain.value -= 0.1;
    }

    function getBuffer(audioBuffer){
        //建立對象,用過AudioBuffer對象來播放音頻數據
        let source  = audioCtx.createBufferSource();
        source.buffer = audioBuffer;
        //將source與analyser分析器鏈接
        source.connect(analyser);
        //將analyser與gainNode分析器鏈接
        analyser.connect(gainNode);
        //音量控制器與輸出設備連接
        gainNode.connect(recorder);
        recorder.connect(audioCtx.destination);
        //播放
        source.start(0); 
        draw(analyser);
        //音頻採集
        recorder.onaudioprocess = function (e) {
            /*輸入流,必需要連接到輸出流,audioCtx.destination纔能有輸出*/
              let inputBuffer = e.inputBuffer, outputBuffer = e.outputBuffer;
                outputBuffer.copyToChannel(inputBuffer.getChannelData(0), 0, 0);
                outputBuffer.copyToChannel(inputBuffer.getChannelData(1), 1, 0);
        };
    }
    let WIDTH = 500, HEIGHT = 500;
    //繪製波形圖
    function draw() {
        requestAnimationFrame(draw);
        //保存頻率數據
      let dataArray = new Uint8Array(analyser.fftSize),
          bufferLength = analyser.fftSize;
      //獲取頻域的輸出信息 
      analyser.getByteTimeDomainData(dataArray);
      canvasCtx.fillStyle = 'rgb(200, 200, 200)';
      canvasCtx.fillRect(0, 0, 500, 500);

      canvasCtx.lineWidth = 2;
      canvasCtx.strokeStyle = 'rgb(0, 0, 0)';

      canvasCtx.beginPath();

      var sliceWidth = WIDTH * 1.0 / bufferLength;
      var x = 0;

      for(var i = 0; i < bufferLength; i++) {
   
        var v = dataArray[i] / 128.0;
        var y = v * HEIGHT/2;

        if(i === 0) {
          canvasCtx.moveTo(x, y);
        } else {
          canvasCtx.lineTo(x, y);
        }

        x += sliceWidth;
      }

      canvasCtx.lineTo(canvas.width, canvas.height/2);
      canvasCtx.stroke();
    };
</script>
</html>

圖片描述

結束語

基本上咱們要用到的api都介紹完了,我想你們應該知道如何作音頻轉發了吧。下面一章就開始介紹音頻流的轉發了。
HTML5音頻API Web Audio這一篇文章仍是能夠看看的。
但願你們多多支持,收藏點贊呀數組

相關文章
相關標籤/搜索