Tone.js problems with changing Tone.Polysynth

Viewed 409

In Tone.js I have made a class that creates a synth instance where .play() is called in a sequencer function, thereby playing a sound. In the class below there are absolutely no problems when this.synth in updateSynthType is a monophonic Tone.Synth, but the whole thing breaks when it is Tone.Polysynth and I receive the following error when trying to call updateSynthType.

Uncaught Error: Synth was already disposed
    at ti (Tone.js:1)
    at ra._scheduleEvent (Tone.js:21)
    at Object.callback (Tone.js:21)
    at Gi._timeoutLoop (Tone.js:21)
    at Gi.emit (Tone.js:7)

I don't understand why this never happens with a regular Tone.Synth but when I try to change a Tone.PolySynth an error appears. I am trying to update the settings to change between the type of polysynth (e.g. Synth, AMSynth, MetalSyth etc). How can I stop this problem? Why does this class only work for a regular Tone.Synth? Is there a better way of updating the PolySynth type in this class?

Here is the class in question:

class PolyInstrument {
  constructor(){
    this.synth = null
    this.gain = new Tone.Gain()
    this.gain.toDestination()
  }

  play(note = null, beat, time = null){
    if (this.synth){
      if (note === null){
        time ? this.synth.triggerAttackRelease(beat, time) : this.synth.triggerAttackRelease(beat)
      } else { 
        time ? this.synth.triggerAttackRelease(note, beat, time) : this.synth.triggerAttackRelease(note, beat)
      }
    } else {
      alert('error: no synth')
    }
  }

  get defaultSettings(){
    return {
      Synth: {
        oscillator: {
          type: 'triangle'
        },
        envelope: {
          attack: 0.005,
          decay: 0.1,
          sustain: 0.3,
          release: 1
        }
      },
      AMSynth: {
        harmonicity: 3 ,
        detune: 0 ,
        oscillator: {
          type: 'sine'
        },
        envelope: {
          attack: 0.01 ,
          decay: 0.01 ,
          sustain: 1 ,
          release: 0.5
        },
        modulation: {
          type: 'square'
        },
        modulationEnvelope: {
          attack: 0.5 ,
          decay: 0 ,
          sustain: 1 ,
          release: 0.5
        }
      }
    }
  }

  updateSynthType(synthType){
    if (this.synth){
      this.synth.disconnect(this.gain)
      this.synth.dispose()
    }
    let settings = this.defaultSettings[synthType] || {}
    this.synth = new Tone.PolySynth(Tone[synthType], settings)
    this.synth.connect(this.gain)
    this.play()
  }
}

Thanks for reading.

2 Answers

I was able to fix this by clearing out the context timeline before disposing:

synth.context._timeouts.cancel(0);
synth.dispose();
Related