2015-02-21 19:05:12 +00:00
|
|
|
define(["Tone/core/Tone", "Tone/core/Clock", "Tone/signal/Signal", "Tone/signal/Multiply"],
|
2014-06-16 00:59:49 +00:00
|
|
|
function(Tone){
|
|
|
|
|
2014-09-04 04:41:40 +00:00
|
|
|
"use strict";
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
2015-02-25 21:18:40 +00:00
|
|
|
* @class Oscillator-based transport allows for simple musical timing
|
|
|
|
* supports tempo curves and time changes. Do not construct
|
|
|
|
* an instance of the transport. One is automatically created
|
|
|
|
* on init and additional transports cannot be created. <br><br>
|
|
|
|
* If you need to schedule highly independent callback functions,
|
|
|
|
* check out {@link Tone.Clock}.
|
2014-06-16 00:59:49 +00:00
|
|
|
*
|
2014-06-18 19:39:10 +00:00
|
|
|
* @extends {Tone}
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport = function(){
|
2014-06-16 00:59:49 +00:00
|
|
|
|
2014-06-17 22:46:24 +00:00
|
|
|
/**
|
|
|
|
* watches the main oscillator for timing ticks
|
2014-07-30 17:54:55 +00:00
|
|
|
* initially starts at 120bpm
|
2014-06-17 22:46:24 +00:00
|
|
|
*
|
|
|
|
* @private
|
2014-07-30 17:54:55 +00:00
|
|
|
* @type {Tone.Clock}
|
2014-06-17 22:46:24 +00:00
|
|
|
*/
|
2015-02-21 19:05:12 +00:00
|
|
|
this._clock = new Tone.Clock(0, this._processTick.bind(this));
|
2015-05-05 19:36:06 +00:00
|
|
|
this._clock.onended = this._onended.bind(this);
|
2014-04-11 23:17:01 +00:00
|
|
|
|
2014-06-23 04:53:59 +00:00
|
|
|
/**
|
2015-02-21 19:05:12 +00:00
|
|
|
* If the transport loops or not.
|
2014-06-23 04:53:59 +00:00
|
|
|
* @type {boolean}
|
|
|
|
*/
|
2014-04-06 00:47:59 +00:00
|
|
|
this.loop = false;
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-06-18 19:10:18 +00:00
|
|
|
/**
|
2015-02-21 19:05:12 +00:00
|
|
|
* the bpm value
|
2015-06-13 23:50:39 +00:00
|
|
|
* @type {BPM}
|
|
|
|
* @signal
|
2015-02-21 19:05:12 +00:00
|
|
|
*/
|
2015-05-23 22:57:05 +00:00
|
|
|
this.bpm = new Tone.Signal(120, Tone.Type.BPM);
|
2015-02-21 19:05:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* the signal scalar
|
|
|
|
* @type {Tone.Multiply}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this._bpmMult = new Tone.Multiply(1/60 * tatum);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The state of the transport.
|
2015-05-23 22:57:05 +00:00
|
|
|
* @type {Tone.State}
|
2014-06-18 19:10:18 +00:00
|
|
|
*/
|
2015-05-23 22:57:05 +00:00
|
|
|
this.state = Tone.State.Stopped;
|
2015-02-21 19:05:12 +00:00
|
|
|
|
|
|
|
//connect it all up
|
|
|
|
this.bpm.chain(this._bpmMult, this._clock.frequency);
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
|
|
|
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.extend(Tone.Transport);
|
2014-06-16 00:59:49 +00:00
|
|
|
|
2015-02-24 03:14:22 +00:00
|
|
|
/**
|
|
|
|
* the defaults
|
|
|
|
* @type {Object}
|
|
|
|
* @const
|
|
|
|
* @static
|
|
|
|
*/
|
|
|
|
Tone.Transport.defaults = {
|
|
|
|
"bpm" : 120,
|
|
|
|
"swing" : 0,
|
|
|
|
"swingSubdivision" : "16n",
|
|
|
|
"timeSignature" : 4,
|
|
|
|
"loopStart" : 0,
|
|
|
|
"loopEnd" : "4m"
|
|
|
|
};
|
|
|
|
|
2015-02-21 19:05:12 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
|
|
|
var tatum = 12;
|
|
|
|
|
2014-06-23 17:30:38 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
|
|
|
var timelineTicks = 0;
|
2014-07-30 17:54:55 +00:00
|
|
|
|
2014-06-18 21:39:05 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2014-06-16 00:59:49 +00:00
|
|
|
var transportTicks = 0;
|
2014-07-30 17:54:55 +00:00
|
|
|
|
2015-02-21 19:05:12 +00:00
|
|
|
/**
|
|
|
|
* Which subdivision the swing is applied to.
|
|
|
|
* defaults to an 16th note
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
2014-06-18 21:39:05 +00:00
|
|
|
*/
|
2015-02-21 19:05:12 +00:00
|
|
|
var swingSubdivision = "16n";
|
2014-07-30 17:54:55 +00:00
|
|
|
|
2014-09-25 03:46:57 +00:00
|
|
|
/**
|
|
|
|
* controls which beat the swing is applied to
|
2014-09-30 03:42:56 +00:00
|
|
|
* defaults to an 16th note
|
2014-09-25 03:46:57 +00:00
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2014-09-30 03:42:56 +00:00
|
|
|
var swingTatum = 3;
|
2014-09-25 03:46:57 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* controls which beat the swing is applied to
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
|
|
|
var swingAmount = 0;
|
|
|
|
|
2014-06-18 21:39:05 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2014-06-18 05:35:34 +00:00
|
|
|
var transportTimeSignature = 4;
|
2014-06-16 00:59:49 +00:00
|
|
|
|
2014-06-18 21:39:05 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2014-06-16 00:59:49 +00:00
|
|
|
var loopStart = 0;
|
2014-09-25 03:46:57 +00:00
|
|
|
|
2014-06-18 21:39:05 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2014-06-16 00:59:49 +00:00
|
|
|
var loopEnd = tatum * 4;
|
|
|
|
|
2014-06-18 21:39:05 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {Array}
|
|
|
|
*/
|
2014-06-16 00:59:49 +00:00
|
|
|
var intervals = [];
|
2014-06-18 21:41:39 +00:00
|
|
|
|
2014-06-18 21:39:05 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {Array}
|
|
|
|
*/
|
2014-06-16 00:59:49 +00:00
|
|
|
var timeouts = [];
|
2014-06-18 21:41:39 +00:00
|
|
|
|
2014-06-18 21:39:05 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {Array}
|
|
|
|
*/
|
2014-06-18 20:45:25 +00:00
|
|
|
var transportTimeline = [];
|
2014-06-18 21:41:39 +00:00
|
|
|
|
2014-06-18 21:39:05 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2014-06-16 00:59:49 +00:00
|
|
|
var timelineProgress = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* All of the synced components
|
2014-06-18 21:39:05 +00:00
|
|
|
* @private
|
|
|
|
* @type {Array<Tone>}
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-06-25 16:47:47 +00:00
|
|
|
var SyncedSources = [];
|
2014-06-16 00:59:49 +00:00
|
|
|
|
2015-02-21 19:05:12 +00:00
|
|
|
/**
|
|
|
|
* All of the synced Signals
|
|
|
|
* @private
|
|
|
|
* @type {Array<Tone.Signal>}
|
|
|
|
*/
|
|
|
|
var SyncedSignals = [];
|
|
|
|
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2014-07-30 17:54:55 +00:00
|
|
|
// TICKS
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
2014-07-30 17:54:55 +00:00
|
|
|
* called on every tick
|
|
|
|
* @param {number} tickTime clock relative tick time
|
|
|
|
* @private
|
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype._processTick = function(tickTime){
|
2015-05-23 22:57:05 +00:00
|
|
|
if (this.state === Tone.State.Started){
|
2015-02-21 19:05:12 +00:00
|
|
|
if (swingAmount > 0 &&
|
|
|
|
timelineTicks % tatum !== 0 && //not on a downbeat
|
|
|
|
timelineTicks % swingTatum === 0){
|
2014-09-25 03:46:57 +00:00
|
|
|
//add some swing
|
2015-02-25 21:18:40 +00:00
|
|
|
tickTime += this._ticksToSeconds(swingTatum) * swingAmount;
|
2014-09-25 03:46:57 +00:00
|
|
|
}
|
2014-09-14 19:34:17 +00:00
|
|
|
processIntervals(tickTime);
|
|
|
|
processTimeouts(tickTime);
|
|
|
|
processTimeline(tickTime);
|
|
|
|
transportTicks += 1;
|
|
|
|
timelineTicks += 1;
|
|
|
|
if (this.loop){
|
2014-10-25 15:57:00 +00:00
|
|
|
if (timelineTicks === loopEnd){
|
2014-09-14 19:34:17 +00:00
|
|
|
this._setTicks(loopStart);
|
|
|
|
}
|
2014-04-06 00:47:59 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-07-30 17:54:55 +00:00
|
|
|
/**
|
|
|
|
* jump to a specific tick in the timeline
|
|
|
|
* updates the timeline callbacks
|
|
|
|
*
|
|
|
|
* @param {number} ticks the tick to jump to
|
|
|
|
* @private
|
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype._setTicks = function(ticks){
|
2014-06-23 17:30:38 +00:00
|
|
|
timelineTicks = ticks;
|
2014-06-18 20:45:25 +00:00
|
|
|
for (var i = 0; i < transportTimeline.length; i++){
|
|
|
|
var timeout = transportTimeline[i];
|
2014-04-06 00:47:59 +00:00
|
|
|
if (timeout.callbackTick() >= ticks){
|
2014-06-18 05:35:34 +00:00
|
|
|
timelineProgress = i;
|
2014-04-06 00:47:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2014-06-16 00:59:49 +00:00
|
|
|
// EVENT PROCESSING
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
|
|
|
* process the intervals
|
|
|
|
* @param {number} time
|
|
|
|
*/
|
|
|
|
var processIntervals = function(time){
|
|
|
|
for (var i = 0, len = intervals.length; i<len; i++){
|
|
|
|
var interval = intervals[i];
|
|
|
|
if (interval.testInterval(transportTicks)){
|
2014-04-06 00:47:59 +00:00
|
|
|
interval.doCallback(time);
|
|
|
|
}
|
2014-03-20 03:59:38 +00:00
|
|
|
}
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* process the timeouts
|
|
|
|
* @param {number} time
|
|
|
|
*/
|
|
|
|
var processTimeouts = function(time){
|
|
|
|
var removeTimeouts = 0;
|
|
|
|
for (var i = 0, len = timeouts.length; i<len; i++){
|
|
|
|
var timeout = timeouts[i];
|
2014-04-06 00:47:59 +00:00
|
|
|
var callbackTick = timeout.callbackTick();
|
2014-06-18 05:35:34 +00:00
|
|
|
if (callbackTick <= transportTicks){
|
2014-04-06 00:47:59 +00:00
|
|
|
timeout.doCallback(time);
|
2014-06-16 00:59:49 +00:00
|
|
|
removeTimeouts++;
|
|
|
|
} else if (callbackTick > transportTicks){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//remove the timeouts off the front of the array after they've been called
|
|
|
|
timeouts.splice(0, removeTimeouts);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2014-06-18 20:45:25 +00:00
|
|
|
* process the transportTimeline events
|
2014-06-16 00:59:49 +00:00
|
|
|
* @param {number} time
|
|
|
|
*/
|
|
|
|
var processTimeline = function(time){
|
2014-06-18 20:45:25 +00:00
|
|
|
for (var i = timelineProgress, len = transportTimeline.length; i<len; i++){
|
|
|
|
var evnt = transportTimeline[i];
|
2014-06-16 00:59:49 +00:00
|
|
|
var callbackTick = evnt.callbackTick();
|
2014-06-23 17:30:38 +00:00
|
|
|
if (callbackTick === timelineTicks){
|
2014-06-16 00:59:49 +00:00
|
|
|
timelineProgress = i;
|
2014-09-14 19:34:17 +00:00
|
|
|
evnt.doCallback(time);
|
2014-06-23 17:30:38 +00:00
|
|
|
} else if (callbackTick > timelineTicks){
|
2014-04-06 00:47:59 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-03-20 03:59:38 +00:00
|
|
|
}
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// INTERVAL
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
2015-02-28 04:24:51 +00:00
|
|
|
* Set a callback for a recurring event.
|
2014-09-11 17:38:41 +00:00
|
|
|
*
|
2015-02-28 04:24:51 +00:00
|
|
|
* @param {function} callback
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} interval
|
2015-02-28 04:24:51 +00:00
|
|
|
* @return {number} the id of the interval
|
|
|
|
* @example
|
2014-09-11 17:38:41 +00:00
|
|
|
* //triggers a callback every 8th note with the exact time of the event
|
|
|
|
* Tone.Transport.setInterval(function(time){
|
|
|
|
* envelope.triggerAttack(time);
|
|
|
|
* }, "8n");
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.setInterval = function(callback, interval, ctx){
|
2015-02-25 21:18:40 +00:00
|
|
|
var tickTime = this._toTicks(interval);
|
2014-06-16 00:59:49 +00:00
|
|
|
var timeout = new TimelineEvent(callback, ctx, tickTime, transportTicks);
|
|
|
|
intervals.push(timeout);
|
|
|
|
return timeout.id;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clear an interval from the processing array
|
|
|
|
* @param {number} rmInterval the interval to remove
|
|
|
|
* @return {boolean} true if the event was removed
|
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.clearInterval = function(rmInterval){
|
2014-06-16 00:59:49 +00:00
|
|
|
for (var i = 0; i < intervals.length; i++){
|
|
|
|
var interval = intervals[i];
|
|
|
|
if (interval.id === rmInterval){
|
|
|
|
intervals.splice(i, 1);
|
2014-04-06 00:47:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
2014-03-19 21:25:33 +00:00
|
|
|
}
|
2014-04-06 00:47:59 +00:00
|
|
|
return false;
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
2014-04-06 00:47:59 +00:00
|
|
|
|
2014-06-18 20:45:25 +00:00
|
|
|
/**
|
|
|
|
* removes all of the intervals that are currently set
|
2015-01-06 04:33:05 +00:00
|
|
|
* @return {boolean} true if the event was removed
|
2014-06-18 20:45:25 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.clearIntervals = function(){
|
2015-01-06 04:33:05 +00:00
|
|
|
var willRemove = intervals.length > 0;
|
2014-06-18 20:45:25 +00:00
|
|
|
intervals = [];
|
2015-01-06 04:33:05 +00:00
|
|
|
return willRemove;
|
2014-06-18 20:45:25 +00:00
|
|
|
};
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TIMEOUT
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/**
|
2015-02-28 04:24:51 +00:00
|
|
|
* Set a timeout to occur after time from now. NB: the transport must be
|
2014-09-11 17:38:41 +00:00
|
|
|
* running for this to be triggered. All timeout events are cleared when the
|
|
|
|
* transport is stopped.
|
|
|
|
*
|
2015-02-28 04:24:51 +00:00
|
|
|
* @param {function} callback
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} time
|
2015-02-28 04:24:51 +00:00
|
|
|
* @return {number} the id of the timeout for clearing timeouts
|
|
|
|
* @example
|
2014-09-11 17:38:41 +00:00
|
|
|
* //trigger an event to happen 1 second from now
|
|
|
|
* Tone.Transport.setTimeout(function(time){
|
|
|
|
* player.start(time);
|
|
|
|
* }, 1)
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.setTimeout = function(callback, time, ctx){
|
2015-02-25 21:18:40 +00:00
|
|
|
var ticks = this._toTicks(time);
|
2014-06-16 00:59:49 +00:00
|
|
|
var timeout = new TimelineEvent(callback, ctx, ticks + transportTicks, 0);
|
2014-04-06 00:47:59 +00:00
|
|
|
//put it in the right spot
|
2014-06-16 00:59:49 +00:00
|
|
|
for (var i = 0, len = timeouts.length; i<len; i++){
|
|
|
|
var testEvnt = timeouts[i];
|
|
|
|
if (testEvnt.callbackTick() > timeout.callbackTick()){
|
|
|
|
timeouts.splice(i, 0, timeout);
|
|
|
|
return timeout.id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//otherwise push it on the end
|
|
|
|
timeouts.push(timeout);
|
|
|
|
return timeout.id;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clear the timeout based on it's ID
|
|
|
|
* @param {number} timeoutID
|
|
|
|
* @return {boolean} true if the timeout was removed
|
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.clearTimeout = function(timeoutID){
|
2014-06-16 00:59:49 +00:00
|
|
|
for (var i = 0; i < timeouts.length; i++){
|
|
|
|
var testTimeout = timeouts[i];
|
|
|
|
if (testTimeout.id === timeoutID){
|
|
|
|
timeouts.splice(i, 1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2014-06-18 20:45:25 +00:00
|
|
|
/**
|
|
|
|
* removes all of the timeouts that are currently set
|
2015-01-06 04:33:05 +00:00
|
|
|
* @return {boolean} true if the event was removed
|
2014-06-18 20:45:25 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.clearTimeouts = function(){
|
2015-01-06 04:33:05 +00:00
|
|
|
var willRemove = timeouts.length > 0;
|
2014-06-18 20:45:25 +00:00
|
|
|
timeouts = [];
|
2015-01-06 04:33:05 +00:00
|
|
|
return willRemove;
|
2014-06-18 20:45:25 +00:00
|
|
|
};
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TIMELINE
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/**
|
2014-09-11 02:37:57 +00:00
|
|
|
* Timeline events are synced to the transportTimeline of the Tone.Transport
|
2014-06-16 00:59:49 +00:00
|
|
|
* Unlike Timeout, Timeline events will restart after the
|
2014-09-11 02:37:57 +00:00
|
|
|
* Tone.Transport has been stopped and restarted.
|
2014-06-16 00:59:49 +00:00
|
|
|
*
|
2015-02-28 04:24:51 +00:00
|
|
|
* @param {function} callback
|
|
|
|
* @param {Tome.Time} timeout
|
|
|
|
* @return {number} the id for clearing the transportTimeline event
|
|
|
|
* @example
|
2014-09-11 17:38:41 +00:00
|
|
|
* //trigger the start of a part on the 16th measure
|
|
|
|
* Tone.Transport.setTimeline(function(time){
|
|
|
|
* part.start(time);
|
|
|
|
* }, "16m");
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.setTimeline = function(callback, timeout, ctx){
|
2015-02-25 21:18:40 +00:00
|
|
|
var ticks = this._toTicks(timeout);
|
2014-06-23 17:30:38 +00:00
|
|
|
var timelineEvnt = new TimelineEvent(callback, ctx, ticks, 0);
|
2014-04-16 20:47:25 +00:00
|
|
|
//put it in the right spot
|
2014-06-18 20:45:25 +00:00
|
|
|
for (var i = timelineProgress, len = transportTimeline.length; i<len; i++){
|
|
|
|
var testEvnt = transportTimeline[i];
|
2014-06-16 00:59:49 +00:00
|
|
|
if (testEvnt.callbackTick() > timelineEvnt.callbackTick()){
|
2014-06-18 20:45:25 +00:00
|
|
|
transportTimeline.splice(i, 0, timelineEvnt);
|
2014-06-16 00:59:49 +00:00
|
|
|
return timelineEvnt.id;
|
2014-04-06 00:47:59 +00:00
|
|
|
}
|
2014-03-19 21:25:33 +00:00
|
|
|
}
|
2014-04-06 00:47:59 +00:00
|
|
|
//otherwise push it on the end
|
2014-06-18 20:45:25 +00:00
|
|
|
transportTimeline.push(timelineEvnt);
|
2014-06-16 00:59:49 +00:00
|
|
|
return timelineEvnt.id;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2014-06-18 20:45:25 +00:00
|
|
|
* clear the transportTimeline event from the
|
2014-06-16 00:59:49 +00:00
|
|
|
* @param {number} timelineID
|
|
|
|
* @return {boolean} true if it was removed
|
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.clearTimeline = function(timelineID){
|
2014-06-18 20:45:25 +00:00
|
|
|
for (var i = 0; i < transportTimeline.length; i++){
|
|
|
|
var testTimeline = transportTimeline[i];
|
2014-06-16 00:59:49 +00:00
|
|
|
if (testTimeline.id === timelineID){
|
2014-06-18 20:45:25 +00:00
|
|
|
transportTimeline.splice(i, 1);
|
2014-04-06 00:47:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
2014-03-19 21:25:33 +00:00
|
|
|
}
|
2014-04-06 00:47:59 +00:00
|
|
|
return false;
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
2014-04-06 00:47:59 +00:00
|
|
|
|
2014-06-18 20:45:25 +00:00
|
|
|
/**
|
|
|
|
* remove all events from the timeline
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {boolean} true if the events were removed
|
2014-06-18 20:45:25 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.clearTimelines = function(){
|
2014-06-18 20:45:25 +00:00
|
|
|
timelineProgress = 0;
|
2015-01-06 04:33:05 +00:00
|
|
|
var willRemove = transportTimeline.length > 0;
|
2014-06-18 20:45:25 +00:00
|
|
|
transportTimeline = [];
|
2015-01-06 04:33:05 +00:00
|
|
|
return willRemove;
|
2014-06-18 20:45:25 +00:00
|
|
|
};
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TIME CONVERSIONS
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/**
|
|
|
|
* turns the time into
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} time
|
2015-02-25 21:18:40 +00:00
|
|
|
* @return {number}
|
|
|
|
* @private
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2015-02-25 21:18:40 +00:00
|
|
|
Tone.Transport.prototype._toTicks = function(time){
|
2014-04-11 23:17:01 +00:00
|
|
|
//get the seconds
|
|
|
|
var seconds = this.toSeconds(time);
|
|
|
|
var quarter = this.notationToSeconds("4n");
|
|
|
|
var quarters = seconds / quarter;
|
2014-06-16 00:59:49 +00:00
|
|
|
var tickNum = quarters * tatum;
|
2014-04-06 00:47:59 +00:00
|
|
|
//quantize to tick value
|
2014-06-16 00:59:49 +00:00
|
|
|
return Math.round(tickNum);
|
|
|
|
};
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-06-18 05:35:34 +00:00
|
|
|
/**
|
2015-02-21 19:05:12 +00:00
|
|
|
* convert ticks into seconds
|
|
|
|
*
|
|
|
|
* @param {number} ticks
|
|
|
|
* @param {number=} bpm
|
|
|
|
* @param {number=} timeSignature
|
|
|
|
* @return {number} seconds
|
2015-02-25 21:18:40 +00:00
|
|
|
* @private
|
2014-06-18 05:35:34 +00:00
|
|
|
*/
|
2015-02-25 21:18:40 +00:00
|
|
|
Tone.Transport.prototype._ticksToSeconds = function(ticks, bpm, timeSignature){
|
2015-02-21 19:05:12 +00:00
|
|
|
ticks = Math.floor(ticks);
|
|
|
|
var quater = this.notationToSeconds("4n", bpm, timeSignature);
|
|
|
|
return (quater * ticks) / (tatum);
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-12-01 03:40:07 +00:00
|
|
|
/**
|
|
|
|
* returns the time of the next beat
|
|
|
|
* @param {string} [subdivision="4n"]
|
|
|
|
* @return {number} the time in seconds of the next subdivision
|
|
|
|
*/
|
|
|
|
Tone.Transport.prototype.nextBeat = function(subdivision){
|
|
|
|
subdivision = this.defaultArg(subdivision, "4n");
|
2015-02-25 21:18:40 +00:00
|
|
|
var tickNum = this._toTicks(subdivision);
|
2014-12-01 03:40:07 +00:00
|
|
|
var remainingTicks = (transportTicks % tickNum);
|
|
|
|
var nextTick = remainingTicks;
|
|
|
|
if (remainingTicks > 0){
|
|
|
|
nextTick = tickNum - remainingTicks;
|
|
|
|
}
|
2015-02-25 21:18:40 +00:00
|
|
|
return this._ticksToSeconds(nextTick);
|
2014-12-01 03:40:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// START/STOP/PAUSE
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
|
|
|
* start the transport and all sources synced to the transport
|
|
|
|
*
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} time
|
|
|
|
* @param {Time=} offset the offset position to start
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {Tone.Transport} `this`
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-10-02 17:22:44 +00:00
|
|
|
Tone.Transport.prototype.start = function(time, offset){
|
2015-05-23 22:57:05 +00:00
|
|
|
if (this.state === Tone.State.Stopped || this.state === Tone.State.Paused){
|
2014-10-02 17:22:44 +00:00
|
|
|
if (!this.isUndef(offset)){
|
2015-02-25 21:18:40 +00:00
|
|
|
this._setTicks(this._toTicks(offset));
|
2014-10-02 17:22:44 +00:00
|
|
|
}
|
2015-05-23 22:57:05 +00:00
|
|
|
this.state = Tone.State.Started;
|
2014-06-25 16:47:47 +00:00
|
|
|
var startTime = this.toSeconds(time);
|
2014-07-30 17:54:55 +00:00
|
|
|
this._clock.start(startTime);
|
2014-06-18 19:10:18 +00:00
|
|
|
//call start on each of the synced sources
|
2014-06-25 16:47:47 +00:00
|
|
|
for (var i = 0; i < SyncedSources.length; i++){
|
|
|
|
var source = SyncedSources[i].source;
|
|
|
|
var delay = SyncedSources[i].delay;
|
|
|
|
source.start(startTime + delay);
|
|
|
|
}
|
2014-06-18 05:35:34 +00:00
|
|
|
}
|
2015-01-06 04:33:05 +00:00
|
|
|
return this;
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* stop the transport and all sources synced to the transport
|
|
|
|
*
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} time
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {Tone.Transport} `this`
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.stop = function(time){
|
2015-05-23 22:57:05 +00:00
|
|
|
if (this.state === Tone.State.Started || this.state === Tone.State.Paused){
|
2014-06-25 16:47:47 +00:00
|
|
|
var stopTime = this.toSeconds(time);
|
2015-05-05 19:36:06 +00:00
|
|
|
this._clock.stop(stopTime);
|
2014-06-25 16:47:47 +00:00
|
|
|
//call start on each of the synced sources
|
|
|
|
for (var i = 0; i < SyncedSources.length; i++){
|
|
|
|
var source = SyncedSources[i].source;
|
|
|
|
source.stop(stopTime);
|
|
|
|
}
|
2014-09-14 19:34:17 +00:00
|
|
|
} else {
|
2015-01-05 03:25:16 +00:00
|
|
|
this._onended();
|
2014-06-18 05:35:34 +00:00
|
|
|
}
|
2015-01-06 04:33:05 +00:00
|
|
|
return this;
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
|
|
|
|
2014-09-14 19:34:17 +00:00
|
|
|
/**
|
|
|
|
* invoked when the transport is stopped
|
|
|
|
* @private
|
|
|
|
*/
|
2015-01-05 03:25:16 +00:00
|
|
|
Tone.Transport.prototype._onended = function(){
|
2014-09-14 19:34:17 +00:00
|
|
|
transportTicks = 0;
|
|
|
|
this._setTicks(0);
|
|
|
|
this.clearTimeouts();
|
2015-05-23 22:57:05 +00:00
|
|
|
this.state = Tone.State.Stopped;
|
2014-09-14 19:34:17 +00:00
|
|
|
};
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
|
|
|
* pause the transport and all sources synced to the transport
|
|
|
|
*
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} time
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {Tone.Transport} `this`
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.pause = function(time){
|
2015-05-23 22:57:05 +00:00
|
|
|
if (this.state === Tone.State.Started){
|
|
|
|
this.state = Tone.State.Paused;
|
2014-06-25 16:47:47 +00:00
|
|
|
var stopTime = this.toSeconds(time);
|
2014-07-30 17:54:55 +00:00
|
|
|
this._clock.stop(stopTime);
|
2014-06-18 19:10:18 +00:00
|
|
|
//call pause on each of the synced sources
|
2014-06-25 16:47:47 +00:00
|
|
|
for (var i = 0; i < SyncedSources.length; i++){
|
|
|
|
var source = SyncedSources[i].source;
|
|
|
|
source.pause(stopTime);
|
|
|
|
}
|
2014-06-18 19:10:18 +00:00
|
|
|
}
|
2015-01-06 04:33:05 +00:00
|
|
|
return this;
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2014-04-11 23:17:01 +00:00
|
|
|
// SETTERS/GETTERS
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
2015-02-21 19:05:12 +00:00
|
|
|
* Time signature as just the numerator over 4.
|
|
|
|
* For example 4/4 would be just 4 and 6/8 would be 3.
|
|
|
|
* @memberOf Tone.Transport#
|
|
|
|
* @type {number}
|
|
|
|
* @name timeSignature
|
|
|
|
*/
|
|
|
|
Object.defineProperty(Tone.Transport.prototype, "timeSignature", {
|
|
|
|
get : function(){
|
|
|
|
return transportTimeSignature;
|
|
|
|
},
|
|
|
|
set : function(numerator){
|
|
|
|
transportTimeSignature = numerator;
|
2015-02-10 21:33:18 +00:00
|
|
|
}
|
2015-02-21 19:05:12 +00:00
|
|
|
});
|
2014-06-16 00:59:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-02-21 19:05:12 +00:00
|
|
|
* The loop start point
|
|
|
|
* @memberOf Tone.Transport#
|
2015-06-14 00:20:36 +00:00
|
|
|
* @type {Time}
|
2015-02-21 19:05:12 +00:00
|
|
|
* @name loopStart
|
|
|
|
*/
|
|
|
|
Object.defineProperty(Tone.Transport.prototype, "loopStart", {
|
|
|
|
get : function(){
|
2015-02-25 21:18:40 +00:00
|
|
|
return this._ticksToSeconds(loopStart);
|
2015-02-21 19:05:12 +00:00
|
|
|
},
|
|
|
|
set : function(startPosition){
|
2015-02-25 21:18:40 +00:00
|
|
|
loopStart = this._toTicks(startPosition);
|
2015-02-21 19:05:12 +00:00
|
|
|
}
|
|
|
|
});
|
2014-06-16 00:59:49 +00:00
|
|
|
|
|
|
|
/**
|
2015-02-21 19:05:12 +00:00
|
|
|
* The loop end point
|
|
|
|
* @memberOf Tone.Transport#
|
2015-06-14 00:20:36 +00:00
|
|
|
* @type {Time}
|
2015-02-21 19:05:12 +00:00
|
|
|
* @name loopEnd
|
|
|
|
*/
|
|
|
|
Object.defineProperty(Tone.Transport.prototype, "loopEnd", {
|
|
|
|
get : function(){
|
2015-02-25 21:18:40 +00:00
|
|
|
return this._ticksToSeconds(loopEnd);
|
2015-02-21 19:05:12 +00:00
|
|
|
},
|
|
|
|
set : function(endPosition){
|
2015-02-25 21:18:40 +00:00
|
|
|
loopEnd = this._toTicks(endPosition);
|
2015-02-21 19:05:12 +00:00
|
|
|
}
|
|
|
|
});
|
2014-06-16 00:59:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* shorthand loop setting
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} startPosition
|
|
|
|
* @param {Time} endPosition
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {Tone.Transport} `this`
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.setLoopPoints = function(startPosition, endPosition){
|
2015-02-21 19:05:12 +00:00
|
|
|
this.loopStart = startPosition;
|
|
|
|
this.loopEnd = endPosition;
|
2015-01-06 04:33:05 +00:00
|
|
|
return this;
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
|
|
|
|
2014-09-25 03:46:57 +00:00
|
|
|
/**
|
2015-02-21 19:05:12 +00:00
|
|
|
* The swing value. Between 0-1 where 1 equal to
|
|
|
|
* the note + half the subdivision.
|
|
|
|
* @memberOf Tone.Transport#
|
2015-06-14 00:20:36 +00:00
|
|
|
* @type {NormalRange}
|
2015-02-21 19:05:12 +00:00
|
|
|
* @name swing
|
|
|
|
*/
|
|
|
|
Object.defineProperty(Tone.Transport.prototype, "swing", {
|
|
|
|
get : function(){
|
|
|
|
return swingAmount * 2;
|
|
|
|
},
|
|
|
|
set : function(amount){
|
|
|
|
//scale the values to a normal range
|
|
|
|
swingAmount = amount * 0.5;
|
|
|
|
}
|
|
|
|
});
|
2014-09-25 03:46:57 +00:00
|
|
|
|
|
|
|
/**
|
2015-02-21 19:05:12 +00:00
|
|
|
* Set the subdivision which the swing will be applied to.
|
|
|
|
* The default values is a 16th note. Value must be less
|
|
|
|
* than a quarter note.
|
2014-09-30 03:42:56 +00:00
|
|
|
*
|
2014-09-25 03:46:57 +00:00
|
|
|
*
|
2015-02-21 19:05:12 +00:00
|
|
|
* @memberOf Tone.Transport#
|
2015-06-14 00:20:36 +00:00
|
|
|
* @type {Time}
|
2015-02-21 19:05:12 +00:00
|
|
|
* @name swingSubdivision
|
|
|
|
*/
|
|
|
|
Object.defineProperty(Tone.Transport.prototype, "swingSubdivision", {
|
|
|
|
get : function(){
|
|
|
|
return swingSubdivision;
|
|
|
|
},
|
|
|
|
set : function(subdivision){
|
|
|
|
//scale the values to a normal range
|
|
|
|
swingSubdivision = subdivision;
|
2015-02-25 21:18:40 +00:00
|
|
|
swingTatum = this._toTicks(subdivision);
|
2015-02-21 19:05:12 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The Transport's position in MEASURES:BEATS:SIXTEENTHS.
|
|
|
|
* Setting the value will jump to that position right away.
|
|
|
|
*
|
|
|
|
* @memberOf Tone.Transport#
|
|
|
|
* @type {string}
|
|
|
|
* @name position
|
|
|
|
*/
|
|
|
|
Object.defineProperty(Tone.Transport.prototype, "position", {
|
|
|
|
get : function(){
|
|
|
|
var quarters = timelineTicks / tatum;
|
|
|
|
var measures = Math.floor(quarters / transportTimeSignature);
|
|
|
|
var sixteenths = Math.floor((quarters % 1) * 4);
|
|
|
|
quarters = Math.floor(quarters) % transportTimeSignature;
|
|
|
|
var progress = [measures, quarters, sixteenths];
|
|
|
|
return progress.join(":");
|
|
|
|
},
|
|
|
|
set : function(progress){
|
2015-02-25 21:18:40 +00:00
|
|
|
var ticks = this._toTicks(progress);
|
2015-02-21 19:05:12 +00:00
|
|
|
this._setTicks(ticks);
|
|
|
|
}
|
|
|
|
});
|
2014-09-25 03:46:57 +00:00
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SYNCING
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-25 16:47:47 +00:00
|
|
|
/**
|
|
|
|
* Sync a source to the transport so that
|
|
|
|
* @param {Tone.Source} source the source to sync to the transport
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} delay (optionally) start the source with a delay from the transport
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {Tone.Transport} `this`
|
2014-06-25 16:47:47 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.syncSource = function(source, startDelay){
|
2014-06-25 16:47:47 +00:00
|
|
|
SyncedSources.push({
|
|
|
|
source : source,
|
|
|
|
delay : this.toSeconds(this.defaultArg(startDelay, 0))
|
|
|
|
});
|
2015-01-06 04:33:05 +00:00
|
|
|
return this;
|
2014-06-25 16:47:47 +00:00
|
|
|
};
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
|
|
|
* remove the source from the list of Synced Sources
|
|
|
|
*
|
2014-06-18 21:39:05 +00:00
|
|
|
* @param {Tone.Source} source [description]
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {Tone.Transport} `this`
|
2014-06-16 00:59:49 +00:00
|
|
|
*/
|
2014-09-11 02:37:57 +00:00
|
|
|
Tone.Transport.prototype.unsyncSource = function(source){
|
2014-06-25 16:47:47 +00:00
|
|
|
for (var i = 0; i < SyncedSources.length; i++){
|
|
|
|
if (SyncedSources[i].source === source){
|
|
|
|
SyncedSources.splice(i, 1);
|
|
|
|
}
|
|
|
|
}
|
2015-01-06 04:33:05 +00:00
|
|
|
return this;
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
|
|
|
|
2014-07-30 17:54:55 +00:00
|
|
|
/**
|
|
|
|
* attaches the signal to the tempo control signal so that
|
|
|
|
* any changes in the tempo will change the signal in the same
|
2015-02-21 19:05:12 +00:00
|
|
|
* ratio.
|
2014-07-30 17:54:55 +00:00
|
|
|
*
|
|
|
|
* @param {Tone.Signal} signal
|
2015-02-21 19:05:12 +00:00
|
|
|
* @param {number=} ratio Optionally pass in the ratio between
|
|
|
|
* the two signals. Otherwise it will be computed
|
|
|
|
* based on their current values.
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {Tone.Transport} `this`
|
2014-07-30 17:54:55 +00:00
|
|
|
*/
|
2015-02-21 19:05:12 +00:00
|
|
|
Tone.Transport.prototype.syncSignal = function(signal, ratio){
|
|
|
|
if (!ratio){
|
|
|
|
//get the sync ratio
|
|
|
|
if (signal._value.value !== 0){
|
|
|
|
ratio = signal._value.value / this.bpm.value;
|
|
|
|
} else {
|
|
|
|
ratio = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var ratioSignal = this.context.createGain();
|
|
|
|
ratioSignal.gain.value = ratio;
|
|
|
|
this.bpm.chain(ratioSignal, signal._value);
|
|
|
|
SyncedSignals.push({
|
|
|
|
"ratio" : ratioSignal,
|
|
|
|
"signal" : signal,
|
|
|
|
"initial" : signal._value.value
|
|
|
|
});
|
|
|
|
signal._value.value = 0;
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unsyncs a previously synced signal from the transport's control
|
|
|
|
* @param {Tone.Signal} signal
|
|
|
|
* @returns {Tone.Transport} `this`
|
|
|
|
*/
|
|
|
|
Tone.Transport.prototype.unsyncSignal = function(signal){
|
|
|
|
for (var i = 0; i < SyncedSignals.length; i++){
|
|
|
|
var syncedSignal = SyncedSignals[i];
|
|
|
|
if (syncedSignal.signal === signal){
|
|
|
|
syncedSignal.ratio.disconnect();
|
|
|
|
syncedSignal.signal._value.value = syncedSignal.initial;
|
|
|
|
SyncedSignals.splice(i, 1);
|
|
|
|
}
|
|
|
|
}
|
2015-01-06 04:33:05 +00:00
|
|
|
return this;
|
2014-07-30 17:54:55 +00:00
|
|
|
};
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-09-11 17:38:41 +00:00
|
|
|
/**
|
|
|
|
* clean up
|
2015-01-06 04:33:05 +00:00
|
|
|
* @returns {Tone.Transport} `this`
|
2014-09-11 17:38:41 +00:00
|
|
|
*/
|
|
|
|
Tone.Transport.prototype.dispose = function(){
|
|
|
|
this._clock.dispose();
|
|
|
|
this._clock = null;
|
2015-02-21 19:05:12 +00:00
|
|
|
this.bpm.dispose();
|
|
|
|
this.bpm = null;
|
|
|
|
this._bpmMult.dispose();
|
|
|
|
this._bpmMult = null;
|
2015-01-06 04:33:05 +00:00
|
|
|
return this;
|
2014-09-11 17:38:41 +00:00
|
|
|
};
|
|
|
|
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2014-06-16 00:59:49 +00:00
|
|
|
// TIMELINE EVENT
|
2014-04-06 00:47:59 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-16 00:59:49 +00:00
|
|
|
/**
|
|
|
|
* @static
|
|
|
|
* @type {number}
|
|
|
|
*/
|
|
|
|
var TimelineEventIDCounter = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A Timeline event
|
|
|
|
*
|
|
|
|
* @constructor
|
2015-02-25 21:18:40 +00:00
|
|
|
* @private
|
2014-06-16 00:59:49 +00:00
|
|
|
* @param {function(number)} callback
|
|
|
|
* @param {Object} context
|
|
|
|
* @param {number} tickTime
|
|
|
|
* @param {number} startTicks
|
|
|
|
*/
|
|
|
|
var TimelineEvent = function(callback, context, tickTime, startTicks){
|
|
|
|
this.startTicks = startTicks;
|
|
|
|
this.tickTime = tickTime;
|
2014-04-06 00:47:59 +00:00
|
|
|
this.callback = callback;
|
|
|
|
this.context = context;
|
2014-06-16 00:59:49 +00:00
|
|
|
this.id = TimelineEventIDCounter++;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* invoke the callback in the correct context
|
|
|
|
* passes in the playback time
|
|
|
|
*
|
|
|
|
* @param {number} playbackTime
|
|
|
|
*/
|
|
|
|
TimelineEvent.prototype.doCallback = function(playbackTime){
|
2014-04-06 00:47:59 +00:00
|
|
|
this.callback.call(this.context, playbackTime);
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get the tick which the callback is supposed to occur on
|
|
|
|
*
|
|
|
|
* @return {number}
|
|
|
|
*/
|
|
|
|
TimelineEvent.prototype.callbackTick = function(){
|
|
|
|
return this.startTicks + this.tickTime;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* test if the tick occurs on the interval
|
|
|
|
*
|
|
|
|
* @param {number} tick
|
|
|
|
* @return {boolean}
|
|
|
|
*/
|
|
|
|
TimelineEvent.prototype.testInterval = function(tick){
|
|
|
|
return (tick - this.startTicks) % this.tickTime === 0;
|
|
|
|
};
|
2014-03-20 03:59:38 +00:00
|
|
|
|
2014-03-19 21:25:33 +00:00
|
|
|
|
2014-04-11 23:17:01 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2014-06-16 05:44:00 +00:00
|
|
|
// AUGMENT TONE'S PROTOTYPE TO INCLUDE TRANSPORT TIMING
|
2014-04-11 23:17:01 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-16 05:44:00 +00:00
|
|
|
/**
|
|
|
|
* tests if a string is musical notation
|
|
|
|
* i.e.:
|
|
|
|
* 4n = quarter note
|
|
|
|
* 2m = two measures
|
|
|
|
* 8t = eighth-note triplet
|
2014-09-25 03:46:57 +00:00
|
|
|
* defined in "Tone/core/Transport"
|
2014-06-16 05:44:00 +00:00
|
|
|
*
|
|
|
|
* @return {boolean}
|
2014-06-23 18:20:16 +00:00
|
|
|
* @method isNotation
|
2014-06-23 18:52:33 +00:00
|
|
|
* @lends Tone.prototype.isNotation
|
2014-06-16 05:44:00 +00:00
|
|
|
*/
|
|
|
|
Tone.prototype.isNotation = (function(){
|
|
|
|
var notationFormat = new RegExp(/[0-9]+[mnt]$/i);
|
|
|
|
return function(note){
|
|
|
|
return notationFormat.test(note);
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tests if a string is transportTime
|
|
|
|
* i.e. :
|
|
|
|
* 1:2:0 = 1 measure + two quarter notes + 0 sixteenth notes
|
2014-09-25 03:46:57 +00:00
|
|
|
* defined in "Tone/core/Transport"
|
2014-06-16 05:44:00 +00:00
|
|
|
*
|
|
|
|
* @return {boolean}
|
2014-06-24 03:18:17 +00:00
|
|
|
*
|
|
|
|
* @method isTransportTime
|
2014-06-23 18:52:33 +00:00
|
|
|
* @lends Tone.prototype.isTransportTime
|
2014-06-16 05:44:00 +00:00
|
|
|
*/
|
|
|
|
Tone.prototype.isTransportTime = (function(){
|
2015-01-06 03:46:38 +00:00
|
|
|
var transportTimeFormat = new RegExp(/^\d+(\.\d+)?:\d+(\.\d+)?(:\d+(\.\d+)?)?$/i);
|
2014-06-16 05:44:00 +00:00
|
|
|
return function(transportTime){
|
|
|
|
return transportTimeFormat.test(transportTime);
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
|
|
|
/**
|
2014-06-23 18:20:16 +00:00
|
|
|
*
|
2014-06-16 05:44:00 +00:00
|
|
|
* convert notation format strings to seconds
|
2014-09-25 03:46:57 +00:00
|
|
|
* defined in "Tone/core/Transport"
|
|
|
|
*
|
2014-06-18 05:35:34 +00:00
|
|
|
* @param {string} notation
|
|
|
|
* @param {number=} bpm
|
|
|
|
* @param {number=} timeSignature
|
2014-06-23 18:52:33 +00:00
|
|
|
* @return {number}
|
|
|
|
*
|
2014-06-16 05:44:00 +00:00
|
|
|
*/
|
2014-06-18 05:35:34 +00:00
|
|
|
Tone.prototype.notationToSeconds = function(notation, bpm, timeSignature){
|
2015-02-21 19:05:12 +00:00
|
|
|
bpm = this.defaultArg(bpm, Tone.Transport.bpm.value);
|
2014-06-18 05:35:34 +00:00
|
|
|
timeSignature = this.defaultArg(timeSignature, transportTimeSignature);
|
2014-06-16 05:44:00 +00:00
|
|
|
var beatTime = (60 / bpm);
|
|
|
|
var subdivision = parseInt(notation, 10);
|
|
|
|
var beats = 0;
|
|
|
|
if (subdivision === 0){
|
|
|
|
beats = 0;
|
|
|
|
}
|
|
|
|
var lastLetter = notation.slice(-1);
|
|
|
|
if (lastLetter === "t"){
|
|
|
|
beats = (4 / subdivision) * 2/3;
|
|
|
|
} else if (lastLetter === "n"){
|
|
|
|
beats = 4 / subdivision;
|
|
|
|
} else if (lastLetter === "m"){
|
|
|
|
beats = subdivision * timeSignature;
|
|
|
|
} else {
|
|
|
|
beats = 0;
|
|
|
|
}
|
|
|
|
return beatTime * beats;
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
|
|
|
|
2014-06-16 05:44:00 +00:00
|
|
|
/**
|
|
|
|
* convert transportTime into seconds
|
2014-09-25 03:46:57 +00:00
|
|
|
* defined in "Tone/core/Transport"
|
2014-06-23 18:52:33 +00:00
|
|
|
*
|
|
|
|
* ie: 4:2:3 == 4 measures + 2 quarters + 3 sixteenths
|
2014-06-23 18:20:16 +00:00
|
|
|
*
|
2014-06-16 05:44:00 +00:00
|
|
|
* @param {string} transportTime
|
2014-06-18 05:35:34 +00:00
|
|
|
* @param {number=} bpm
|
|
|
|
* @param {number=} timeSignature
|
2014-06-16 05:44:00 +00:00
|
|
|
* @return {number} seconds
|
2014-06-23 18:52:33 +00:00
|
|
|
*
|
|
|
|
* @lends Tone.prototype.transportTimeToSeconds
|
2014-06-16 05:44:00 +00:00
|
|
|
*/
|
2014-06-18 05:35:34 +00:00
|
|
|
Tone.prototype.transportTimeToSeconds = function(transportTime, bpm, timeSignature){
|
2015-02-21 19:05:12 +00:00
|
|
|
bpm = this.defaultArg(bpm, Tone.Transport.bpm.value);
|
2014-06-18 05:35:34 +00:00
|
|
|
timeSignature = this.defaultArg(timeSignature, transportTimeSignature);
|
2014-06-16 05:44:00 +00:00
|
|
|
var measures = 0;
|
|
|
|
var quarters = 0;
|
|
|
|
var sixteenths = 0;
|
|
|
|
var split = transportTime.split(":");
|
|
|
|
if (split.length === 2){
|
|
|
|
measures = parseFloat(split[0]);
|
|
|
|
quarters = parseFloat(split[1]);
|
|
|
|
} else if (split.length === 1){
|
|
|
|
quarters = parseFloat(split[0]);
|
|
|
|
} else if (split.length === 3){
|
|
|
|
measures = parseFloat(split[0]);
|
|
|
|
quarters = parseFloat(split[1]);
|
|
|
|
sixteenths = parseFloat(split[2]);
|
|
|
|
}
|
|
|
|
var beats = (measures * timeSignature + quarters + sixteenths / 4);
|
2014-06-17 22:46:24 +00:00
|
|
|
return beats * this.notationToSeconds("4n");
|
2014-06-16 05:44:00 +00:00
|
|
|
};
|
2014-04-11 23:17:01 +00:00
|
|
|
|
2014-06-16 05:44:00 +00:00
|
|
|
/**
|
|
|
|
* Convert seconds to the closest transportTime in the form
|
|
|
|
* measures:quarters:sixteenths
|
2014-09-25 03:46:57 +00:00
|
|
|
* defined in "Tone/core/Transport"
|
2014-06-23 18:20:16 +00:00
|
|
|
*
|
|
|
|
* @method toTransportTime
|
|
|
|
*
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} seconds
|
2014-06-18 05:35:34 +00:00
|
|
|
* @param {number=} bpm
|
|
|
|
* @param {number=} timeSignature
|
2014-06-23 18:52:33 +00:00
|
|
|
* @return {string}
|
|
|
|
*
|
|
|
|
* @lends Tone.prototype.toTransportTime
|
2014-06-16 05:44:00 +00:00
|
|
|
*/
|
2014-06-18 05:35:34 +00:00
|
|
|
Tone.prototype.toTransportTime = function(time, bpm, timeSignature){
|
|
|
|
var seconds = this.toSeconds(time, bpm, timeSignature);
|
2015-02-21 19:05:12 +00:00
|
|
|
bpm = this.defaultArg(bpm, Tone.Transport.bpm.value);
|
2014-06-18 05:35:34 +00:00
|
|
|
timeSignature = this.defaultArg(timeSignature, transportTimeSignature);
|
2014-06-17 22:46:24 +00:00
|
|
|
var quarterTime = this.notationToSeconds("4n");
|
2014-06-16 05:44:00 +00:00
|
|
|
var quarters = seconds / quarterTime;
|
|
|
|
var measures = Math.floor(quarters / timeSignature);
|
|
|
|
var sixteenths = Math.floor((quarters % 1) * 4);
|
|
|
|
quarters = Math.floor(quarters) % timeSignature;
|
|
|
|
var progress = [measures, quarters, sixteenths];
|
|
|
|
return progress.join(":");
|
2014-06-16 00:59:49 +00:00
|
|
|
};
|
2014-04-11 23:17:01 +00:00
|
|
|
|
2014-06-17 22:46:24 +00:00
|
|
|
/**
|
2015-02-26 16:26:23 +00:00
|
|
|
* Convert a frequency representation into a number.
|
|
|
|
* Defined in "Tone/core/Transport".
|
2014-06-17 22:46:24 +00:00
|
|
|
*
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Frequency} freq
|
2015-02-26 16:26:23 +00:00
|
|
|
* @param {number=} now if passed in, this number will be
|
|
|
|
* used for all 'now' relative timings
|
|
|
|
* @return {number} the frequency in hertz
|
|
|
|
*/
|
|
|
|
Tone.prototype.toFrequency = function(freq, now){
|
|
|
|
if (this.isFrequency(freq)){
|
|
|
|
return parseFloat(freq);
|
|
|
|
} else if (this.isNotation(freq) || this.isTransportTime(freq)) {
|
|
|
|
return this.secondsToFrequency(this.toSeconds(freq, now));
|
2014-06-17 22:46:24 +00:00
|
|
|
} else {
|
2015-02-26 16:26:23 +00:00
|
|
|
return freq;
|
2014-06-17 22:46:24 +00:00
|
|
|
}
|
|
|
|
};
|
2014-04-11 23:17:01 +00:00
|
|
|
|
2014-06-16 05:44:00 +00:00
|
|
|
/**
|
2015-06-14 00:20:36 +00:00
|
|
|
* Convert Time into seconds.
|
2015-02-26 16:26:23 +00:00
|
|
|
* Defined in "Tone/core/Transport".
|
2014-06-16 05:44:00 +00:00
|
|
|
*
|
2015-02-26 16:26:23 +00:00
|
|
|
* Unlike the method which it overrides, this takes into account
|
|
|
|
* transporttime and musical notation.
|
2014-06-23 18:52:33 +00:00
|
|
|
*
|
2014-07-30 17:54:55 +00:00
|
|
|
* Time : 1.40
|
|
|
|
* Notation: 4n|1m|2t
|
|
|
|
* TransportTime: 2:4:1 (measure:quarters:sixteens)
|
|
|
|
* Now Relative: +3n
|
|
|
|
* Math: 3n+16n or even very complicated expressions ((3n*2)/6 + 1)
|
|
|
|
*
|
2014-06-23 18:52:33 +00:00
|
|
|
* @override
|
2015-06-14 00:20:36 +00:00
|
|
|
* @param {Time} time
|
2014-06-21 17:08:56 +00:00
|
|
|
* @param {number=} now if passed in, this number will be
|
|
|
|
* used for all 'now' relative timings
|
2014-06-19 17:38:21 +00:00
|
|
|
* @return {number}
|
2014-06-16 05:44:00 +00:00
|
|
|
*/
|
2014-06-21 17:08:56 +00:00
|
|
|
Tone.prototype.toSeconds = function(time, now){
|
|
|
|
now = this.defaultArg(now, this.now());
|
2014-06-16 05:44:00 +00:00
|
|
|
if (typeof time === "number"){
|
|
|
|
return time; //assuming that it's seconds
|
|
|
|
} else if (typeof time === "string"){
|
|
|
|
var plusTime = 0;
|
|
|
|
if(time.charAt(0) === "+") {
|
2014-06-21 17:08:56 +00:00
|
|
|
plusTime = now;
|
2014-12-01 03:40:07 +00:00
|
|
|
time = time.slice(1);
|
2014-06-16 05:44:00 +00:00
|
|
|
}
|
2014-07-30 17:54:55 +00:00
|
|
|
var components = time.split(/[\(\)\-\+\/\*]/);
|
|
|
|
if (components.length > 1){
|
2014-12-01 03:40:07 +00:00
|
|
|
var originalTime = time;
|
2014-07-30 17:54:55 +00:00
|
|
|
for(var i = 0; i < components.length; i++){
|
2014-10-25 15:57:00 +00:00
|
|
|
var symb = components[i].trim();
|
2014-07-30 17:54:55 +00:00
|
|
|
if (symb !== ""){
|
2014-10-25 15:57:00 +00:00
|
|
|
var val = this.toSeconds(symb);
|
2014-07-30 17:54:55 +00:00
|
|
|
time = time.replace(symb, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
//i know eval is evil, but i think it's safe here
|
|
|
|
time = eval(time); // jshint ignore:line
|
|
|
|
} catch (e){
|
2015-05-23 23:01:05 +00:00
|
|
|
throw new EvalError("problem evaluating Tone.Type.Time: "+originalTime);
|
2014-07-30 17:54:55 +00:00
|
|
|
}
|
|
|
|
} else if (this.isNotation(time)){
|
2014-06-21 17:08:56 +00:00
|
|
|
time = this.notationToSeconds(time);
|
2014-06-16 05:44:00 +00:00
|
|
|
} else if (this.isTransportTime(time)){
|
2014-06-21 17:08:56 +00:00
|
|
|
time = this.transportTimeToSeconds(time);
|
2014-06-16 05:44:00 +00:00
|
|
|
} else if (this.isFrequency(time)){
|
2014-06-21 17:08:56 +00:00
|
|
|
time = this.frequencyToSeconds(time);
|
2014-06-17 22:46:24 +00:00
|
|
|
} else {
|
|
|
|
time = parseFloat(time);
|
2014-06-16 05:44:00 +00:00
|
|
|
}
|
2014-06-17 22:46:24 +00:00
|
|
|
return time + plusTime;
|
2014-06-16 05:44:00 +00:00
|
|
|
} else {
|
2014-06-21 17:08:56 +00:00
|
|
|
return now;
|
2014-06-16 05:44:00 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-09-14 19:34:17 +00:00
|
|
|
var TransportConstructor = Tone.Transport;
|
2014-08-29 20:36:31 +00:00
|
|
|
|
2014-07-30 17:54:55 +00:00
|
|
|
Tone._initAudioContext(function(){
|
2014-10-16 04:49:31 +00:00
|
|
|
if (typeof Tone.Transport === "function"){
|
|
|
|
//a single transport object
|
|
|
|
Tone.Transport = new Tone.Transport();
|
|
|
|
} else {
|
|
|
|
//stop the clock
|
|
|
|
Tone.Transport.stop();
|
|
|
|
//get the previous bpm
|
2015-02-21 19:05:12 +00:00
|
|
|
var bpm = Tone.Transport.bpm.value;
|
2014-10-16 04:49:31 +00:00
|
|
|
//destory the old clock
|
|
|
|
Tone.Transport._clock.dispose();
|
|
|
|
//make new Transport insides
|
|
|
|
TransportConstructor.call(Tone.Transport);
|
|
|
|
//set the bpm
|
2015-02-21 19:05:12 +00:00
|
|
|
Tone.Transport.bpm.value = bpm;
|
2014-10-16 04:49:31 +00:00
|
|
|
}
|
2014-07-30 17:54:55 +00:00
|
|
|
});
|
2014-06-17 22:46:24 +00:00
|
|
|
|
2014-04-06 00:47:59 +00:00
|
|
|
return Tone.Transport;
|
|
|
|
});
|