您的渲染代码效率极低,因为它将为每秒的音频渲染 44100 像素。您希望最好使用减少的数据集渲染最多视口宽度。
可以使用 audioDurationSeconds * samplerate / viewPortWidthPx 计算适合视口中波形所需的每像素采样范围。因此,对于 1000 像素的视口和 2 秒的音频文件,采样率为 44100,每个像素的样本数 = (2 * 44100) / 1000 = ~88。对于屏幕上的每个像素,您从该样本范围中获取最小值和最大值,然后使用此数据绘制波形。
这是一个执行此操作的示例算法,但允许您将每个像素的样本作为参数以及滚动位置以允许虚拟滚动和缩放。它包括一个可以调整性能的分辨率参数,这表明每个像素样本范围应该采用多少样本:
在 Javascript 中绘制可缩放的音频波形时间线
那里的绘制方法与您的相似,为了使其平滑,您需要使用lineTo而不是fillRect。这个差异实际上应该没有那么大,我想您可能忘记在画布上设置宽度和高度属性。在 css 中设置此项会导致绘图模糊,您需要设置属性。
let drawWaveform = function(canvas, drawData, width, height) {
let ctx = canvas.getContext('2d');
let drawHeight = height / 2;
// clear canvas incase there is already something drawn
ctx.clearRect(0, 0, width, height);
ctx.beginPath();
ctx.moveTo(0, drawHeight);
for(let i = 0; i < width; i++) {
// transform data points to pixel height and move to centre
let minPixel = drawData[i][0] * drawHeigth + drawHeight;
ctx.lineTo(i, minPixel);
}
ctx.lineTo(width, drawHeight);
ctx.moveTo(0, drawHeight);
for(let i = 0; i < width; i++) {
// transform data points to pixel height and move to centre
let maxPixel = drawData[i][1] * drawHeigth + drawHeight;
ctx.lineTo(i, maxPixel);
}
ctx.lineTo(width, drawHeight);
ctx.closePath();
ctx.fill(); // can do ctx.stroke() for an outline of the waveform
}