Web Audio API中的振荡器节点对象的生命周期和stop()方法

4

我正在尝试理解Web Audio API的时间和调度方法。

但是我仍然没有完全理解振荡器节点的stop()方法。

在这里,我正在尝试使用120 BPM的速度安排播放4个振荡器。

但是似乎一旦释放时间上的stop()方法启动,它就会停止所有的振荡器。

以下是代码:

var context = new webkitAudioContext();
var now = context.currentTime;
var tempo = 120;
var releaseTime = 0.5;
var secondsPerBeat = 60.0 / tempo;

for(var i = 0; i < 4; i++){
    var now = context.currentTime;
    var osc = context.createOscillator();
    osc.connect(context.destination);
    osc.start(now + (i*secondsPerBeat));
    var now = context.currentTime;
    osc.stop(now + releaseTime);
}

为什么会发生这种情况,我该如何预防?

谢谢


你确定它们在完全相同的时刻停止了吗?我认为你的问题在于循环非常快,所以作为人类,你看到它们在完全相同的时刻停止,但实际上并不是这样。 - MisterJ
@VincentPiel认为当for循环被调用时,它必须创建四个不同的振荡器节点,但很明显只有一个。令人困惑的是缓冲源和振荡器节点的相似之处,因为在BufferSourceNode上,当您执行完全相同的操作时,它会创建新的缓冲区并播放和停止而不会干扰其他已安排的音符。 - zya
@MisterJ,我的意思是,我希望振荡器节点在一个小节内播放4次,释放时间为0.5秒。 - zya
是的,我理解你想要什么,但正如@VincentPiel和我所说,问题在于你的循环将执行比一秒钟少得多的时间,然后你的振荡器将停止,从人类的视角来看,它们实际上是在同一时刻停止的,而它们实际上是以我们无法看到的微小延迟停止的。如果您想确定我告诉您的是否是真相,只需尝试更改测试中的releaseTime,在“ osc.stop(now + releaseTime)之前,在您的循环中添加“ releaseTime + = i;”。 - MisterJ
尝试将你的停止时间更改为:osc.stop(now + releaseTime+ i*secondsPerBeat)。我认为这就是你的意思:他们应该在开始后释放“releaseTime”。 - GameAlchemist
显示剩余4条评论
2个回答

2

首先,关于JavaScript:Js中没有块级作用域,因此将所有变量定义放在当前执行上下文的开头可能会更清晰。

其次,你确实会延迟启动声音,但是同时停止它们,这不是你想要的。

第三,for循环中的currentTime几乎是相同的:你不能依赖for循环来引入延迟。

var context = new webkitAudioContext();
var tempo = 120;
var releaseTime = 0.5;
var secondsPerBeat = 60.0 / tempo;

var now = context.currentTime;
var i = 0, startTime=0, osc = null;

for(i = 0; i < 4; i++) {
    startTime = now + (i*secondsPerBeat) ;
    osc = context.createOscillator();
    osc.connect(context.destination);
    osc.start();
    osc.stop(startTime + releaseTime);
} 

很快你会想编写一个函数来创建你的振荡器,以进一步清除代码。
编辑:关于对象的生命周期,最好查看规范:
https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
请参阅4.2.3.生命周期部分。
总之,如果正在播放或连接到引用上下文,则它们将存活,否则将死亡。
你可以选择:
- 保持相同的上下文,并在数组中存储4个振荡器,以便在需要时启动/停止它们。
- 或每次重新创建新的上下文+新的振荡器。
(但是你不能在同一上下文中不断创建新的振荡器,因为它们仍然连接在一起,会使用太多内存)。

你不能多次调用振荡器的启动。我发现最好的方法是将振荡器连接到增益节点,然后从0(无音符)切换到某个非零值以播放它。 - PinkElephantsOnParade
我认为我并不建议多次启动它们。在(简短的)代码中,我创建并启动了其中的4个。否则,您将确认以下两点:1)即使从JavaScript全局对象仍然可以访问音频资源(即它们无法被js回收/正在使用),它们也会被回收;2)将osc连接到已连接的增益节点将使其保持活动状态? - GameAlchemist

1
我也遇到了类似的问题。我发现你需要停止 stop() 并且断开 disconnect() 每个振荡器(或其他缓冲产生节点类型)实例,否则这些实例会持续存在并干扰任何新实例的播放。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接