我知道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
但是那也不起作用。有什么想法吗?
答案 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);