Web Audio可视化并与波形交互

时间:2012-03-01 12:32:34

标签: javascript html5 canvas web-audio

如何编写JavaScript程序以显示音频文件中的波形?我想使用Web Audio和Canvas。

我试过这段代码:

(new window.AudioContext).decodeAudioData(audioFile, function (data) {
   var channel = data.getChannelData(0);
   for (var i = 0; i < channel; i++) {
       canvas.getContext('2d').fillRect(i, 1, 40 - channel[i], 40);
   }
});

但是结果远非我想要的(即,由于我用矩形绘制,图像不平滑)。我希望它看起来像这张图像一样平滑:

Waveform example

有关如何实现波形的任何提示?

4 个答案:

答案 0 :(得分:41)

毕竟推出了我自己的图书馆: wavesurfer.js

它从PCM数据中绘制波形,并通过单击来搜索音频区域。

Imgur

答案 1 :(得分:9)

您可能对AudioJedit感兴趣。这是一个开源项目hosted at GitHub。它有用于加载音频文件的小型服务器端node.js脚本,但是在客户端JavaScript中实现了与音频的所有交互。我认为这与您所寻找的类似。

答案 2 :(得分:2)

对于(希望)简单使用和集成波形与您的应用程序,您可能想要检查我们在IRCAM上做了什么,特别是在这种特殊情况下的波形可见。

它是所有开源的,旨在模块化(并且正在进行中)

您可以找到demo over here
以及相应的githug repository

答案 3 :(得分:0)

您的渲染代码效率极低,因为它会为每秒音频渲染44100像素。您希望最好使用缩小的数据集渲染视口宽度。

可以使用audioDurationSeconds * samplerate / viewPortWidthPx计算在视口中拟合波形所需的每像素采样范围。因此,对于1000px的视口和44100采样率的2秒的音频文件,每像素的样本=(2 * 44100)/ 1000 = ~88。 对于屏幕上的每个像素,您可以从该样本范围中获取最小值和最大值,然后使用此数据绘制波形。

这是一个执行此操作的示例算法,但允许您将每个像素的样本作为参数以及滚动位置,以允许虚拟滚动和缩放。它包含一个可以调整性能的分辨率参数,这表示每个像素样本范围应采用的样本数量: this thread

那里的绘制方法与你的类似,为了平滑它你需要使用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
}