2

我试图将音频缓冲区的波形数据可视化为 html5 画布。

我曾经buffer.getChannelData(0)获取每个样本的值。然后我使用 for 循环将每个样本值绘制到缓冲区。

它现在可以工作,但问题是它使用每个像素作为样本,这意味着它需要 44100 像素大小的画布来绘制一秒钟的音频。

这是我用来绘制的代码:

for (var i = 0; i < data.length; i++) {

ctx.fillStyle = 'black';
ctx.fillRect(i, height / 2, 0.5, (data[i] * height));
        }

你可以在这里看到整个代码 http://jsfiddle.net/ehsanziya/KKNFL/1/

canvas.width每次加载缓冲区时,我如何缩放它以使其适合根据加载的缓冲区大小?

谢谢

4

5 回答 5

3

假设您的画布宽度为 500,音频长度为 60 秒,采样率为 44100 kHz...

您需要做的是弄清楚有多少样本将代表画布上的单个像素。要做到这一点,你基本上说var binSize = ( audioBuffer.duration * 44100 ) / 500;

现在您遍历所有样本并将它们分组为binSize长度部分。对于每个 bin,您找到最大值并将其推入一个数组。完成后,您将拥有一个包含 500 个值的数组,可用于绘制到画布中。

于 2013-07-03T18:32:36.350 回答
1

我为此编写了一个示例库:https ://github.com/cwilso/Audio-Buffer-Draw 。

于 2013-07-05T15:35:11.450 回答
1

我已经修改了您的 JSFiddle 并在此处发布了一个分支:

http://jsfiddle.net/jjDpm/4/

这是关键行:

ctx.lineTo(i, height/2 + data[step*i] * amp);

X 轴上的缩放问题通过提出一个“步长”因子然后使用它以适当的速率移动数据来解决。这个想法是您将无法绘制每个数据点的图表,但您实际上将绘制数据中均匀(步长)间隔的一组样本。

于 2013-07-03T22:22:43.873 回答
0

我编写了一个简单的 ADSR 合成器,允许用户输入仪器的参数,然后将其合成,使其数据可用于可视化或回放。我也使用了 44100 赫兹。

获得好看图像的关键是要意识到您不想为每个水平像素只绘制一次,而是为每个样本绘制一次。对于 0.2 秒的样本和 256 像素宽的画布,您需要将 8,820 个样本放入 256 像素中 - 每像素约 34 个样本。这似乎有点矫枉过正,但这是获得不会丢失数据的可视化的唯一方法。这也是获得类似于声音编辑程序中的图像的方法,例如 Audacity、Milkytracker 等。

这是一个踩镲鼓,Fmax > 10,000 Hz 踩镲鼓的可视化 - Fmax = > 10,000 Hz

编辑:添加图像以显示调用 closePath 不会添加从端点回到起点的线。

在此处输入图像描述

这是我使用的可视化代码:

function drawFloatArray(samples, canvas)
{
    var i, n = samples.length;
    var dur = (n / 44100 * 1000)>>0;
    canvas.title = 'Duration: ' +  dur / 1000.0 + 's';

    var width=canvas.width,height=canvas.height;
    var ctx = canvas.getContext('2d');
    ctx.strokeStyle = 'yellow';
    ctx.fillStyle = '#303030';
    ctx.fillRect(0,0,width,height);
    ctx.beginPath();
    ctx.moveTo(0,height/2);
    for (i=0; i<n; i++)
    {
        x = ( (i*width) / n);
        y = ((samples[i]*height/2)+height/2);
        ctx.lineTo(x, y);
    }
    ctx.stroke();
    ctx.closePath();
    canvas.mBuffer = samples;
    canvas.onclick = function() { playSound(this.mBuffer, 44100, 50); };
}
于 2013-07-04T00:54:18.647 回答
0

由enhzflep编写的解决方案是正确的方法,但是对于具有大音频缓冲区数组的音频文件,您需要在迭代音频数组的缓冲区长度时对处理进行分块,以防止浏览器崩溃。与其使用 setTimeout,不如将变量设置为可以在块处理完成后检查的值。我这样做的方式是这样的:

 function processChunk(ctx, cwidth, cheight){

    var chsize = 6000;
    var index=0;
    var chComplete;

    function doChunk(){

        var chunk = chsize;

        while(chunk-- && index<data.length){

            var x = (index*cwidth)/data.length;
            var y = ((data[index]*cheight/2)+cheight/2)
            ctx.lineTo(x,y);
            index++;
            chComplete=1;

        }

        chComplete=0;

        if(index < data.length){

            function checkChunk(){
                if(chComplete==0){
                    doChunk()
                    console.log('chunking');
                }else{

                    setTimeout(checkChunk(), 500);  
                }
            }

            checkChunk();
        }


    }

    doChunk();

}
于 2015-04-28T10:07:33.727 回答