2014-11-30 18:20:35 +00:00
|
|
|
define(["Tone/core/Tone", "Tone/signal/WaveShaper"], function(Tone){
|
2014-06-16 23:37:25 +00:00
|
|
|
|
2014-09-04 04:41:40 +00:00
|
|
|
"use strict";
|
2014-06-16 23:37:25 +00:00
|
|
|
|
2014-06-14 23:11:37 +00:00
|
|
|
/**
|
2014-07-04 17:47:56 +00:00
|
|
|
* @class Constant audio-rate signal.
|
|
|
|
* Tone.Signal is a core component which allows for sample-accurate
|
|
|
|
* synchronization of many components. Tone.Signal can be scheduled
|
|
|
|
* with all of the functions available to AudioParams
|
2014-06-17 16:15:10 +00:00
|
|
|
*
|
2014-06-14 23:11:37 +00:00
|
|
|
* @constructor
|
2014-12-01 04:26:42 +00:00
|
|
|
* @extends {Tone.SignalBase}
|
2014-12-03 22:20:23 +00:00
|
|
|
* @param {number} [value=0] initial value
|
2014-06-14 23:11:37 +00:00
|
|
|
*/
|
2014-04-05 22:05:42 +00:00
|
|
|
Tone.Signal = function(value){
|
2014-06-21 19:54:11 +00:00
|
|
|
|
2014-06-16 23:37:25 +00:00
|
|
|
/**
|
|
|
|
* scales the constant output to the desired output
|
|
|
|
* @type {GainNode}
|
2014-07-30 17:56:32 +00:00
|
|
|
* @private
|
2014-06-16 23:37:25 +00:00
|
|
|
*/
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar = this.context.createGain();
|
2014-10-03 19:50:21 +00:00
|
|
|
|
2014-12-01 04:26:42 +00:00
|
|
|
/**
|
|
|
|
* @type {GainNode}
|
|
|
|
*/
|
|
|
|
this.input = this.output = this.context.createGain();
|
|
|
|
|
2014-06-16 23:37:25 +00:00
|
|
|
/**
|
|
|
|
* the ratio of the this value to the control signal value
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2014-06-14 23:11:37 +00:00
|
|
|
this._syncRatio = 1;
|
2014-04-04 17:07:16 +00:00
|
|
|
|
2014-10-03 19:50:21 +00:00
|
|
|
/**
|
|
|
|
* the value of the Signal
|
|
|
|
* @type {number}
|
|
|
|
*/
|
|
|
|
this.value = this.defaultArg(value, 0);
|
|
|
|
|
2014-06-16 23:37:25 +00:00
|
|
|
//connect the constant 1 output to the node output
|
2014-12-01 02:32:09 +00:00
|
|
|
Tone.Signal._constant.chain(this._scalar, this.output);
|
2014-12-01 04:26:42 +00:00
|
|
|
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
2014-04-04 17:07:16 +00:00
|
|
|
|
2014-12-01 04:26:42 +00:00
|
|
|
Tone.extend(Tone.Signal, Tone.SignalBase);
|
2014-04-04 17:07:16 +00:00
|
|
|
|
2014-06-14 23:11:37 +00:00
|
|
|
/**
|
|
|
|
* @return {number} the current value of the signal
|
|
|
|
*/
|
2014-04-11 23:17:01 +00:00
|
|
|
Tone.Signal.prototype.getValue = function(){
|
2014-08-23 18:22:18 +00:00
|
|
|
return this._scalar.gain.value;
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set the value of the signal right away
|
|
|
|
* will be overwritten if there are previously scheduled automation curves
|
|
|
|
*
|
|
|
|
* @param {number} value
|
|
|
|
*/
|
|
|
|
Tone.Signal.prototype.setValue = function(value){
|
|
|
|
if (this._syncRatio === 0){
|
|
|
|
value = 0;
|
|
|
|
} else {
|
|
|
|
value *= this._syncRatio;
|
|
|
|
}
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.gain.value = value;
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Schedules a parameter value change at the given time.
|
|
|
|
*
|
2014-06-16 23:37:25 +00:00
|
|
|
* @param {number} value
|
|
|
|
* @param {Tone.Time} time
|
2014-06-14 23:11:37 +00:00
|
|
|
*/
|
2014-04-05 22:05:42 +00:00
|
|
|
Tone.Signal.prototype.setValueAtTime = function(value, time){
|
2014-06-14 23:11:37 +00:00
|
|
|
value *= this._syncRatio;
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.gain.setValueAtTime(value, this.toSeconds(time));
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
2014-06-18 05:36:22 +00:00
|
|
|
/**
|
|
|
|
* creates a schedule point with the current value at the current time
|
2014-06-18 20:56:50 +00:00
|
|
|
*
|
|
|
|
* @param {number=} now (optionally) pass the now value in
|
2014-06-18 05:36:22 +00:00
|
|
|
* @returns {number} the current value
|
|
|
|
*/
|
2014-06-18 20:56:50 +00:00
|
|
|
Tone.Signal.prototype.setCurrentValueNow = function(now){
|
|
|
|
now = this.defaultArg(now, this.now());
|
2014-06-18 05:36:22 +00:00
|
|
|
var currentVal = this.getValue();
|
|
|
|
this.cancelScheduledValues(now);
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.gain.setValueAtTime(currentVal, now);
|
2014-06-18 05:36:22 +00:00
|
|
|
return currentVal;
|
|
|
|
};
|
|
|
|
|
2014-06-14 23:11:37 +00:00
|
|
|
/**
|
|
|
|
* Schedules a linear continuous change in parameter value from the
|
|
|
|
* previous scheduled parameter value to the given value.
|
|
|
|
*
|
|
|
|
* @param {number} value
|
2014-06-15 21:38:59 +00:00
|
|
|
* @param {Tone.Time} endTime
|
2014-06-14 23:11:37 +00:00
|
|
|
*/
|
2014-04-05 22:05:42 +00:00
|
|
|
Tone.Signal.prototype.linearRampToValueAtTime = function(value, endTime){
|
2014-06-14 23:11:37 +00:00
|
|
|
value *= this._syncRatio;
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.gain.linearRampToValueAtTime(value, this.toSeconds(endTime));
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Schedules an exponential continuous change in parameter value from
|
|
|
|
* the previous scheduled parameter value to the given value.
|
|
|
|
*
|
|
|
|
* @param {number} value
|
2014-06-15 21:38:59 +00:00
|
|
|
* @param {Tone.Time} endTime
|
2014-06-14 23:11:37 +00:00
|
|
|
*/
|
2014-04-05 22:05:42 +00:00
|
|
|
Tone.Signal.prototype.exponentialRampToValueAtTime = function(value, endTime){
|
2014-06-14 23:11:37 +00:00
|
|
|
value *= this._syncRatio;
|
2014-12-06 21:47:48 +00:00
|
|
|
//can't go below a certain value
|
|
|
|
value = Math.max(0.00001, value);
|
|
|
|
this._scalar.gain.exponentialRampToValueAtTime(value, this.toSeconds(endTime));
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
2014-06-18 05:36:22 +00:00
|
|
|
/**
|
|
|
|
* Schedules an exponential continuous change in parameter value from
|
|
|
|
* the current time and current value to the given value.
|
|
|
|
*
|
|
|
|
* @param {number} value
|
|
|
|
* @param {Tone.Time} endTime
|
|
|
|
*/
|
|
|
|
Tone.Signal.prototype.exponentialRampToValueNow = function(value, endTime){
|
2014-06-18 20:56:50 +00:00
|
|
|
var now = this.now();
|
|
|
|
this.setCurrentValueNow(now);
|
2014-06-18 05:36:22 +00:00
|
|
|
//make sure that the endTime doesn't start with +
|
|
|
|
if (endTime.toString().charAt(0) === "+"){
|
|
|
|
endTime = endTime.substr(1);
|
|
|
|
}
|
2014-09-06 19:57:01 +00:00
|
|
|
this.exponentialRampToValueAtTime(value, now + this.toSeconds(endTime));
|
2014-06-18 05:36:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Schedules an linear continuous change in parameter value from
|
|
|
|
* the current time and current value to the given value at the given time.
|
|
|
|
*
|
|
|
|
* @param {number} value
|
|
|
|
* @param {Tone.Time} endTime
|
|
|
|
*/
|
2014-06-18 16:50:00 +00:00
|
|
|
Tone.Signal.prototype.linearRampToValueNow = function(value, endTime){
|
2014-06-18 20:56:50 +00:00
|
|
|
var now = this.now();
|
|
|
|
this.setCurrentValueNow(now);
|
2014-06-18 05:36:22 +00:00
|
|
|
value *= this._syncRatio;
|
|
|
|
//make sure that the endTime doesn't start with +
|
|
|
|
if (endTime.toString().charAt(0) === "+"){
|
|
|
|
endTime = endTime.substr(1);
|
|
|
|
}
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.gain.linearRampToValueAtTime(value, now + this.toSeconds(endTime));
|
2014-06-18 05:36:22 +00:00
|
|
|
};
|
|
|
|
|
2014-06-14 23:11:37 +00:00
|
|
|
/**
|
|
|
|
* Start exponentially approaching the target value at the given time with
|
|
|
|
* a rate having the given time constant.
|
|
|
|
*
|
|
|
|
* @param {number} value
|
2014-06-15 21:38:59 +00:00
|
|
|
* @param {Tone.Time} startTime
|
2014-06-14 23:11:37 +00:00
|
|
|
* @param {number} timeConstant
|
|
|
|
*/
|
|
|
|
Tone.Signal.prototype.setTargetAtTime = function(value, startTime, timeConstant){
|
|
|
|
value *= this._syncRatio;
|
2014-09-03 21:31:51 +00:00
|
|
|
this._scalar.gain.setTargetAtTime(value, this.toSeconds(startTime), timeConstant);
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets an array of arbitrary parameter values starting at the given time
|
|
|
|
* for the given duration.
|
|
|
|
*
|
|
|
|
* @param {Array<number>} values
|
2014-06-15 21:38:59 +00:00
|
|
|
* @param {Tone.Time} startTime
|
|
|
|
* @param {Tone.Time} duration
|
2014-06-14 23:11:37 +00:00
|
|
|
*/
|
2014-04-05 22:05:42 +00:00
|
|
|
Tone.Signal.prototype.setValueCurveAtTime = function(values, startTime, duration){
|
2014-06-14 23:11:37 +00:00
|
|
|
for (var i = 0; i < values.length; i++){
|
|
|
|
values[i] *= this._syncRatio;
|
|
|
|
}
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.gain.setValueCurveAtTime(values, this.toSeconds(startTime), this.toSeconds(duration));
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cancels all scheduled parameter changes with times greater than or
|
|
|
|
* equal to startTime.
|
|
|
|
*
|
2014-06-15 21:38:59 +00:00
|
|
|
* @param {Tone.Time} startTime
|
2014-06-14 23:11:37 +00:00
|
|
|
*/
|
2014-04-05 22:05:42 +00:00
|
|
|
Tone.Signal.prototype.cancelScheduledValues = function(startTime){
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.gain.cancelScheduledValues(this.toSeconds(startTime));
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2014-06-16 23:37:25 +00:00
|
|
|
* Sync this to another signal and it will always maintain the
|
|
|
|
* ratio between the two signals until it is unsynced
|
2014-06-20 05:23:47 +00:00
|
|
|
*
|
|
|
|
* Signals can only be synced to one other signal. while syncing,
|
|
|
|
* if a signal's value is changed, the new ratio between the signals
|
|
|
|
* is maintained as the syncing signal is changed.
|
2014-06-14 23:11:37 +00:00
|
|
|
*
|
|
|
|
* @param {Tone.Signal} signal to sync to
|
2014-06-20 05:23:47 +00:00
|
|
|
* @param {number=} ratio optionally pass in the ratio between
|
|
|
|
* the two signals, otherwise it will be computed
|
2014-06-14 23:11:37 +00:00
|
|
|
*/
|
2014-06-20 05:23:47 +00:00
|
|
|
Tone.Signal.prototype.sync = function(signal, ratio){
|
|
|
|
if (ratio){
|
|
|
|
this._syncRatio = ratio;
|
2014-06-14 23:11:37 +00:00
|
|
|
} else {
|
2014-06-20 05:23:47 +00:00
|
|
|
//get the sync ratio
|
|
|
|
if (signal.getValue() !== 0){
|
|
|
|
this._syncRatio = this.getValue() / signal.getValue();
|
|
|
|
} else {
|
|
|
|
this._syncRatio = 0;
|
|
|
|
}
|
2014-06-14 23:11:37 +00:00
|
|
|
}
|
2014-06-16 23:37:25 +00:00
|
|
|
//make a new scalar which is not connected to the constant signal
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.disconnect();
|
|
|
|
this._scalar = this.context.createGain();
|
2014-11-30 22:37:29 +00:00
|
|
|
this.connectSeries(signal, this._scalar, this.output);
|
2014-06-16 23:37:25 +00:00
|
|
|
//set it ot the sync ratio
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.gain.value = this._syncRatio;
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* unbind the signal control
|
|
|
|
*
|
|
|
|
* will leave the signal value as it was without the influence of the control signal
|
|
|
|
*/
|
|
|
|
Tone.Signal.prototype.unsync = function(){
|
|
|
|
//make a new scalar so that it's disconnected from the control signal
|
|
|
|
//get the current gain
|
2014-06-16 23:37:25 +00:00
|
|
|
var currentGain = this.getValue();
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.disconnect();
|
|
|
|
this._scalar = this.context.createGain();
|
|
|
|
this._scalar.gain.value = currentGain / this._syncRatio;
|
2014-06-14 23:11:37 +00:00
|
|
|
this._syncRatio = 1;
|
2014-06-16 23:37:25 +00:00
|
|
|
//reconnect things up
|
2014-12-01 04:26:42 +00:00
|
|
|
Tone.Signal._constant.chain(this._scalar, this.output);
|
2014-06-14 23:11:37 +00:00
|
|
|
};
|
2014-04-04 17:07:16 +00:00
|
|
|
|
2014-06-19 02:35:31 +00:00
|
|
|
/**
|
|
|
|
* internal dispose method to tear down the node
|
|
|
|
*/
|
|
|
|
Tone.Signal.prototype.dispose = function(){
|
2014-09-06 22:55:11 +00:00
|
|
|
Tone.prototype.dispose.call(this);
|
2014-08-23 18:22:18 +00:00
|
|
|
this._scalar.disconnect();
|
|
|
|
this._scalar = null;
|
2014-06-19 02:35:31 +00:00
|
|
|
};
|
|
|
|
|
2014-10-03 19:50:21 +00:00
|
|
|
//defines getter / setter for value
|
|
|
|
Object.defineProperty(Tone.Signal.prototype, "value", {
|
|
|
|
get : function(){
|
|
|
|
return this.getValue();
|
|
|
|
},
|
|
|
|
set : function(val){
|
|
|
|
this.setValue(val);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2014-07-30 17:56:32 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// STATIC
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/**
|
2014-11-30 18:20:35 +00:00
|
|
|
* the constant signal generator
|
2014-07-30 17:56:32 +00:00
|
|
|
* @static
|
|
|
|
* @private
|
2014-11-30 18:20:35 +00:00
|
|
|
* @const
|
|
|
|
* @type {OscillatorNode}
|
2014-07-30 17:56:32 +00:00
|
|
|
*/
|
2014-11-30 18:20:35 +00:00
|
|
|
Tone.Signal._generator = null;
|
2014-07-30 17:56:32 +00:00
|
|
|
|
|
|
|
/**
|
2014-11-30 18:20:35 +00:00
|
|
|
* the signal generator waveshaper. makes the incoming signal
|
|
|
|
* only output 1 for all inputs.
|
2014-07-30 17:56:32 +00:00
|
|
|
* @static
|
|
|
|
* @private
|
2014-11-30 18:20:35 +00:00
|
|
|
* @const
|
|
|
|
* @type {Tone.WaveShaper}
|
2014-07-30 17:56:32 +00:00
|
|
|
*/
|
2014-11-30 18:20:35 +00:00
|
|
|
Tone.Signal._constant = null;
|
2014-07-30 17:56:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* initializer function
|
|
|
|
*/
|
|
|
|
Tone._initAudioContext(function(audioContext){
|
2014-11-30 18:20:35 +00:00
|
|
|
Tone.Signal._generator = audioContext.createOscillator();
|
|
|
|
Tone.Signal._constant = new Tone.WaveShaper([1,1]);
|
|
|
|
Tone.Signal._generator.connect(Tone.Signal._constant);
|
|
|
|
Tone.Signal._generator.start(0);
|
|
|
|
Tone.Signal._generator.noGC();
|
2014-07-30 17:56:32 +00:00
|
|
|
});
|
|
|
|
|
2014-04-05 22:05:42 +00:00
|
|
|
return Tone.Signal;
|
2014-06-14 23:11:37 +00:00
|
|
|
});
|