javascript 用于可视化波形并与波形交互的 Web 音频

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9516324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 06:56:51  来源:igfitidea点击:

Web Audio to visualize and interact with waveforms

javascripthtmlcanvasweb-audio-api

提问by katspaugh

How do I write a JavaScript program to display a waveform from an audio file? I want to use Web Audio and Canvas.

如何编写 JavaScript 程序来显示音频文件中的波形?我想使用网络音频和画布。

I tried this code:

我试过这个代码:

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

But the result is far from what I want (namely, the image is not smooth since I'm drawing with rectangles). I want it to look smooth like this image:

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

Waveform example

波形示例

Any hints on how to implement the waveform?

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

采纳答案by Vadim Baryshev

You may be interested in AudioJedit. This is an open source project hosted at GitHub. It have small server-side node.js script for loading audio files, but all interaction with audio implemented in client-side JavaScript. I think this is similar to what you are looking for.

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

回答by katspaugh

Rolled out my own library after all: wavesurfer.js.

毕竟推出了我自己的库:wavesurfer.js

It draws a waveform from PCM data and seeks regions of the audio by clicking on it.

它从 PCM 数据中绘制一个波形,并通过点击它来寻找音频的区域。

Imgur

伊格

回答by vectorsize

For a (hopefully) simple use and integration of a waveform with your app you might want to check what we are doing at IRCAM, specially the waveform-vis in this particular case.

为了(希望)简单地使用和将波形与您的应用程序集成,您可能需要检查我们在 IRCAM 上所做的工作,特别是在这种特殊情况下的波形可视化。

It's all open source and aimed for modularity (and work in progress)

它都是开源的,旨在实现模块化(并且正在进行中)

You can find a demo over here
And the corresponding githug repository

你可以在这里找到一个demo
和相应的github 仓库

回答by David Sherman

Your render code is extremely inefficient because it will render 44100 pixels for each second of audio. You want to preferably render at most the viewport width with a reduced data set.

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

The per pixel sample range needed to fit the waveform in the viewport can be calculated with audioDurationSeconds * samplerate / viewPortWidthPx. So for a viewport of 1000px and an audio file of 2 second at 44100 samplerate the samples per pixel = (2 * 44100) / 1000 = ~88. For each pixel on screen you take the min and max value from that sample range, you use this data to draw the waveform.

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

Here is an example algorithm that does this but allows you to give the samples per pixel as argument as well as a scroll position to allow for virtual scroll and zooming. It includes a resolution parameter you can tweak for performance, this indicates how many samples it should take per pixel sample range: Drawing zoomable audio waveform timeline in Javascript

这是一个执行此操作的示例算法,但允许您将每个像素的样本作为参数以及滚动位置以允许虚拟滚动和缩放。它包括一个分辨率参数,您可以调整性能,这表明每个像素样本范围应该采用多少样本: 在 Javascript 中绘制可缩放音频波形时间线

The draw method there is similar to yours, in order to smooth it you need to use lineTo instead of fillRect.This difference shouldn't actually be that huge, I think you might be forgetting to set the width and height attributes on the canvas. Setting this in css causes for blurry drawing, you need to set the attributes.

那里的 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
}