2

我正在尝试构建一个循环音序器,它利用网络音频 API 和许多不同长度的不同音乐循环。一般的想法是随机选择循环(在一定程度上),然后以特定顺序播放开头、中间和结尾部分。有四个通道 - 贝司、鼓、主音和 FX。就在最后一节结束之前,使用相同的公式选择并播放了一组新样本。

然后我打算添加一个可视化器,也许还有一些自动化 - 即可能为最后几个小节添加混响。

我必须尝试遵循“两个时钟的故事”方法,但由于我对编程和 javascript 还比较陌生,所以我很难实现它。我认为这可能会使事情变得比完成这项工作所需的更复杂。

我最初的想法是创建一个 for 循环,其中的 play 方法指定了我希望循环播放的次数,但我发现这些样本将同时播放。根据“两个时钟的故事”,我尽可能避免使用 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) 次调用。我猜想使用光谱仪、自动音频参数和音量/效果滑块,这可能会导致一些问题?谢谢。

//// 这是我的大部分问题都源于的代码示例:

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 方法的返回之前不会继续,但似乎我错了。

我希望这可以让您对我所处的位置有更多的了解。请询问您是否还希望我包括其他任何内容。感谢一百万的任何帮助!

4

1 回答 1

0

好吧,我想你可能只是误解了循环是如何工作的,或者音频 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 的所有调用都是“现在”发生的,但是声音真正开始播放的时间是由 buffer.start() 的第一个参数决定的。

于 2015-03-09T20:52:43.690 回答