Tone.js/Tone/core/Draw.js

104 lines
No EOL
2.7 KiB
JavaScript

define(["Tone/core/Tone", "Tone/core/Timeline"], function (Tone) {
"use strict";
/**
* @class Tone.Draw is useful for synchronizing visuals and audio events.
* Callbacks from Tone.Transport or any of the Tone.Event classes
* always happen _before_ the scheduled time and are not synchronized
* to the animation frame so they are not good for triggering tightly
* synchronized visuals and sound. Tone.Draw makes it easy to schedule
* callbacks using the AudioContext time and uses requestAnimationFrame.
*
* @singleton
* @extends {Tone}
* @example
* Tone.Transport.schedule(function(time){
* //use the time argument to schedule a callback with Tone.Draw
* Tone.Draw.schedule(function(){
* //do drawing or DOM manipulation here
* }, time)
* }, "+0.5")
*/
Tone.Draw = function(){
/**
* All of the events.
* @type {Tone.Timeline}
* @private
*/
this._events = new Tone.Timeline();
/**
* The time after which events are not invoked.
* @type {Number}
*/
this.expiration = 0.25;
/**
* The amount of time before the scheduled time
* that the callback can be invoked. Default is
* half the time of an animation frame (0.008 seconds).
* @type {Number}
*/
this.anticipation = 0.008;
/**
* The draw loop
* @type {Function}
* @private
*/
this._boundDrawLoop = this._drawLoop.bind(this);
//start the loop
this._drawLoop();
};
Tone.extend(Tone.Draw);
/**
* Schedule a function at the given time to be invoked
* on the nearest animation frame.
* @param {Function} callback Callback is invoked at the given time.
* @param {Time} time The time relative to the AudioContext time
* to invoke the callback.
* @return {Tone.Draw} this
*/
Tone.Draw.prototype.schedule = function(callback, time){
this._events.addEvent({
callback : callback,
time : this.toSeconds(time)
});
return this;
};
/**
* Cancel events scheduled after the given time
* @param {Time=} after Time after which scheduled events will
* be removed from the scheduling timeline.
* @return {Tone.Draw} this
*/
Tone.Draw.prototype.cancel = function(after){
this._events.cancel(this.toSeconds(after));
return this;
};
/**
* The draw loop
* @private
*/
Tone.Draw.prototype._drawLoop = function(){
requestAnimationFrame(this._boundDrawLoop);
var now = Tone.now();
while(this._events.length && this._events.peek().time - this.anticipation <= now){
var event = this._events.shift();
if (now - event.time <= this.expiration){
event.callback();
}
}
};
//make a singleton
Tone.Draw = new Tone.Draw();
return Tone.Draw;
});