mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 16:48:00 +00:00
Tone.TickSignal calculates elapsed ticks
sums area under scheduling curve. approximates exponential and target curves using multiple linear ramps
This commit is contained in:
parent
470cc4520f
commit
f86639fc8e
1 changed files with 149 additions and 0 deletions
149
Tone/signal/TickSignal.js
Normal file
149
Tone/signal/TickSignal.js
Normal file
|
@ -0,0 +1,149 @@
|
|||
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;
|
||||
});
|
Loading…
Reference in a new issue