Web Audio API - 停止连接到释放包络的振荡器的正确方法

4
我正在使用WebAudioAPIWebMIDIAPI创建一个多音合成器。我为我的两个振荡器中的每一个设置了增益节点,然后将它们连接到主增益节点。
我想知道如何在发行后正确停止(并在必要时删除?)振荡器。我不确定是否需要调用oscillator.stop()并从数组中delete删除振荡器。
如果这样做,释放包络不起作用,音符会立即停止。如果不这样做,释放包络确实起作用,但是音符有时会一直播放下去。
编辑:当未实现.stop()功能且同时播放两个音符时,其中一个振荡器始终处于开启状态。不确定是我的代码还是其他原因。
以下是我的noteOff函数代码:
/**
 * Note is being released
 */
this.noteOff = function (frequency, velocity, note){

    var now = this.context.currentTime;

    // Get the release values
    var osc1ReleaseVal = now + this.osc1Release;
    var osc2ReleaseVal = now + this.osc2Release;

    // Cancel scheduled values
    this.oscGain.gain.cancelScheduledValues(now);
    this.osc2Gain.gain.cancelScheduledValues(now);

    // Set the value
    this.oscGain.gain.setValueAtTime(this.oscGain.gain.value, now);
    this.osc2Gain.gain.setValueAtTime(this.osc2Gain.gain.value, now);

    // Release the note
    this.oscGain.gain.linearRampToValueAtTime(0.0, osc1ReleaseVal);
    this.osc2Gain.gain.linearRampToValueAtTime(0.0, osc2ReleaseVal);

    // ----- IF I COMMENT THE `forEach` Loop the release works correctly but with side-effects!
    // Stop the oscillators
    this.oscillators[frequency].forEach(function (oscillator) {
        oscillator.stop(now);
        oscillator.disconnect();
        delete oscillator;
    });
};

非常感谢您的帮助!如有需要,敬请指教。


其实我不确定你是否应该从数组中删除你的osc。使用一个函数来在你释放音符后切断增益怎么样?这样你就可以确保在某个时候音量关闭了,而不必停止和删除osc。只是一个想法...我需要花点时间研究它哈哈... - DevMoutarde
@DevMoutarde 也许是个好主意,我尝试快速将 oscillator.stop() 放入一个 setTimeout 函数中,时间设置为 osc1ReleaseValosc2ReleaseVal,但没有起作用... 我想我需要考虑添加其他东西。 - Alistair Hughes
哦,太糟糕了,它没有起作用,因为它听起来像是一个好的方法。也许(我猜你已经这样做了),你应该看一下互联网上的一些HTML/JS合成器,看看他们如何设法制作一个方便的播放/停止功能。我曾经自己玩过增益节点,而不是停止振荡。 - DevMoutarde
1个回答

3
不要使用oscillator.stop(now)。使用oscillator.stop(osc1ReleaseVal)来安排振荡器在增益降至0时停止。
你不必断开和删除振荡器。一旦停止,振荡器可以自行从增益节点断开连接。如果你放弃对振荡器的引用,它可以被垃圾回收。

谢谢你的回答,这确实有所作用。我猜可能是我的代码问题,虽然这样做可以解决持续不断的音符错误,但似乎现在当同时按下两个音符时,它不会执行“linearRampToValueAtTime”,而是以点击声突然结束。有什么想法吗?如果没有,我可能还是会接受你的答案,因为它解决了我的问题。 - Alistair Hughes
上面的代码片段是否说明了这一点?如果没有看到显示问题的代码部分,很难知道发生了什么。 - Raymond Toy
是的,我的意思是这是唯一执行停止振荡器的代码,它可能与我创建它们的方式有关,但我认为这超出了问题的范围。我可以编辑它以包括振荡器的创建,您想看吗? - Alistair Hughes
我认为这取决于你。但是,由于它不能满足您希望的某些用例,并且当前示例并没有真正显示出问题,因此提供一个真实的代码片段来说明问题可能会有很大帮助。 - Raymond Toy

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