mirror of
https://github.com/Tonejs/Tone.js
synced 2025-01-08 18:08:46 +00:00
f86639fc8e
sums area under scheduling curve. approximates exponential and target curves using multiple linear ramps
149 lines
No EOL
4.8 KiB
JavaScript
149 lines
No EOL
4.8 KiB
JavaScript
define(["Tone/core/Tone", "Tone/signal/TimelineSignal"], function (Tone) {
|
|
|
|
/**
|
|
* @class Tone.TickSignal extends Tone.TimelineSignal, but adds the capability
|
|
* to calculate the number of elapsed ticks. exponential and target curves
|
|
* are approximated with multiple linear ramps.
|
|
* @param {Number} value The initial value of the signal
|
|
* @extends {Tone.TimelineSignal}
|
|
*/
|
|
Tone.TickSignal = function(value){
|
|
|
|
Tone.TimelineSignal.call(this, {
|
|
"units" : Tone.Type.Ticks,
|
|
"value" : value
|
|
});
|
|
|
|
//extend the memory
|
|
this._events.memory = Infinity;
|
|
};
|
|
|
|
Tone.extend(Tone.TickSignal, Tone.TimelineSignal);
|
|
|
|
/**
|
|
* Wraps Tone.TimelineSignal methods so that they also
|
|
* record the ticks.
|
|
* @param {Function} method
|
|
* @return {Function}
|
|
* @private
|
|
*/
|
|
function _wrapScheduleMethods(method){
|
|
return function(value, time){
|
|
time = this.toSeconds(time);
|
|
method.apply(this, arguments);
|
|
var event = this._events.get(time);
|
|
event.ticks = Math.max(this.getTickAtTime(event.time - this.sampleTime), 0);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
Tone.TickSignal.prototype.setValueAtTime = _wrapScheduleMethods(Tone.TimelineSignal.prototype.setValueAtTime);
|
|
Tone.TickSignal.prototype.linearRampToValueAtTime = _wrapScheduleMethods(Tone.TimelineSignal.prototype.linearRampToValueAtTime);
|
|
|
|
/**
|
|
* Start exponentially approaching the target value at the given time with
|
|
* a rate having the given time constant.
|
|
* @param {number} value
|
|
* @param {Time} startTime
|
|
* @param {number} timeConstant
|
|
* @returns {Tone.TickSignal} this
|
|
*/
|
|
Tone.TickSignal.prototype.setTargetAtTime = function(value, time, constant){
|
|
//aproximate it with multiple linear ramps
|
|
time = this.toSeconds(time);
|
|
this.setRampPoint(time);
|
|
//start from previously scheduled value
|
|
var prevEvent = this._events.get(time);
|
|
var segments = 5;
|
|
var segmentDur = constant;
|
|
for (var i = 0; i <= segments; i++){
|
|
var segTime = segmentDur * i + time;
|
|
var rampVal = this._exponentialApproach(prevEvent.time, prevEvent.value, value, constant, segTime);
|
|
this.linearRampToValueAtTime(rampVal, segTime);
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Schedules an exponential continuous change in parameter value from
|
|
* the previous scheduled parameter value to the given value.
|
|
* @param {number} value
|
|
* @param {Time} endTime
|
|
* @returns {Tone.TickSignal} this
|
|
*/
|
|
Tone.TickSignal.prototype.exponentialRampToValueAtTime = function(value, time){
|
|
//aproximate it with multiple linear ramps
|
|
time = this.toSeconds(time);
|
|
//start from previously scheduled value
|
|
var prevEvent = this._events.get(time);
|
|
if (prevEvent === null){
|
|
prevEvent = {
|
|
"value" : this._initial,
|
|
"time" : 0
|
|
};
|
|
}
|
|
var segments = 5;
|
|
var segmentDur = ((time - prevEvent.time)/segments);
|
|
for (var i = 0; i <= segments; i++){
|
|
var segTime = segmentDur * i + prevEvent.time;
|
|
var rampVal = this._exponentialInterpolate(prevEvent.time, prevEvent.value, time, value, segTime);
|
|
this.linearRampToValueAtTime(rampVal, segTime);
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Calculates the number of ticks elapsed between the given interval
|
|
* @param {Number} time0
|
|
* @param {Number} time1
|
|
* @param {Tone.TimelineSignal.Type} curve
|
|
* @return {Ticks}
|
|
* @private
|
|
*/
|
|
Tone.TickSignal.prototype._getElapsedTicksBetween = function(time0, time1, curve){
|
|
var val0 = this.getValueAtTime(time0);
|
|
var val1 = this.getValueAtTime(time1);
|
|
return 0.5 * (time1 - time0) * (val0 + val1);
|
|
};
|
|
|
|
/**
|
|
* Returns the tick value at the time. Takes into account
|
|
* any automation curves scheduled on the signal.
|
|
* @param {Time} time The time to get the tick count at
|
|
* @return {Ticks} The number of ticks which have elapsed at the time
|
|
* given any automations.
|
|
*/
|
|
Tone.TickSignal.prototype.getTickAtTime = function(time){
|
|
time = this.toSeconds(time);
|
|
var event = this._events.get(time);
|
|
if (event !== null){
|
|
return this._getElapsedTicksBetween(event.time, time, event.type) + event.ticks;
|
|
} else {
|
|
//from the start
|
|
return this._getElapsedTicksBetween(0, time, Tone.TimelineSignal.Type.Set);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Given a tick, returns the time that tick occurs at.
|
|
* @param {Ticks} tick
|
|
* @return {Time} The time that the tick occurs.
|
|
*/
|
|
Tone.TickSignal.prototype.getTimeOfTick = function(tick){
|
|
var before = this._events.get(tick, "ticks");
|
|
var after = this._events.getAfter(tick, "ticks");
|
|
if (before !== null && after !== null && after.type === Tone.TimelineSignal.Type.Linear){
|
|
return this._linearInterpolate(before.ticks, before.time, after.ticks, after.time, tick);
|
|
} else if (before !== null){
|
|
if (before.value === 0){
|
|
return Infinity;
|
|
} else {
|
|
return before.time + (tick - before.ticks) / before.value;
|
|
}
|
|
} else {
|
|
return tick / this._initial;
|
|
}
|
|
};
|
|
|
|
return Tone.TickSignal;
|
|
}); |