Web Audio API - 调度问题

时间:2015-03-05 17:02:00

标签: javascript html5 web-audio synchronous sequencing

我正在尝试构建一个使用Web音频API和许多不同长度的不同音乐循环的循环音序器。一般的想法是循环被随机选择(在一定程度上),然后以特定顺序回放开始,中间和结束部分。有四个通道 - 低音,鼓,引导和FX。在最后一节结束之前,选择一组新样本并使用相同的公式进行回放。

然后我打算添加一个可视化器,也许还有一些自动化程序 - 也就是最后几个小节的混响。

我必须尝试遵循“两个时钟的故事”方法,但因为我对编程相对较新 - 而且对于javascript - 我很难实现它。我认为这可能会使事情变得比完成此事更复杂。

我最初的想法是使用play方法创建一个for循环,指定我想要循环播放的次数,但我发现样本将立即全部播放。根据“两个时钟的故事”,我尽量避免使用setTimeout()和setInterval(),因为它只会导致滞后。

我的第二个想法是立即调用所有的播放方法,除了每个都在“歌曲”中的某个点被提示,例如

START SECTION

playlead(time, buffer);

playdrums(time + length*2, buffer);

MIDDLE SECTION

playlead(time + length*10, buffer);

playdrums(time + length*10, buffer);

playlead2(time + length*10, buffer);

playbass(time + length*10, buffer);

等等。然而,这导致了它自己的一系列问题,并且似乎是一种相当低效的方法。

感觉可能缺少一个明显的解决方案,但经过相当多的研究,我仍然无法解决它。看起来最简单的事情就是让我的for循环中的playSound函数等待样本在再次迭代之前完成,但这比看起来要困难得多。如果有人能提出任何建议,我会非常感激,因为我最终会对此有所了解。提前谢谢!

//只是添加,我在第二种方法中遇到的问题是,为了实际上只是开始部分,代码必须看起来像这样才能玩约30秒:

///START SECTION ( for 30 seconds or so)

playlead(time, buffer);
playlead(time + length, buffer);
playlead(time +  length*2, buffer);
playlead(time, + length*3, buffer);

playbass(time, buffer);
playbass(time + length, buffer);
playbass(time +  length*2, buffer);
playbass(time, + length*3, buffer);

playlead1(time, buffer);
playlead1(time + length, buffer);
playlead1(time +  length*2, buffer);
playlead1(time, + length*3, buffer);

playdrums(time, buffer);
playdrums(time + length, buffer);
playdrums(time +  length*2, buffer);
playdrums(time, + length*3, buffer);

这是一次调用play()方法的16次。对于要播放的完整歌曲,在重新缓存并要求再次播放之前,很可能会有4个部分。这是在加载后直接同时至少进行16 * 4(64)次呼叫。我猜测,使用自动audioPad和音量/效果滑块可能会导致一些问题吗?谢谢。

////以下是我的大多数问题源自的代码示例:

function LeadStartSection
(buffer, time, gainNode, bufferList) 
{

console.log("playing lead Start section");   
    var timer = setTimeout(function() {    //checks when audiobuffer has finished
    console.log('sample times out at' + timer);
    }, buffer.duration * 1000);  

    var Length = buffer.duration;           
    console.log(Length);
    var n = 1;

////Example of second method/////
 playLead(buffer, time, gainNode,n, bufferList);
 playLead(buffer, time + Length, gainNode, Length,n, bufferList);
 playLead(buffer, time + Length*2, gainNode, Length,n, bufferList);
 playLead(buffer, time + Length*3, gainNode, Length, n+2, bufferList);
}

///example of what I would like to do///

for (i=o; i<leadPlayCount; i++)
{
PlayLead(buffer, gainNode, Length, bufferList);
}

*在第一个例子中,n被传递给函数,因为中间部分将被提示一次n = n + 2。

*在第二个例子中,我在调用playLead时遇到问题,因此每个循环都在它结束之前的一个循环之后开始。相反,该方法一次被调用4次。它听起来不太好!我在想,也许有一种方法可以让for循环不会继续,直到它收到playLead方法的返回但看起来我错了。

我希望这可以让你更多地了解我所处的位置。请问您是否还有其他任何想要我加入的内容。万分感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

好的,我想你可能只是误解了循环是如何工作的,或者是Audio API如何工作,或者JavaScript是如何工作的。如果你有这样的功能:

function playBuffer(time, buffer) {
  var node = context.createBufferSource();
  node.buffer = buffer;
  node.connect(context.destination);
  node.start(time);
}

然后,要连续多次播放相同的缓冲区,您可以这样做:

playBuffer(context.currentTime, buffer);
playBuffer(context.currentTime + buffer.duration, buffer);
playBuffer(context.currentTime + 2 * buffer.duration, buffer);
playBuffer(context.currentTime + 3 * buffer.duration, buffer);

或:

for (var i = 0; i < 4; i++) {
  playBuffer(context.currentTime + i * buffer.duration, buffer);
}

这两者是等价的。

所以基本上你需要为将来的buffer.start提供一个开始时间,即大于context.currentTime,否则它将立即启动。无论是否从循环调用,所有对buffer.start的调用都会发生&#34; now&#34;,但是当声音实际开始播放时,由buffer.start()的第一个参数决定。