【问题标题】:Analyser not updating canvas draws as quickly as audio is coming in分析器没有像音频进入一样快地更新画布绘制
【发布时间】:2014-03-03 15:09:49
【问题描述】:

每当我有一个新缓冲区进入我的客户端时,我想将该音频实例重绘到我的画布上。我从http://webaudioapi.com/samples/visualizer/ 获取示例代码并尝试对其进行更改以适应我在现场环境中的需求。我似乎有一些工作,因为当我调用 .draw() 时确实看到画布在更新,但它并没有达到应有的速度。我可能看到大约 1 fps。如何加快我的 fps 并仍然为新缓冲区的每个实例调用 draw?

完整代码: https://github.com/grkblood13/web-audio-stream/tree/master/visualizer

这是为每个缓冲区调用 .draw() 的部分:

function playBuffer(audio, sampleRate) {
    var source      = context.createBufferSource();
    var audioBuffer = context.createBuffer(1, audio.length , sampleRate);
    source.buffer   = audioBuffer;
    audioBuffer.getChannelData(0).set(audio);

    source.connect(analyser);
    var visualizer = new Visualizer(analyser);
    visualizer.analyser.connect(context.destination);
    visualizer.draw(); // Draw new canvas for every new set of data

    if (nextTime == 0) {
        nextTime = context.currentTime + 0.05;  /// add 50ms latency to work well across systems - tune this if you like
    }
    source.start(nextTime);

    nextTime+=source.buffer.duration; // Make the next buffer wait the length of the last buffer before being played
}

这是 .draw() 方法:

Visualizer.prototype.draw = function() {
    function myDraw() {
        this.analyser.smoothingTimeConstant = SMOOTHING;
        this.analyser.fftSize = FFT_SIZE;

        // Get the frequency data from the currently playing music
        this.analyser.getByteFrequencyData(this.freqs);
        this.analyser.getByteTimeDomainData(this.times);

        var width = Math.floor(1/this.freqs.length, 10);

        // Draw the time domain chart.
        this.drawContext.fillStyle = 'black';
        this.drawContext.fillRect(0, 0, WIDTH, HEIGHT);

        for (var i = 0; i < this.analyser.frequencyBinCount; i++) {
            var value = this.times[i];
            var percent = value / 256;
            var height = HEIGHT * percent;
            var offset = HEIGHT - height - 1;
            var barWidth = WIDTH/this.analyser.frequencyBinCount;
            this.drawContext.fillStyle = 'green';
            this.drawContext.fillRect(i * barWidth, offset, 1, 2);
        }
    }
    requestAnimFrame(myDraw.bind(this));
}

【问题讨论】:

    标签: javascript html streaming html5-canvas web-audio-api


    【解决方案1】:

    你有工作演示吗?因为您可以使用 chrome 中的时间轴轻松调试它。您可以找出哪些过程需要很长时间。也请去掉不必要的数学。您的大部分代码不需要每帧都执行。另外,从playBuffer 调用draw 函数多少次?当您调用 play 时,在该函数结束时,它会请求一个新的动画帧。如果您每次获得缓冲区时都调用 play,那么您将获得更多的 math-&gt;drawing-&gt;request frame 循环。这也使它非常缓慢。如果你已经在使用 requestanimationframe,你应该只调用一次播放函数。

    修复多帧问题:

    window.animframe = requestAnimFrame(myDraw.bind(this));
    

    在你的 playBuffer 上:

    if(!animframe) visualizer.draw();
    

    这确保它只在没有请求时执行播放功能。

    【讨论】:

      【解决方案2】:

      您有现场示例演示吗?我想通过一些分析来运行它。您正在尝试获取正在播放的音频的更新,而不仅仅是每个块一次,对吧?

      我看到了一些效率低下的地方:

      • 您复制数据的次数至少超过了必要的次数 - 您应该让 scheduleBuffers() 方法创建一个适当长度的 AudioBuffer,而不是随后需要转换的数组。

      • 如果我理解您的代码逻辑,它将为每个传入的块创建一个新的 Visualizer,尽管它们使用相同的分析器。我不确定你是否真的每次都想要一个新的 Visualizer - 事实上,我想你可能不想要。

      -您正在使用一个相当大的 fftSize,这对于频率分析可能是可取的,但在 2048/44100 时,您的采样超出了您的需要。不过是次要的。

      -我完全不确定你为什么要执行 getByteFrequencyData。

      -我认为额外的闭包可能会导致内存泄漏。这是我想通过开发工具运行它的原因之一。

      -您应该将 barWidth 定义连同 sn-p 长度一起移到循环之外:

      var snippetLength = this.analyser.frequencyBinCount;
      var barWidth = WIDTH/snippetLength;
      

      如果您可以发布一个显示 1fps 行为的现场演示,或私下向我发送一个 URL(cwilso at google 或 gmail),我很乐意看看。

      【讨论】:

      • 你问的关于每块一次的问题和一个演示让我重新思考我在这里实际上想要做什么。在编写代码时,我正在使用 PCM 音频进行本地测试。正因为如此,我的块很短,所以“每块一次”是我想要做的。如果我要设置一个现场演示,我将不得不添加压缩,然后我的块会变得更长。然后,“每块一次”的想法不合适,因为我仍然只能获得 1 fps,因为一个块的长度约为 1 秒。我需要的是一个可以改变刷新率的滑块,与块大小无关。
      猜你喜欢
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 2017-12-25
      • 2018-06-05
      • 1970-01-01
      • 2020-11-02
      相关资源
      最近更新 更多