如何获取 AudioBufferSourceNode 当前时间?

How can I get an AudioBufferSourceNode's current time?

使用音频元素 (<audio>) 或上下文 (AudioContext) 时,您可以检查它们的 currentTime 属性 以准确了解缓冲区的播放时间.

在我在单个 AudioContext.

中创建多个源(或 AudioBufferSourceNode)之前,所有这些都很好,花花公子

源可以在不同时间播放,因此我需要知道它们对应的 currentTime,以说明:

一些供您使用的基本代码:

buffer1 = [0,1,0]; //not real buffers
buffer2 = [1,0,1];

ctx = new AudioContext();

source1 = ctx.createBufferSourceNode();
source1.buffer = buffer1;
source1.connect(ctx.destination);
source1.start(0);

source2 = ctx.createBufferSourceNode();
source2.buffer = buffer2;
source2.connect(ctx.destination);
setTimeout(1000/*some time later*/){
    source2.start(0);
}

setTimeout(1500/*some more time later*/){
    getCurrentTime();
}

function getCurrentTime(){
    /* magic */
    /* more magic */
    console.log("the sources currentTime values are obviously 1500 (source1) and 500 (source2).");
}

我通常做的是为跟踪播放状态的音频源节点创建一个包装器。我尽量减少下面的代码以显示基础知识。

核心思想是跟踪声音开始的时间和声音的时间 'paused' 并使用这些值获取当前时间并从暂停位置恢复播放。

我放了一个working example on codepen

function createSound(buffer, context) {
    var sourceNode = null,
        startedAt = 0,
        pausedAt = 0,
        playing = false;

    var play = function() {
        var offset = pausedAt;

        sourceNode = context.createBufferSource();
        sourceNode.connect(context.destination);
        sourceNode.buffer = buffer;
        sourceNode.start(0, offset);

        startedAt = context.currentTime - offset;
        pausedAt = 0;
        playing = true;
    };

    var pause = function() {
        var elapsed = context.currentTime - startedAt;
        stop();
        pausedAt = elapsed;
    };

    var stop = function() {
        if (sourceNode) {          
            sourceNode.disconnect();
            sourceNode.stop(0);
            sourceNode = null;
        }
        pausedAt = 0;
        startedAt = 0;
        playing = false;
    };

    var getPlaying = function() {
        return playing;
    };

    var getCurrentTime = function() {
        if(pausedAt) {
            return pausedAt;
        }
        if(startedAt) {
            return context.currentTime - startedAt;
        }
        return 0;
    };

    var getDuration = function() {
      return buffer.duration;
    };

    return {
        getCurrentTime: getCurrentTime,
        getDuration: getDuration,
        getPlaying: getPlaying,
        play: play,
        pause: pause,
        stop: stop
    };
}

旧线程 (非常有用!谢谢!),但也许值得一提的是 而不是

function update() {
    window.requestAnimationFrame(update);
    info.innerHTML = sound.getCurrentTime().toFixed(1) + '/' + sound.getDuration().toFixed(1);
    }
update(); 

使用 createScriptProcessor 可能更精确,占用资源更少 就像 this post

中解释的那样
const audioBuffer = await audioContext.decodeAudioData(response.data);
const chan = audioBuffer.numberOfChannels;
const  scriptNode = audioContext.createScriptProcessor(4096, chan, chan);
scriptNode.connect(audioContext.destination);
scriptNode.onaudioprocess = (e) => {

  // ---> audio loop <----

};

[更新]

注意:截至 2014 年 8 月 29 日网络音频 API 规范发布,此功能已被标记为已弃用,并被 AudioWorklet 取代(请参阅 AudioWorkletNode)。 https://developers.google.com/web/updates/2017/12/audio-worklet