在Javascript中绘制可缩放的音频波形时间线

问题描述 投票:0回答:4

我有来自歌曲的原始 44,1 kHz 音频数据作为 Javascript 数组,我想用它创建一个可缩放的时间线。

Audacity 的时间表示例:

Sample waveform from Audacity

由于有数百万个时间点,普通的 Javascript 图形库可能无法消除它:我认为,不确定,普通的图形库会在这么多时间点上死亡。但是是否已经存在用于 JS 可视化的库? Canvas、webGL、SVG 都是可接受的解决方案。

最好具有缩放和平移的解决方案。

请注意,这种情况仅发生在客户端,服务器端解决方案是不可接受的。

javascript graph html5-canvas
4个回答
3
投票

我已经非常广泛地研究了同样的问题。据我所知,唯一接近您想要的现有项目是wavesurfer.js。我还没有使用过它,但屏幕截图和描述听起来很有希望。

另请参阅这个问题

祝你好运。


3
投票

你不能简单地获取波形数据并渲染所有数据点,这是非常低效的。

变量解释:

  • width:绘制区域宽度(以像素为单位),最大值为屏幕宽度
  • height:与宽度相同,但绘制区域的高度
  • spp:每像素的样本,这是您的缩放级别
  • 分辨率:每个像素样本范围采集的样本数,调整性能与准确性。
  • scroll:您需要虚拟滚动来提高性能,这是以 px 为单位的滚动位置
  • data:原始音频数据数组,可能有几百万个样本长
  • drawData:用于绘制的缩减音频数据

您只需从音频数据中获取视口中的样本并减少这些样本。通常,这会产生 2 * 宽度的数据集,您可以使用该数据集来渲染图像。 要缩小,请增加 spp,要放大,请减少它。更改滚动值会平移它。

以下代码的复杂度为 O(RN),其中 N 是宽度,R 是分辨率。最大精度为 spp <= resolution.

代码看起来像这样,这会得到峰值,你也可以做均方根或平均值。

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);
   }
} 

0
投票

我使用了RaphaelJS在浏览器中进行SVG渲染,它的表现非常好。这就是我想要的。希望 SVG 能够胜任这项任务。


0
投票

如果您碰巧有原始录音,您可以将其扔到peaks.js

对于您的 javascript 数组,您可以尝试他们描述的内部内容并使用他们的库 konva 和 waveform-data

关于waveform-data.js:

waveform-data.js 是一个用于创建可缩放的 JavaScript 库 音频波形的表示以实现音频可视化 内容。

这似乎正是您正在寻找的。

© www.soinside.com 2019 - 2024. All rights reserved.