import Tone from "../core/Tone"; import "../source/OmniOscillator"; import "../instrument/Instrument"; import "../component/AmplitudeEnvelope"; /** * @class Tone.MembraneSynth makes kick and tom sounds using a single oscillator * with an amplitude envelope and frequency ramp. A Tone.OmniOscillator * is routed through a Tone.AmplitudeEnvelope to the output. The drum * quality of the sound comes from the frequency envelope applied * during Tone.MembraneSynth.triggerAttack(note). The frequency envelope * starts at note * .octaves and ramps to note * over the duration of .pitchDecay. * * @constructor * @extends {Tone.Instrument} * @param {Object} [options] the options available for the synth * see defaults below * @example * var synth = new Tone.MembraneSynth().toMaster(); * synth.triggerAttackRelease("C2", "8n"); */ Tone.MembraneSynth = function(options){ options = Tone.defaultArg(options, Tone.MembraneSynth.defaults); Tone.Instrument.call(this, options); /** * The oscillator. * @type {Tone.OmniOscillator} */ this.oscillator = new Tone.OmniOscillator(options.oscillator); /** * The amplitude envelope. * @type {Tone.AmplitudeEnvelope} */ this.envelope = new Tone.AmplitudeEnvelope(options.envelope); /** * The number of octaves the pitch envelope ramps. * @type {Positive} */ this.octaves = options.octaves; /** * The amount of time the frequency envelope takes. * @type {Time} */ this.pitchDecay = options.pitchDecay; this.oscillator.chain(this.envelope, this.output); this._readOnly(["oscillator", "envelope"]); }; Tone.extend(Tone.MembraneSynth, Tone.Instrument); /** * @static * @type {Object} */ Tone.MembraneSynth.defaults = { "pitchDecay" : 0.05, "octaves" : 10, "oscillator" : { "type" : "sine", }, "envelope" : { "attack" : 0.001, "decay" : 0.4, "sustain" : 0.01, "release" : 1.4, "attackCurve" : "exponential" } }; /** * Trigger the note at the given time with the given velocity. * * @param {Frequency} note the note * @param {Time} [time=now] the time, if not given is now * @param {number} [velocity=1] velocity defaults to 1 * @returns {Tone.MembraneSynth} this * @example * kick.triggerAttack(60); */ Tone.MembraneSynth.prototype.triggerAttack = function(note, time, velocity){ time = this.toSeconds(time); note = this.toFrequency(note); var maxNote = note * this.octaves; this.oscillator.frequency.setValueAtTime(maxNote, time); this.oscillator.frequency.exponentialRampToValueAtTime(note, time + this.toSeconds(this.pitchDecay)); this.envelope.triggerAttack(time, velocity); this.oscillator.start(time); if (this.envelope.sustain === 0){ this.oscillator.stop(time + this.envelope.attack + this.envelope.decay); } return this; }; /** * Trigger the release portion of the note. * * @param {Time} [time=now] the time the note will release * @returns {Tone.MembraneSynth} this */ Tone.MembraneSynth.prototype.triggerRelease = function(time){ time = this.toSeconds(time); this.envelope.triggerRelease(time); this.oscillator.stop(time + this.envelope.release); return this; }; /** * Clean up. * @returns {Tone.MembraneSynth} this */ Tone.MembraneSynth.prototype.dispose = function(){ Tone.Instrument.prototype.dispose.call(this); this._writable(["oscillator", "envelope"]); this.oscillator.dispose(); this.oscillator = null; this.envelope.dispose(); this.envelope = null; return this; }; export default Tone.MembraneSynth;