Tone.js/Tone/component/Envelope.js

289 lines
7.9 KiB
JavaScript
Raw Normal View History

2015-08-18 20:29:39 +00:00
define(["Tone/core/Tone", "Tone/signal/TimelineSignal",
2015-08-16 19:17:35 +00:00
"Tone/signal/Pow", "Tone/core/Types"], function(Tone){
2014-03-11 23:27:46 +00:00
"use strict";
2014-06-15 23:35:00 +00:00
/**
2015-07-04 19:25:37 +00:00
* @class Tone.Envelope is an [ADSR](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope)
* envelope generator. Tone.Envelope outputs a signal which
2015-07-02 19:45:40 +00:00
* can be connected to an AudioParam or Tone.Signal.
* <img src="https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg">
2014-06-16 23:59:58 +00:00
*
* @constructor
* @extends {Tone}
2015-06-20 23:25:49 +00:00
* @param {Time} [attack] The amount of time it takes for the envelope to go from
* 0 to it's maximum value.
2015-06-14 00:20:36 +00:00
* @param {Time} [decay] The period of time after the attack that it takes for the envelope
* to fall to the sustain value.
* @param {NormalRange} [sustain] The percent of the maximum value that the envelope rests at until
* the release is triggered.
* @param {Time} [release] The amount of time after the release is triggered it takes to reach 0.
2015-02-27 21:53:10 +00:00
* @example
2015-06-20 23:25:49 +00:00
* //an amplitude envelope
2015-06-14 03:56:32 +00:00
* var gainNode = Tone.context.createGain();
* var env = new Tone.Envelope({
* "attack" : 0.1,
* "decay" : 0.2,
* "sustain" : 1,
* "release" : 0.8,
* });
* env.connect(gainNode.gain);
2014-06-15 23:35:00 +00:00
*/
Tone.Envelope = function(){
//get all of the defaults
var options = this.optionsObject(arguments, ["attack", "decay", "sustain", "release"], Tone.Envelope.defaults);
2014-08-24 16:12:40 +00:00
/**
2015-06-20 23:25:49 +00:00
* When triggerAttack is called, the attack time is the amount of
* time it takes for the envelope to reach it's maximum value.
2015-06-14 00:20:36 +00:00
* @type {Time}
*/
this.attack = options.attack;
/**
2015-06-20 23:25:49 +00:00
* After the attack portion of the envelope, the value will fall
* over the duration of the decay time to it's sustain value.
2015-06-14 00:20:36 +00:00
* @type {Time}
*/
this.decay = options.decay;
/**
2015-06-20 23:25:49 +00:00
* The sustain value is the value
* which the envelope rests at after triggerAttack is
* called, but before triggerRelease is invoked.
2015-06-14 00:20:36 +00:00
* @type {NormalRange}
*/
this.sustain = options.sustain;
/**
2015-06-20 23:25:49 +00:00
* After triggerRelease is called, the envelope's
* value will fall to it's miminum value over the
* duration of the release time.
2015-06-14 00:20:36 +00:00
* @type {Time}
*/
this.release = options.release;
/**
* the next time the envelope is at standby
* @type {number}
* @private
*/
2015-08-16 19:17:35 +00:00
this._attackCurve = Tone.Envelope.Type.Linear;
/**
* the next time the envelope is at standby
* @type {number}
* @private
*/
2015-08-16 19:17:35 +00:00
this._releaseCurve = Tone.Envelope.Type.Exponential;
/**
* the minimum output value
* @type {number}
* @private
*/
2015-07-20 14:47:52 +00:00
this._minOutput = 0.00001;
/**
2014-11-02 01:54:40 +00:00
* the signal
2015-08-18 20:29:39 +00:00
* @type {Tone.TimelineSignal}
2014-11-02 01:54:40 +00:00
* @private
*/
2015-08-18 20:29:39 +00:00
this._sig = this.output = new Tone.TimelineSignal();
2015-08-16 19:17:35 +00:00
this._sig.setValueAtTime(0, 0);
2015-04-20 14:42:27 +00:00
//set the attackCurve initially
this.attackCurve = options.attackCurve;
2015-08-16 19:17:35 +00:00
this.releaseCurve = options.releaseCurve;
2014-06-15 21:37:55 +00:00
};
2014-03-11 23:27:46 +00:00
2014-06-15 21:37:55 +00:00
Tone.extend(Tone.Envelope);
2014-04-06 00:47:59 +00:00
/**
* the default parameters
* @static
* @const
*/
Tone.Envelope.defaults = {
"attack" : 0.01,
"decay" : 0.1,
"sustain" : 0.5,
"release" : 1,
2015-08-16 19:17:35 +00:00
"attackCurve" : "linear",
"releaseCurve" : "exponential",
};
2014-11-02 01:54:40 +00:00
/**
* the envelope time multipler
* @type {number}
* @private
*/
Tone.Envelope.prototype._timeMult = 0.25;
2015-07-04 17:36:38 +00:00
/**
* Read the current value of the envelope. Useful for
* syncronizing visual output to the envelope.
* @memberOf Tone.Envelope#
* @type {Number}
* @name value
* @readOnly
*/
Object.defineProperty(Tone.Envelope.prototype, "value", {
get : function(){
return this._sig.value;
}
});
/**
2015-05-24 13:53:53 +00:00
* The slope of the attack. Either "linear" or "exponential".
* @memberOf Tone.Envelope#
2015-05-24 13:53:53 +00:00
* @type {string}
2015-04-20 14:42:27 +00:00
* @name attackCurve
* @example
2015-04-20 14:42:27 +00:00
* env.attackCurve = "linear";
*/
2015-04-20 14:42:27 +00:00
Object.defineProperty(Tone.Envelope.prototype, "attackCurve", {
get : function(){
2015-04-20 14:42:27 +00:00
return this._attackCurve;
},
set : function(type){
2015-05-24 13:53:53 +00:00
if (type === Tone.Envelope.Type.Linear ||
type === Tone.Envelope.Type.Exponential){
2015-04-20 14:42:27 +00:00
this._attackCurve = type;
} else {
2015-04-20 14:42:27 +00:00
throw Error("attackCurve must be either \"linear\" or \"exponential\". Invalid type: ", type);
}
}
});
/**
2015-08-16 19:17:35 +00:00
* The slope of the Release. Either "linear" or "exponential".
* @memberOf Tone.Envelope#
* @type {string}
* @name releaseCurve
* @example
* env.releaseCurve = "linear";
*/
2015-08-16 19:17:35 +00:00
Object.defineProperty(Tone.Envelope.prototype, "releaseCurve", {
get : function(){
return this._releaseCurve;
},
set : function(type){
if (type === Tone.Envelope.Type.Linear ||
type === Tone.Envelope.Type.Exponential){
this._releaseCurve = type;
} else {
2015-08-16 19:17:35 +00:00
throw Error("releaseCurve must be either \"linear\" or \"exponential\". Invalid type: ", type);
}
}
2015-08-16 19:17:35 +00:00
});
2014-06-15 23:35:00 +00:00
/**
2015-02-27 21:53:10 +00:00
* Trigger the attack/decay portion of the ADSR envelope.
2015-06-20 23:25:49 +00:00
* @param {Time} [time=now] When the attack should start.
* @param {NormalRange} [velocity=1] The velocity of the envelope scales the vales.
2014-09-04 02:36:56 +00:00
* number between 0-1
* @returns {Tone.Envelope} this
2015-02-27 21:53:10 +00:00
* @example
* //trigger the attack 0.5 seconds from now with a velocity of 0.2
* env.triggerAttack("+0.5", 0.2);
2014-06-15 23:35:00 +00:00
*/
2014-09-04 02:36:56 +00:00
Tone.Envelope.prototype.triggerAttack = function(time, velocity){
//to seconds
var now = this.now() + this.blockTime;
time = this.toSeconds(time, now);
2015-08-16 19:17:35 +00:00
var attack = this.toSeconds(this.attack) + time;
var decay = this.toSeconds(this.decay);
2015-08-16 19:17:35 +00:00
velocity = this.defaultArg(velocity, 1);
//attack
2015-05-24 13:53:53 +00:00
if (this._attackCurve === Tone.Envelope.Type.Linear){
2015-08-16 19:17:35 +00:00
this._sig.linearRampToValueBetween(velocity, time, attack);
} else {
2015-08-16 19:17:35 +00:00
this._sig.exponentialRampToValueBetween(velocity, time, attack);
}
2015-08-16 19:17:35 +00:00
//decay
this._sig.setTargetAtTime(this.sustain * velocity, attack, decay * this._timeMult);
2015-02-02 17:49:13 +00:00
return this;
2014-06-15 21:37:55 +00:00
};
2014-06-15 23:35:00 +00:00
/**
2015-02-27 21:53:10 +00:00
* Triggers the release of the envelope.
2015-06-20 23:25:49 +00:00
* @param {Time} [time=now] When the release portion of the envelope should start.
* @returns {Tone.Envelope} this
2015-02-27 21:53:10 +00:00
* @example
* //trigger release immediately
* env.triggerRelease();
2014-06-15 23:35:00 +00:00
*/
2014-04-06 00:47:59 +00:00
Tone.Envelope.prototype.triggerRelease = function(time){
var now = this.now() + this.blockTime;
time = this.toSeconds(time, now);
var release = this.toSeconds(this.release);
2015-08-16 19:17:35 +00:00
if (this._releaseCurve === Tone.Envelope.Type.Linear){
this._sig.linearRampToValueBetween(this._minOutput, time, time + release);
} else {
2015-08-16 19:17:35 +00:00
this._sig.setTargetAtTime(this._minOutput, time, release * this._timeMult);
}
2015-02-02 17:49:13 +00:00
return this;
2014-06-15 21:37:55 +00:00
};
2014-09-20 19:18:36 +00:00
/**
2015-06-20 23:25:49 +00:00
* triggerAttackRelease is shorthand for triggerAttack, then waiting
* some duration, then triggerRelease.
* @param {Time} duration The duration of the sustain.
* @param {Time} [time=now] When the attack should be triggered.
* @param {number} [velocity=1] The velocity of the envelope.
* @returns {Tone.Envelope} this
2015-02-27 21:53:10 +00:00
* @example
2015-06-20 23:25:49 +00:00
* //trigger the attack and then the release after 0.6 seconds.
* env.triggerAttackRelease(0.6);
2014-09-20 19:18:36 +00:00
*/
Tone.Envelope.prototype.triggerAttackRelease = function(duration, time, velocity) {
time = this.toSeconds(time);
this.triggerAttack(time, velocity);
this.triggerRelease(time + this.toSeconds(duration));
2015-02-02 17:49:13 +00:00
return this;
2014-09-20 19:18:36 +00:00
};
2014-06-15 23:35:00 +00:00
/**
2015-06-14 01:54:20 +00:00
* Borrows the connect method from Tone.Signal.
* @function
2015-06-20 23:25:49 +00:00
* @private
2014-06-15 23:35:00 +00:00
*/
Tone.Envelope.prototype.connect = Tone.Signal.prototype.connect;
2014-04-06 00:47:59 +00:00
2014-06-20 05:23:35 +00:00
/**
2015-06-20 23:25:49 +00:00
* Disconnect and dispose.
* @returns {Tone.Envelope} this
2014-06-20 05:23:35 +00:00
*/
Tone.Envelope.prototype.dispose = function(){
Tone.prototype.dispose.call(this);
2014-11-02 01:54:40 +00:00
this._sig.dispose();
this._sig = null;
2015-02-02 17:49:13 +00:00
return this;
2014-06-20 05:23:35 +00:00
};
/**
* The phase of the envelope.
* @enum {string}
*/
Tone.Envelope.Phase = {
2015-05-24 13:53:53 +00:00
Attack : "attack",
Decay : "decay",
Sustain : "sustain",
Release : "release",
Standby : "standby",
};
/**
* The phase of the envelope.
* @enum {string}
*/
Tone.Envelope.Type = {
2015-05-24 13:53:53 +00:00
Linear : "linear",
Exponential : "exponential",
};
2014-04-06 00:47:59 +00:00
return Tone.Envelope;
});