簡體   English   中英

實時處理網絡音頻API

[英]real-time processing web audio api

我正在使用web audio api和requestAnimationFrame來可視化麥克風的音頻輸入。 我可以成功地可視化時域頻率數據,但問題在於,由於web audio api以秒為單位計算時間,因此我的界面每秒都會根據輸入的變化而變化。

所以我的問題是,我如何可視化聲音並使圖形保持在屏幕上,因此我可以在一定時間內看到我的所有頻率數據(假設我說話,同時在畫布上可視化僅5秒)。

我使用以下代碼(從這里的例子中獲取):

MicrophoneSample.prototype.visualize = function() {
  this.canvas.width = this.WIDTH;
  this.canvas.height = this.HEIGHT;
  var drawContext = this.canvas.getContext('2d');

  var times = new Uint8Array(this.analyser.frequencyBinCount);
  this.analyser.getByteTimeDomainData(times);
  for (var i = 0; i < times.length; i++) {
    var value = times[i];
    var percent = value / 256;
    var height = this.HEIGHT * percent;
    var offset = this.HEIGHT - height - 1;
    var barWidth = this.WIDTH/times.length;
    drawContext.fillStyle = 'purple';
    drawContext.fillRect(i * barWidth, offset, 1, 1);

  }
  requestAnimFrame(this.visualize.bind(this));

}

getByteTimeDomainData不會為您提供頻率信息。 這些是實時的時域波形值,也稱為幅度值。 如果要隨着時間的推移將它們可視化,請將值附加到數組中並繪制它。 如果您想要實際頻率值,請使用getByteFrequencyData。

OP,這里有一些偽代碼。 僅供參考,這真的不是一個網絡音頻問題,而是一個動畫問題。

在可視化器原型函數中存儲一個變量/字段,該函數可以跟蹤您想要延遲重繪畫布的秒數,保留一個單獨的計數器,每當requestAnimFrame(...)被繪制時它將遞增。 計數器達到延遲量后,重新繪制畫布。

編輯現在,我想到了......解決方案應該非常簡單。 如果我錯了,請糾正我,但是這個粗略的解決方案是假設您在動畫循環中調用MicrophoneSample.visualize()...因此,其中的代碼每秒執行一次。 如果您發布MicrophoneSample對象代碼,或者至少是您的動畫循環,我可以提供更多幫助。

/* NOTE!
*
*/
// Find a way to put these into your PARENT MicrophoneSample object
var delay = 5;
// Note that I am setting delayCount initially to zero - during the loop
// the delayCount will actually get reset to 1 from thereafter (not 0)...
// this gives us a way to initially draw your visualization on the first frame.
var delayCount = 0;

// Pull var times out so it doesn't get calculated each time.
var times = new Uint8Array(MicrophoneSample.analyser.frequencyBinCount);

// Same goes for the canvas...
// I would set these values inside of the PARENT MicrophoneSample object
MicrophoneSample.canvas.width = this.WIDTH;
MicrophoneSample.canvas.height = this.HEIGHT;

// you only need to establish the drawing context once. Do it in the PARENT
// MicrophoneSample object
var drawContext = this.canvas.getContext('2d');

MicrophoneSample.prototype.visualize = function() {

      /*
      *    NOTE!
      */
      // Here's the juicy meat & potatoes:
      // only if the delayCount reaches the delay amount, should you UPDATE THE
      // TIME DOMAIN DATA ARRAY (times)
      // if your loop runs every second, then delayCount increments each second
      // and after 5 seconds will reach your designated delay amount and update your
      // times array.

      if(delayCount == 0 || delayCount == delay) {
          this.analyser.getByteTimeDomainData(times);

          // Now, it would be redundant (and totally noob-programmer of you) to 
          // redraw the same visualization onto the canvas 5 times in a row, so
          // only draw the visualization after the first pass through the loop and then
          // every 5th pass after that :]
          for (var i = 0; i < times.length; i++) {
              var value = times[i];
              var percent = value / 256;
              var height = this.HEIGHT * percent;
              var offset = this.HEIGHT - height - 1;
              var barWidth = this.WIDTH/times.length;
              drawContext.fillStyle = 'purple';
              drawContext.fillRect(i * barWidth, offset, 1, 1);
          }

          // Note: 1, not 0!
          delayCount = 1;
      } 
      else {
          delayCount++;
      } 


      requestAnimFrame(this.visualize.bind(this));
}

請記住,我實際上沒有測試過這些。 但它至少應該指向正確的方向。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM