您的渲染代码效率极低,因为它将为每秒的音频渲染 44100 像素。您希望最好使用减少的数据集渲染最多视口宽度。
可以使用 audioDurationSeconds * samplerate / viewPortWidthPx 计算适合视口中波形所需的每像素采样范围。因此,对于 1000 像素的视口和 2 秒的音频文件,采样率为 44100,每个像素的样本数 = (2 * 44100) / 1000 = ~88。
对于屏幕上的每个像素,您可以从该样本范围中获取最小值和最大值,然后使用这些数据来绘制波形。
这是一个示例算法,它允许您将每个像素的样本作为参数以及滚动位置以允许虚拟滚动和缩放。它包括一个可以调整性能的分辨率参数,这表明每个像素样本范围应该采用多少样本:
Drawing zoomable audio waveform timeline in Javascript
那里的draw方法和你的类似,为了平滑它你需要使用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
}