diff --git a/Tone/instrument/Instrument.ts b/Tone/instrument/Instrument.ts index 6ee6e8d1..a7e20f1a 100644 --- a/Tone/instrument/Instrument.ts +++ b/Tone/instrument/Instrument.ts @@ -80,14 +80,25 @@ export abstract class Instrument extends Tone * Tone.Transport.start(); */ sync(): this { - if (!this._synced) { - this._synced = true; + if (this._syncState()) { this._syncMethod("triggerAttack", 1); this._syncMethod("triggerRelease", 0); } return this; } + /** + * set _sync + */ + protected _syncState(): boolean { + let changed = false; + if (!this._synced) { + this._synced = true; + changed = true; + } + return changed; + } + /** * Wrap the given method so that it can be synchronized * @param method Which method to wrap and sync diff --git a/Tone/instrument/NoiseSynth.ts b/Tone/instrument/NoiseSynth.ts index 78584f7f..38781e05 100644 --- a/Tone/instrument/NoiseSynth.ts +++ b/Tone/instrument/NoiseSynth.ts @@ -103,8 +103,10 @@ export class NoiseSynth extends Instrument { } sync(): this { - this._syncMethod("triggerAttack", 0); - this._syncMethod("triggerRelease", 0); + if (this._syncState()) { + this._syncMethod("triggerAttack", 0); + this._syncMethod("triggerRelease", 0); + } return this; } diff --git a/Tone/instrument/PolySynth.ts b/Tone/instrument/PolySynth.ts index ad0ad93d..8daa23b7 100644 --- a/Tone/instrument/PolySynth.ts +++ b/Tone/instrument/PolySynth.ts @@ -334,8 +334,10 @@ export class PolySynth = Synth> extends Instrument } sync(): this { - this._syncMethod("triggerAttack", 1); - this._syncMethod("triggerRelease", 1); + if (this._syncState()) { + this._syncMethod("triggerAttack", 1); + this._syncMethod("triggerRelease", 1); + } return this; } diff --git a/Tone/instrument/Sampler.ts b/Tone/instrument/Sampler.ts index 4e50833e..c7ba3951 100644 --- a/Tone/instrument/Sampler.ts +++ b/Tone/instrument/Sampler.ts @@ -254,8 +254,10 @@ export class Sampler extends Instrument { } sync(): this { - this._syncMethod("triggerAttack", 1); - this._syncMethod("triggerRelease", 1); + if (this._syncState()) { + this._syncMethod("triggerAttack", 1); + this._syncMethod("triggerRelease", 1); + } return this; } diff --git a/test/helper/InstrumentTests.ts b/test/helper/InstrumentTests.ts index bc4976f9..eecb3e86 100644 --- a/test/helper/InstrumentTests.ts +++ b/test/helper/InstrumentTests.ts @@ -5,6 +5,10 @@ import { Offline } from "./Offline"; import { OutputAudio } from "./OutputAudio"; import { Monophonic } from "Tone/instrument/Monophonic"; +function wait(time) { + return new Promise(done => setTimeout(done, time)); +} + export function InstrumentTest(Constr, note, constrArg?, optionsIndex?): void { context("Instrument Tests", () => { @@ -167,6 +171,35 @@ export function InstrumentTest(Constr, note, constrArg?, optionsIndex?): void { }); }); + + it("can unsync and re-sync triggerAttack to the Transport", () => { + return Offline(async ({ transport }) => { + const instance = new Constr(constrArg); + instance.toDestination(); + + instance.sync(); + if (note) { + instance.triggerAttack(note, 0.1); + } else { + instance.triggerAttack(0.1); + } + transport.start(0.1); + await wait(100); + instance.unsync(); + transport.stop(); + + instance.sync(); + if (note) { + instance.triggerAttack(note, 0.1); + } else { + instance.triggerAttack(0.1); + } + transport.start(0.1); + }, 1).then((buffer) => { + expect(buffer.getTimeOfFirstSound()).to.be.within(0.19, 0.25); + }); + }); + it("calling sync and unsync multiple times has no effect", () => { return Offline(({ transport }) => { const instance = new Constr(constrArg);