如何在Web音频中循环播放WAV一定次数?

时间:2019-10-07 03:02:15

标签: javascript web-audio-api

我知道AudioBufferSourceNode上有一个选项loop=true。但是我只想重复几次wav。例如,如何重复两次?

var url  = 'main.wav';

var context = new AudioContext();
var source = context.createBufferSource();

source.connect(context.destination);

var request = new XMLHttpRequest();
request.open('GET', url, true); 
request.responseType = 'arraybuffer';
request.onload = function() {
    context.decodeAudioData(request.response, function(response) {

        source.buffer = response;

        source.start(0);
        source.start(source.buffer.duration); // doesn't work "cannot call start more than once."
        //source.loop = true; // this is infinite amount of times, not good

    }, function () { console.error('The request failed.'); } );
}
request.send();

我还尝试创建第二个缓冲区:

var source2 = context.createBufferSource();

// inside callback
source2.buffer = response; // same response so I don't need to load this separately
source2.start(source.buffer.duration); // doesn't work

但是那也不起作用。有什么想法吗?

4 个答案:

答案 0 :(得分:1)

一种解决方案是允许loop的{​​{1}}行为,然后在允许播放声音文件的时间段后安排对source播放源的回调多次:

stop()

答案 1 :(得分:1)

您可以将AudioBufferSource的loop设置为true并调用

source.stop( ctx.currentTime + audioBuffer.duration * repeatTime )

(async () => {  
  const url = 'https://dl.dropboxusercontent.com/s/1cdwpm3gca9mlo0/kick.mp3';
  const buf = await fetch( url ).then( (r) => r.arrayBuffer() );
  const ctx = new AudioContext();
  const audioBuffer = await ctx.decodeAudioData( buf );
  
  btn.onclick = (e) => {
    const source = ctx.createBufferSource();
    source.buffer = audioBuffer;
    source.loop = true;
    source.connect( ctx.destination );
    source.start( 0 );
    source.stop( ctx.currentTime + audioBuffer.duration * inp.valueAsNumber );
  };
  btn.disabled = false;
})().catch( console.error );
<label> repeat<input id="inp" type="number" min="1" max="20" value="5"></label>
<button id="btn" disabled>start</button>

答案 2 :(得分:1)

您使用第二个缓冲区的方法几乎是正确的。您只需要使用绝对的开始时间,而不是相对的。要获取绝对时间总和,音频上下文的当前时间和声音持续时间:

// Play first sound now
var source1 = context.createBufferSource();
source1.buffer = response;
source1.start(context.currentTime);  // This is the same as source1.start();

// Play second sound with a delay
var source2 = context.createBufferSource();
source2.buffer = response;
source2.start(context.currentTime + response.duration);

这种方法提供了无间隙的播放(如果文件没有间隙)。

您可以将其包装为一个简单的函数:

function play(context, buffer, delay=0) {
    var source = context.createBufferSource();
    source.buffer = buffer;
    source.start(context.currentTime + delay);
    return source;
}

...

// Play the sound twice, one after another
play(context, response, 0);
play(context, response, response.duration);

答案 3 :(得分:1)

另一种替代方法是使用start()的3-arg版本。像这样:

let nReps = 2; /* Number of times to repeat the source */
let s = new AudioBufferSourceNode(context, 
             {buffer: buffer, loop: true});
s.start(startTime, 0, buffer.duration * nReps);