首页 > 解决方案 > 改善可视化器外观

问题描述

我对这段代码如何使用画布和getByteFrequencyData. https://share.getcloudapp.com/Kou7AJb1

条形似乎太大了,我认为这是因为 FFT(快速傅立叶变换)数组包含广泛的数据,但在我的代码中,我根据画布的宽度生成 n 个条形。

然后在拥有 n 个柱之后,我将 FFT 映射到柱的相同索引,而忽略了许多有用的信息。

function convertRange(value: any, r1: any, r2: any) {
  return ((value - r1[0]) * (r2[1] - r2[0])) / (r1[1] - r1[0]) + r2[0];
}

// line up and down
const drawVisualizer2 = ({ canvas, frameData, background }: any) => {
  const ctx = canvas.getContext("2d");
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // TODO: Improve?
  const bars = Math.round(canvas.width) / 15 - 1;
  const max_of_array = Math.max.apply(Math, frameData.fft);

  for (let i = 0; i < bars; i++) {
    const height = convertRange(frameData.fft[i], [0, max_of_array], [0, canvas.height / 2 - 20]);
    const centerY = canvas.height / 2;

    // draw the bar
    ctx.strokeStyle = background ? background.colors[0] : "#ffffff";
    ctx.lineWidth = 10;
    ctx.lineCap = "round";

    ctx.beginPath();
    ctx.moveTo((i + 1) * 15, centerY);
    ctx.lineTo((i + 1) * 15, centerY + height);
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo((i + 1) * 15, centerY);
    ctx.lineTo((i + 1) * 15, centerY - height);
    ctx.stroke();
  }
};

export default drawVisualizer2;

我认为需要做的是根据循环中的条数对 FFT 进行平均。如果这是有道理的,那么实现这一目标的实用方法是什么?

我希望这是有道理的,如果需要,很高兴澄清。

标签: javascriptaudiocanvasfft

解决方案


我假设这frameData.fft是包含该AnalyserNode.getByteFrequencyData()方法返回的实际频率数据的 Uint8Array。

您的假设是正确的-条形图的数量当然与存储在数组中的项目数不匹配,并且带有类似的循环

for (let i = 0; i < bars; i++) {
...
frameData.fft[i]
...
}

您只是使用从零到条数的前几个值,并最终跳过整个数组的其余部分。

修复非常简单:

不是以 1 的间隔从数组中获取值,间隔必须是数组中元素的数量除以条形的数量。然后将该数字乘以ifor 循环内的变量并四舍五入,因为除法可能会导致十进制数,并且数组的元素位于整数位置。

这是一个例子:

let frameData = {
  fft: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
};
let bars = 5;
let steps = frameData.fft.length / bars;
for (let i = 0; i < bars; i++) {
  console.log(frameData.fft[Math.round(i * steps)]);
}


推荐阅读