【问题标题】:real-time processing web audio api实时处理网络音频api
【发布时间】:2013-04-01 19:24:25
【问题描述】:

我正在使用网络音频 api 和 requestAnimationFrame 来可视化来自麦克风的音频输入。我可以成功地将时域频率数据可视化,但问题是由于网络音频 api 以秒为单位计算时间,所以我的界面每秒都会根据输入的内容而变化。

所以我的问题是,我怎样才能可视化声音并使图表留在屏幕上,这样我就可以在一定的时间内看到我的所有频率数据(假设我说话同时在画布上可视化只有 5 秒)。

我正在使用以下代码(取自示例here):

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));

}

【问题讨论】:

  • Rq :调整画布大小/在每次调用时获取上下文是一种过度杀伤:执行一次并存储 ctx。不需要将声源连接到分析仪来获取频率吗?
  • 输入已经连接到分析仪,我也可以获取可以获取的波形值或其他声音属性。主要问题是如何使它们的可视化常驻?

标签: javascript html5-canvas html5-audio web-audio-api


【解决方案1】:

getByteTimeDomainData 不会为您提供频率信息。这些是实时的时域波形值,也称为幅度值。如果您想随着时间的推移将它们可视化,请将其附加到数组中并绘制它。如果您想要真实的频率值,请使用 getByteFrequencyData。

【讨论】:

  • 如果 getByteTimeDomainData 能够创建也有用的波形。这个例子已经可视化了输入,但正如我所说的,每秒钟图表都会消失。我怎样才能让它留在那里?
  • 正如我所说:将 times[i] 数据推送到您存储在 MicrophoneSample 类中的另一个数组中并绘制该数组。
【解决方案2】:

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));
}

请记住,我还没有实际测试过这些。但它至少应该为您指明正确的方向。

【讨论】:

  • 我尝试使用您的伪代码实现解决方案,但没有成功。不知道是因为我的编程能力还是……你能把代码写得更详细这里还是在PM中?谢谢哥们:)))
  • 好的,只是为了确保,你知道伪代码不是字面上使用的吗?只是为了首先解决这个问题:]
猜你喜欢
  • 1970-01-01
  • 2015-07-18
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 2013-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多