我正在使用web audio 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));
}
答案 0 :(得分:2)
getByteTimeDomainData不会为您提供频率信息。这些是实时的时域波形值,也称为幅度值。如果要随着时间的推移将它们可视化,请将值附加到数组中并绘制它。如果您想要实际频率值,请使用getByteFrequencyData。
答案 1 :(得分: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));
}
请记住,我实际上没有测试过这些。但它至少应该指向正确的方向。