diff --git a/Tone/instrument/PluckSynth.test.ts b/Tone/instrument/PluckSynth.test.ts index fd2212540..979b2e6d4 100644 --- a/Tone/instrument/PluckSynth.test.ts +++ b/Tone/instrument/PluckSynth.test.ts @@ -13,15 +13,25 @@ describe("PluckSynth", () => { return CompareToFile(() => { const synth = new PluckSynth().toDestination(); synth.triggerAttack("C4"); - }, "pluckSynth.wav", 0.26); + }, "pluckSynth.wav", 0.02); + }); + + it("matches a file with release", () => { + return CompareToFile(() => { + const synth = new PluckSynth({ + resonance: 0.97, + release: 0.2 + }).toDestination(); + synth.triggerAttackRelease("C4", 0.6); + }, "pluckSynth2.wav", 0.06); }); context("API", () => { it("can get and set resonance", () => { const pluck = new PluckSynth(); - pluck.resonance.value = 0.4; - expect(pluck.resonance.value).to.be.closeTo(0.4, 0.001); + pluck.resonance = 0.4; + expect(pluck.resonance).to.be.closeTo(0.4, 0.001); pluck.dispose(); }); @@ -45,7 +55,7 @@ describe("PluckSynth", () => { resonance: 0.5, }); expect(pluck.dampening).to.be.closeTo(300, 0.1); - expect(pluck.resonance.value).to.be.closeTo(0.5, 0.001); + expect(pluck.resonance).to.be.closeTo(0.5, 0.001); pluck.dispose(); }); }); diff --git a/Tone/instrument/PluckSynth.ts b/Tone/instrument/PluckSynth.ts index 96040ce7f..60d3e118c 100644 --- a/Tone/instrument/PluckSynth.ts +++ b/Tone/instrument/PluckSynth.ts @@ -1,10 +1,8 @@ -import { Param } from "../core/context/Param"; import { Frequency, NormalRange, Time } from "../core/type/Units"; import { LowpassCombFilter } from "../component/filter/LowpassCombFilter"; import { deepMerge } from "../core/util/Defaults"; import { optionsFromArguments } from "../core/util/Defaults"; import { RecursivePartial } from "../core/util/Interface"; -import { Signal } from "../signal/Signal"; import { Noise } from "../source/Noise"; import { Instrument, InstrumentOptions } from "./Instrument"; @@ -12,11 +10,11 @@ export interface PluckSynthOptions extends InstrumentOptions { attackNoise: number; dampening: Frequency; resonance: NormalRange; + release: Time; } /** - * Karplus-String string synthesis. Often out of tune. - * + * Karplus-String string synthesis. * @example * var plucky = new Tone.PluckSynth().toDestination(); * plucky.triggerAttack("C4"); @@ -41,9 +39,14 @@ export class PluckSynth extends Instrument { attackNoise: number; /** - * The resonance control. + * The amount of resonance of the pluck. Also correlates to the sustain duration. */ - readonly resonance: Param; + resonance: NormalRange; + + /** + * The release time which corresponds to a resonance ramp down to 0 + */ + release: Time; constructor(options?: RecursivePartial) constructor() { @@ -64,7 +67,8 @@ export class PluckSynth extends Instrument { resonance: options.resonance, }); - this.resonance = this._lfcf.resonance; + this.resonance = options.resonance; + this.release = options.release; this._noise.connect(this._lfcf); this._lfcf.connect(this.output); @@ -75,6 +79,7 @@ export class PluckSynth extends Instrument { attackNoise: 1, dampening: 4000, resonance: 0.7, + release: 1, }); } @@ -97,14 +102,16 @@ export class PluckSynth extends Instrument { this._lfcf.delayTime.setValueAtTime(delayAmount, time); this._noise.start(time); this._noise.stop(time + delayAmount * this.attackNoise); + this._lfcf.resonance.cancelScheduledValues(time); + this._lfcf.resonance.setValueAtTime(this.resonance, time); return this; } /** - * PluckSynths' trigger release method doesn't do anything. + * Ramp down the [[resonance]] to 0 over the duration of the release time. */ - triggerRelease(): this{ - // does nothing + triggerRelease(time?: Time): this{ + this._lfcf.resonance.linearRampTo(0, this.release, time); return this; } diff --git a/test/audio/compare/pluckSynth2.wav b/test/audio/compare/pluckSynth2.wav new file mode 100644 index 000000000..6d60bdf76 Binary files /dev/null and b/test/audio/compare/pluckSynth2.wav differ