【问题标题】:Drawing zoomable audio waveform timeline in Javascript在 Javascript 中绘制可缩放的音频波形时间线
【发布时间】:2017-11-17 21:03:31
【问题描述】:

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

Audacity 的时间线示例:

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

最好使用缩放和平移的解决方案。

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

【问题讨论】:

  • 您不能简单地通过将幅度值放入图形库并希望它能够解决这个问题来解决这个问题。您需要为缩小的数据创建“概览”或“预览”。
  • 因此,我想问这样的解决方案是否已经存在?我很清楚当前的图形库无法处理它。
  • 创建概览并非难事。这样的库可能存在,但大部分麻烦在于将数据进出库,而不是实际创建概览。

标签: javascript graph html5-canvas


【解决方案1】:

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

另见this question

祝你好运。

【讨论】:

    【解决方案2】:

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

    变量解释:

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

    【讨论】:

    • 您能否提供更多详细信息如何使用它?
    • @Toniq 你想要什么细节?我创建了一个库,用于在多个轨道上渲染音频片段,如果您对如何实现它感兴趣,可以在这里找到。 github.com/Idicious/waveshaper
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2022-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-03
      • 1970-01-01
      • 2016-06-14
      • 1970-01-01
      相关资源
      最近更新 更多