Tone.js/Tone/component/Follower.js

187 lines
4.5 KiB
JavaScript
Raw Normal View History

define(["Tone/core/Tone", "Tone/signal/Abs", "Tone/signal/Subtract", "Tone/signal/Multiply",
"Tone/signal/Signal", "Tone/signal/WaveShaper", "Tone/type/Type", "Tone/core/Delay", "Tone/core/AudioNode"],
function(Tone){
"use strict";
/**
* @class Tone.Follower is a crude envelope follower which will follow
* the amplitude of an incoming signal.
* Take care with small (< 0.02) attack or decay values
2015-07-02 00:19:58 +00:00
* as follower has some ripple which is exaggerated
* at these values. Read more about envelope followers (also known
2015-07-04 19:25:37 +00:00
* as envelope detectors) on [Wikipedia](https://en.wikipedia.org/wiki/Envelope_detector).
*
* @constructor
* @extends {Tone.AudioNode}
2015-06-20 23:25:49 +00:00
* @param {Time|Object} [attack] The rate at which the follower rises.
* @param {Time=} release The rate at which the folower falls.
2015-02-27 21:53:10 +00:00
* @example
2015-06-20 23:25:49 +00:00
* var follower = new Tone.Follower(0.2, 0.4);
*/
Tone.Follower = function(){
var options = Tone.defaults(arguments, ["attack", "release"], Tone.Follower);
Tone.AudioNode.call(this);
2016-09-20 03:02:42 +00:00
this.createInsOuts(1, 1);
2014-07-02 22:20:34 +00:00
/**
2014-07-02 22:20:34 +00:00
* @type {Tone.Abs}
* @private
*/
2014-07-02 22:20:34 +00:00
this._abs = new Tone.Abs();
/**
2014-07-23 19:22:46 +00:00
* the lowpass filter which smooths the input
* @type {BiquadFilterNode}
* @private
*/
this._filter = this.context.createBiquadFilter();
this._filter.type = "lowpass";
this._filter.frequency.value = 0;
this._filter.Q.value = -100;
/**
* @type {WaveShaperNode}
* @private
*/
this._frequencyValues = new Tone.WaveShaper();
/**
2014-10-30 23:44:05 +00:00
* @type {Tone.Subtract}
* @private
*/
2014-10-30 23:44:05 +00:00
this._sub = new Tone.Subtract();
/**
* @type {Tone.Delay}
* @private
*/
this._delay = new Tone.Delay(this.blockTime);
/**
* this keeps it far from 0, even for very small differences
* @type {Tone.Multiply}
* @private
*/
2014-10-30 23:44:05 +00:00
this._mult = new Tone.Multiply(10000);
2014-08-25 13:57:36 +00:00
/**
* @private
* @type {number}
*/
2015-02-12 04:09:20 +00:00
this._attack = options.attack;
2014-08-25 13:57:36 +00:00
/**
* @private
* @type {number}
*/
2015-02-12 04:09:20 +00:00
this._release = options.release;
2014-08-25 13:57:36 +00:00
//the smoothed signal to get the values
2014-12-01 02:32:09 +00:00
this.input.chain(this._abs, this._filter, this.output);
//the difference path
2014-10-30 23:44:05 +00:00
this._abs.connect(this._sub, 0, 1);
2014-12-01 02:32:09 +00:00
this._filter.chain(this._delay, this._sub);
//threshold the difference and use the thresh to set the frequency
2014-12-01 02:32:09 +00:00
this._sub.chain(this._mult, this._frequencyValues, this._filter.frequency);
//set the attack and release values in the table
2014-08-25 13:57:36 +00:00
this._setAttackRelease(this._attack, this._release);
};
Tone.extend(Tone.Follower, Tone.AudioNode);
2014-07-02 22:20:34 +00:00
/**
* @static
* @type {Object}
*/
Tone.Follower.defaults = {
"attack" : 0.05,
"release" : 0.5
};
2014-07-23 19:25:46 +00:00
/**
* sets the attack and release times in the wave shaper
* @param {Time} attack
* @param {Time} release
* @private
2014-07-23 19:25:46 +00:00
*/
Tone.Follower.prototype._setAttackRelease = function(attack, release){
var minTime = this.blockTime;
2016-04-18 06:19:01 +00:00
attack = Tone.Time(attack).toFrequency();
release = Tone.Time(release).toFrequency();
2014-10-13 23:21:34 +00:00
attack = Math.max(attack, minTime);
release = Math.max(release, minTime);
this._frequencyValues.setMap(function(val){
if (val <= 0){
return attack;
} else {
return release;
}
});
2014-07-23 19:25:46 +00:00
};
2014-08-25 13:57:36 +00:00
/**
* The attack time.
* @memberOf Tone.Follower#
2015-06-14 00:20:36 +00:00
* @type {Time}
* @name attack
2014-08-25 13:57:36 +00:00
*/
Object.defineProperty(Tone.Follower.prototype, "attack", {
get : function(){
return this._attack;
},
set : function(attack){
this._attack = attack;
this._setAttackRelease(this._attack, this._release);
}
});
2014-08-25 13:57:36 +00:00
/**
* The release time.
* @memberOf Tone.Follower#
2015-06-14 00:20:36 +00:00
* @type {Time}
* @name release
2014-08-25 13:57:36 +00:00
*/
Object.defineProperty(Tone.Follower.prototype, "release", {
get : function(){
return this._release;
},
set : function(release){
this._release = release;
this._setAttackRelease(this._attack, this._release);
}
});
2014-08-25 13:57:36 +00:00
/**
2015-07-02 00:19:58 +00:00
* Borrows the connect method from Signal so that the output can be used
* as a Tone.Signal control signal.
2015-02-27 21:53:10 +00:00
* @function
*/
Tone.Follower.prototype.connect = Tone.Signal.prototype.connect;
2014-07-02 22:20:34 +00:00
/**
* dispose
* @returns {Tone.Follower} this
2014-07-02 22:20:34 +00:00
*/
Tone.Follower.prototype.dispose = function(){
Tone.AudioNode.prototype.dispose.call(this);
this._filter.disconnect();
2014-10-30 23:44:05 +00:00
this._filter = null;
this._frequencyValues.disconnect();
2014-10-30 23:44:05 +00:00
this._frequencyValues = null;
this._delay.dispose();
this._delay = null;
2014-10-30 23:44:05 +00:00
this._sub.disconnect();
this._sub = null;
this._abs.dispose();
2014-07-02 22:20:34 +00:00
this._abs = null;
2014-10-30 23:44:05 +00:00
this._mult.dispose();
this._mult = null;
this._curve = null;
2015-02-02 17:49:13 +00:00
return this;
2014-07-02 22:20:34 +00:00
};
return Tone.Follower;
});