Tonejs / Tone.js

A Web Audio framework for making interactive music in the browser.
https://tonejs.github.io
MIT License
13.52k stars 983 forks source link

Switching connections during offline render produces unexpected results #922

Closed joeweiss closed 3 years ago

joeweiss commented 3 years ago

Describe the bug

When rendering an offline context, it appears that a scheduled connection change (e.g. from Synth->Reverb to Synth->Vibrato) causes the last connection (Synth->Vibrato) to be used for the entire render.

To Reproduce

Here's a CodePen that reproduces the issue. https://codepen.io/joeweiss/pen/rNmdwWN

I've created a Tone.Synth and attached it to a Tone.Reverb. After 4 seconds, I disconnect it from the Reverb and attach it to a Tone.Vibrato.

When played normally, it works as expected. The reverb is applied for 4 seconds only, then the synth plays with a vibrato.

When rendered offline, the vibrato is used for the entire buffer.

What I've tried

I've tried passing the offline context explicitly as outlined in #781, but that doesn't seem to be the issue here. The playback is scheduled as expected; it's the chain itself that isn't correct.

tambien commented 3 years ago

Switching connections isn't supported in the OfflineContext. The connection graph needs to be static when used inside of the OfflineAudioContext. Since the OfflineRendering is done after the callbacks (including the callbacks in Tone.Transport) are invoked, only the resulting connections at the end of all the callbacks are used.

I would suggest setting up both connection paths in the Offline context, and instead of disconnect/connect. You can schedule the bypass with the Reverb's wet attribute, so after 4 seconds: reverb.wet.setValueAtTime(0, 4) to bypass the reverb after 4 seconds.