您不能简单地获取波形数据并渲染所有数据点,这是非常低效的。
变量解释:
-
width:以像素为单位绘制区域宽度,最大为屏幕宽度
-
高度:与宽度相同,然后是绘图区域的高度
-
spp:每个像素的样本数,这是您的缩放级别
-
分辨率:每个像素样本范围内的样本数,针对性能与准确性进行调整。
-
滚动:您需要虚拟滚动以提高性能,这是以像素为单位的滚动位置
-
data:原始音频数据数组,可能有几百万个样本长度
-
drawData:用于绘制的压缩音频数据
您将只需要从音频数据中获取视口中的样本并减少这些样本。通常这会产生一个 2 * 宽度的数据集,您可以使用此数据集来渲染图像。
缩小增加spp,放大减少spp。更改滚动值会对其进行平移。
以下代码具有 O(RN) 复杂度,其中 N 是宽度,R 是分辨率。最大精度为 spp
代码看起来像这样,它得到峰值,你也可以做 rms 或平均值。
let reduceAudioPeak = function(data, spp, scroll, width, resolution) {
let drawData = new Array(width);
let startSample = scroll * spp;
let skip = Math.ceil(spp / resolution);
// For each pixel in draw area
for (let i = 0; i < width; i++) {
let min = 0; // minimum value in sample range
let max = 0; // maximum value in sample range
let pixelStartSample = startSample + (i * spp);
// Iterate over the sample range for this pixel (spp)
// and find the min and max values.
for(let j = 0; j < spp; j += skip) {
const index = pixelStartSample + j;
if(index < data.length) {
let val = data[index];
if (val > max) {
max = val;
} else if (val < min) {
min = val;
}
}
}
drawData[i] = [min, max];
}
return drawData;
}
有了这些数据,你可以像这样绘制它,你可以使用线条、svg 等:
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);
for(let i = 0; i < width; i++) {
// transform data points to pixel height and move to centre
let minPixel = drawData[i][0] * drawHeigth + drawHeight;
let maxPixel = drawData[i][1] * drawHeight + drawHeight;
let pixelHeight = maxPixel - minPixel;
ctx.fillRect(i, minPixel, 1, pixelHeight);
}
}