2014-09-01 16:52:13 +00:00
|
|
|
define(["Tone/core/Tone", "Tone/component/LFO", "Tone/effect/FeedbackEffect", "Tone/component/Filter", "Tone/effect/StereoFeedbackEffect"],
|
2014-08-24 21:51:01 +00:00
|
|
|
function(Tone){
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
/**
|
2014-09-01 16:52:13 +00:00
|
|
|
* @class A Phaser effect with feedback. inspiration from https://github.com/Dinahmoe/tuna/
|
2014-08-24 21:51:01 +00:00
|
|
|
*
|
2014-09-01 16:52:13 +00:00
|
|
|
* @extends {Tone.StereoFeedbackEffect}
|
2014-08-24 21:51:01 +00:00
|
|
|
* @constructor
|
|
|
|
* @param {number|object=} rate the speed of the phasing
|
|
|
|
* @param {number=} depth the depth of the effect
|
|
|
|
* @param {number} baseFrequency the base frequency of the filters
|
|
|
|
*/
|
2014-08-24 23:28:42 +00:00
|
|
|
Tone.Phaser = function(){
|
2014-08-24 21:51:01 +00:00
|
|
|
|
|
|
|
//set the defaults
|
2014-08-25 14:23:37 +00:00
|
|
|
var options = this.optionsObject(arguments, ["rate", "depth", "baseFrequency"], Tone.Phaser.defaults);
|
2014-09-01 16:52:13 +00:00
|
|
|
Tone.StereoFeedbackEffect.call(this, options);
|
2014-08-24 21:51:01 +00:00
|
|
|
|
2014-09-01 16:52:13 +00:00
|
|
|
/**
|
|
|
|
* the lfo which controls the frequency on the left side
|
|
|
|
* @type {Tone.LFO}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this._lfoL = new Tone.LFO(options.rate, 0, 1);
|
2014-08-24 21:51:01 +00:00
|
|
|
|
|
|
|
/**
|
2014-09-01 16:52:13 +00:00
|
|
|
* the lfo which controls the frequency on the right side
|
2014-08-24 21:51:01 +00:00
|
|
|
* @type {Tone.LFO}
|
|
|
|
* @private
|
|
|
|
*/
|
2014-09-01 16:52:13 +00:00
|
|
|
this._lfoR = new Tone.LFO(options.rate, 0, 1);
|
2014-09-04 04:32:44 +00:00
|
|
|
this._lfoR.setPhase(180);
|
2014-08-24 21:51:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* the base modulation frequency
|
|
|
|
* @type {number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this._baseFrequency = options.baseFrequency;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* the depth of the phasing
|
|
|
|
* @type {number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this._depth = options.depth;
|
|
|
|
|
|
|
|
/**
|
2014-09-01 16:52:13 +00:00
|
|
|
* the array of filters for the left side
|
2014-08-24 21:51:01 +00:00
|
|
|
* @type {Array.<Tone.Filter>}
|
|
|
|
* @private
|
|
|
|
*/
|
2014-09-06 19:37:44 +00:00
|
|
|
this._filtersL = this._makeFilters(options.stages, this._lfoL, options.Q);
|
2014-08-24 21:51:01 +00:00
|
|
|
|
2014-09-01 16:52:13 +00:00
|
|
|
/**
|
|
|
|
* the array of filters for the left side
|
|
|
|
* @type {Array.<Tone.Filter>}
|
|
|
|
* @private
|
|
|
|
*/
|
2014-09-05 04:36:55 +00:00
|
|
|
this._filtersR = this._makeFilters(options.stages, this._lfoR, options.Q);
|
2014-09-01 16:52:13 +00:00
|
|
|
|
2014-08-24 21:51:01 +00:00
|
|
|
//connect them up
|
2014-09-01 16:52:13 +00:00
|
|
|
this.effectSendL.connect(this._filtersL[0]);
|
|
|
|
this.effectSendR.connect(this._filtersR[0]);
|
|
|
|
this._filtersL[options.stages - 1].connect(this.effectReturnL);
|
|
|
|
this._filtersR[options.stages - 1].connect(this.effectReturnR);
|
2014-09-04 04:32:44 +00:00
|
|
|
this.effectSendL.connect(this.effectReturnL);
|
|
|
|
this.effectSendR.connect(this.effectReturnR);
|
2014-09-01 16:52:13 +00:00
|
|
|
//control the frequency with one LFO
|
|
|
|
this._lfoL.frequency.connect(this._lfoR.frequency);
|
2014-08-24 21:51:01 +00:00
|
|
|
//set the options
|
|
|
|
this.setBaseFrequency(options.baseFrequency);
|
|
|
|
this.setDepth(options.depth);
|
2014-09-01 16:52:13 +00:00
|
|
|
this.setRate(options.rate);
|
2014-08-24 21:51:01 +00:00
|
|
|
//start the lfo
|
2014-09-01 16:52:13 +00:00
|
|
|
this._lfoL.start();
|
|
|
|
this._lfoR.start();
|
2014-08-24 21:51:01 +00:00
|
|
|
};
|
|
|
|
|
2014-09-01 16:52:13 +00:00
|
|
|
Tone.extend(Tone.Phaser, Tone.StereoFeedbackEffect);
|
2014-08-24 21:51:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* defaults
|
|
|
|
* @static
|
|
|
|
* @type {object}
|
|
|
|
*/
|
2014-08-25 14:23:37 +00:00
|
|
|
Tone.Phaser.defaults = {
|
2014-09-01 16:52:13 +00:00
|
|
|
"rate" : 0.5,
|
|
|
|
"depth" : 1,
|
2014-09-04 04:32:44 +00:00
|
|
|
"stages" : 4,
|
2014-09-05 04:36:55 +00:00
|
|
|
"Q" : 6,
|
2014-09-04 04:32:44 +00:00
|
|
|
"baseFrequency" : 400,
|
2014-09-01 16:52:13 +00:00
|
|
|
"feedback" : 0.6
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} stages
|
|
|
|
* @returns {Array} the number of filters all connected together
|
|
|
|
* @private
|
|
|
|
*/
|
2014-09-05 04:36:55 +00:00
|
|
|
Tone.Phaser.prototype._makeFilters = function(stages, connectToFreq, Q){
|
2014-09-01 16:52:13 +00:00
|
|
|
var filters = new Array(stages);
|
|
|
|
//make all the filters
|
|
|
|
for (var i = 0; i < stages; i++){
|
|
|
|
var filter = this.context.createBiquadFilter();
|
|
|
|
filter.type = "allpass";
|
2014-09-05 04:36:55 +00:00
|
|
|
filter.Q.value = Q;
|
2014-09-01 16:52:13 +00:00
|
|
|
connectToFreq.connect(filter.frequency);
|
|
|
|
filters[i] = filter;
|
|
|
|
}
|
|
|
|
this.chain.apply(this, filters);
|
|
|
|
return filters;
|
2014-08-24 21:51:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set the depth of the chorus
|
|
|
|
* @param {number} depth
|
|
|
|
*/
|
|
|
|
Tone.Phaser.prototype.setDepth = function(depth){
|
|
|
|
this._depth = depth;
|
2014-09-01 16:52:13 +00:00
|
|
|
var max = this._baseFrequency + this._baseFrequency * depth;
|
|
|
|
this._lfoL.setMax(max);
|
|
|
|
this._lfoR.setMax(max);
|
2014-08-24 21:51:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set the base frequency of the filters
|
|
|
|
* @param {number} freq
|
|
|
|
*/
|
|
|
|
Tone.Phaser.prototype.setBaseFrequency = function(freq){
|
|
|
|
this._baseFrequency = freq;
|
2014-09-01 16:52:13 +00:00
|
|
|
this._lfoL.setMin(freq);
|
|
|
|
this._lfoR.setMin(freq);
|
2014-08-24 21:51:01 +00:00
|
|
|
this.setDepth(this._depth);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set the phaser rate
|
|
|
|
* @param {number} rate in hertz
|
|
|
|
*/
|
|
|
|
Tone.Phaser.prototype.setRate = function(rate){
|
2014-09-01 16:52:13 +00:00
|
|
|
this._lfoL.setFrequency(rate);
|
2014-08-24 21:51:01 +00:00
|
|
|
};
|
|
|
|
|
2014-08-24 23:28:42 +00:00
|
|
|
/**
|
|
|
|
* bulk setter
|
|
|
|
* @param {object} params
|
|
|
|
*/
|
|
|
|
Tone.Phaser.prototype.set = function(params){
|
|
|
|
if (!this.isUndef(params.rate)) this.setRate(params.rate);
|
|
|
|
if (!this.isUndef(params.baseFrequency)) this.setBaseFrequency(params.baseFrequency);
|
|
|
|
if (!this.isUndef(params.depth)) this.setDepth(params.depth);
|
2014-09-01 16:52:13 +00:00
|
|
|
Tone.StereoFeedbackEffect.prototype.set.call(this, params);
|
2014-08-24 23:28:42 +00:00
|
|
|
};
|
|
|
|
|
2014-08-24 21:51:01 +00:00
|
|
|
/**
|
|
|
|
* clean up
|
|
|
|
*/
|
|
|
|
Tone.Phaser.prototype.dispose = function(){
|
2014-09-01 16:52:13 +00:00
|
|
|
Tone.StereoFeedbackEffect.prototype.dispose.call(this);
|
|
|
|
this._lfoL.dispose();
|
2014-10-23 15:41:38 +00:00
|
|
|
this._lfoL = null;
|
2014-09-01 16:52:13 +00:00
|
|
|
this._lfoR.dispose();
|
2014-10-23 15:41:38 +00:00
|
|
|
this._lfoR = null;
|
2014-09-01 16:52:13 +00:00
|
|
|
for (var i = 0; i < this._filtersL.length; i++){
|
|
|
|
this._filtersL[i].disconnect();
|
|
|
|
this._filtersL[i] = null;
|
|
|
|
}
|
|
|
|
this._filtersL = null;
|
2014-10-23 15:41:38 +00:00
|
|
|
for (var j = 0; j < this._filtersR.length; j++){
|
|
|
|
this._filtersR[j].disconnect();
|
|
|
|
this._filtersR[j] = null;
|
|
|
|
}
|
2014-09-01 16:52:13 +00:00
|
|
|
this._filtersR = null;
|
2014-08-24 21:51:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return Tone.Phaser;
|
|
|
|
});
|