2019-10-28 19:11:36 +00:00
|
|
|
import { Positive } from "../core/type/Units";
|
|
|
|
import { optionsFromArguments } from "../core/util/Defaults";
|
2019-09-27 13:36:26 +00:00
|
|
|
import { RecursivePartial } from "../core/util/Interface";
|
|
|
|
import { Multiply } from "../signal/Multiply";
|
2019-10-28 19:11:36 +00:00
|
|
|
import { ModulationSynth, ModulationSynthOptions } from "./ModulationSynth";
|
2019-09-27 13:36:26 +00:00
|
|
|
|
2019-10-28 19:11:36 +00:00
|
|
|
export interface FMSynthOptions extends ModulationSynthOptions {
|
2019-09-27 13:36:26 +00:00
|
|
|
modulationIndex: Positive;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FMSynth is composed of two Tone.Synths where one Tone.Synth modulates
|
|
|
|
* the frequency of a second Tone.Synth. A lot of spectral content
|
|
|
|
* can be explored using the modulationIndex parameter. Read more about
|
|
|
|
* frequency modulation synthesis on Sound On Sound: [Part 1](https://web.archive.org/web/20160403123704/http://www.soundonsound.com/sos/apr00/articles/synthsecrets.htm), [Part 2](https://web.archive.org/web/20160403115835/http://www.soundonsound.com/sos/may00/articles/synth.htm).
|
|
|
|
*
|
2019-10-23 03:04:52 +00:00
|
|
|
* @example
|
2019-10-24 22:01:27 +00:00
|
|
|
* import { FMSynth } from "tone";
|
|
|
|
* const fmSynth = new FMSynth().toDestination();
|
2019-09-27 13:36:26 +00:00
|
|
|
* fmSynth.triggerAttackRelease("C5", "4n");
|
2019-10-28 21:31:25 +00:00
|
|
|
*
|
|
|
|
* @category Instrument
|
2019-09-27 13:36:26 +00:00
|
|
|
*/
|
|
|
|
|
2019-10-28 19:11:36 +00:00
|
|
|
export class FMSynth extends ModulationSynth<FMSynthOptions> {
|
2019-09-27 13:36:26 +00:00
|
|
|
readonly name: string = "FMSynth";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The modulation index which essentially the depth or amount of the modulation. It is the
|
|
|
|
* ratio of the frequency of the modulating signal (mf) to the amplitude of the
|
|
|
|
* modulating signal (ma) -- as in ma/mf.
|
|
|
|
*/
|
|
|
|
readonly modulationIndex: Multiply;
|
|
|
|
|
|
|
|
constructor(options?: RecursivePartial<FMSynthOptions>);
|
|
|
|
constructor() {
|
|
|
|
super(optionsFromArguments(FMSynth.getDefaults(), arguments));
|
|
|
|
const options = optionsFromArguments(FMSynth.getDefaults(), arguments);
|
|
|
|
|
2019-09-30 20:48:39 +00:00
|
|
|
this.modulationIndex = new Multiply({
|
|
|
|
context: this.context,
|
|
|
|
value: options.modulationIndex,
|
|
|
|
});
|
2019-09-27 13:36:26 +00:00
|
|
|
|
|
|
|
// control the two voices frequency
|
|
|
|
this.frequency.connect(this._carrier.frequency);
|
|
|
|
this.frequency.chain(this.harmonicity, this._modulator.frequency);
|
|
|
|
this.frequency.chain(this.modulationIndex, this._modulationNode);
|
|
|
|
this.detune.fan(this._carrier.detune, this._modulator.detune);
|
|
|
|
this._modulator.connect(this._modulationNode.gain);
|
|
|
|
this._modulationNode.connect(this._carrier.frequency);
|
|
|
|
this._carrier.connect(this.output);
|
|
|
|
}
|
|
|
|
|
|
|
|
static getDefaults(): FMSynthOptions {
|
2019-10-28 19:11:36 +00:00
|
|
|
return Object.assign(ModulationSynth.getDefaults(), {
|
2019-09-27 13:36:26 +00:00
|
|
|
modulationIndex: 10,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
dispose(): this {
|
|
|
|
super.dispose();
|
|
|
|
this.modulationIndex.dispose();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|