/**
* Base class for time engines
*
* A time engine generates more or less regular events and/or plays back a
* media stream. It implements one or multiple interfaces to be driven by a
* master (i.e. a Scheduler, a Transport or a PlayControl) in synchronization
* with other engines. The provided interfaces are scheduled, transported,
* and play-controlled.
*
*
* #### The `scheduled` interface
*
* The scheduled interface allows for synchronizing an engine to a monotonous time
* as it is provided by the Scheduler master.
*
* ###### `advanceTime(time :Number) -> {Number}`
*
* The `advanceTime` method has to be implemented by an `TimeEngine` as part of the
* scheduled interface. The method is called by the master (e.g. the scheduler).
* It generates an event and to returns the time of the next event (i.e. the next
* call of advanceTime). The returned time has to be greater than the time
* received as argument of the method. In case that a TimeEngine has to generate
* multiple events at the same time, the engine has to implement its own loop
* while(event.time <= time) and return the time of the next event (if any).
*
* ###### `resetTime(time=undefined :Number)`
*
* The `resetTime` method is provided by the `TimeEngine` base class. An engine may
* call this method to reset its next event time (e.g. when a parameter is
* changed that influences the engine's temporal behavior). When no argument
* is given, the time is reset to the current master time. When calling the
* method with Infinity the engine is suspended without being removed from the
* master.
*
*
* #### The `transported` interface
*
* The transported interface allows for synchronizing an engine to a position
* (i.e. media playback time) that can run forward and backward and jump as it
* is provided by the Transport master.
*
* ###### `syncPosition(time :Number, position :Number, speed :Number) -> {Number}`
*
* The `syncPositon` method has to be implemented by a `TimeEngine` as part of the
* transported interface. The method syncPositon is called whenever the master
* of a transported engine has to (re-)synchronize the engine's position. This
* is for example required when the master (re-)starts playback, jumps to an
* arbitrary position, and when reversing playback direction. The method returns
* the next position of the engine in the given playback direction
* (i.e. `speed < 0` or `speed > 0`).
*
* ###### `advancePosition(time :Number, position :Number, speed :Number) -> {Number}`
*
* The `advancePosition` method has to be implemented by a `TimeEngine` as part
* of the transported interface. The master calls the advancePositon method when
* the engine's event position is reached. The method generates an event and
* returns the next position in the given playback direction (i.e. speed < 0 or
* speed > 0). The returned position has to be greater (i.e. when speed > 0)
* or less (i.e. when speed < 0) than the position received as argument of the
* method.
*
* ###### `resetPosition(position=undefined :Number)`
*
* The resetPosition method is provided by the TimeEngine base class. An engine
* may call this method to reset its next event position. When no argument
* is given, the time is reset to the current master time. When calling the
* method with Infinity the engine is suspended without being removed from
* the master.
*
*
* #### The speed-controlled interface
*
* The "speed-controlled" interface allows for syncronizing an engine that is
* neither driven through the scheduled nor the transported interface. The
* interface allows in particular to synchronize engines that assure their own
* scheduling (i.e. audio player or an oscillator) to the event-based scheduled
* and transported engines.
*
* ###### `syncSpeed(time :Number, position :Number, speed :Number, seek=false :Boolean)`
*
* The syncSpeed method has to be implemented by a TimeEngine as part of the
* speed-controlled interface. The method is called by the master whenever the
* playback speed changes or the position jumps arbitarily (i.e. on a seek).
*
*
* <hr />
*
* Example that shows a `TimeEngine` running in a `Scheduler` that counts up
* at a given frequency:
* {@link https://rawgit.com/wavesjs/waves-audio/master/examples/time-engine.html}
*
* @example
* import * as audio from 'waves-audio';
*
* class MyEngine extends audio.TimeEngine {
* constructor() {
* super();
* // ...
* }
* }
*
*/
class TimeEngine {
constructor() {
/**
* The engine's master.
*
* @type {Mixed}
* @name master
* @memberof TimeEngine
*/
this.master = null;
}
/**
* The time engine's current (master) time.
*
* @type {Number}
* @memberof TimeEngine
* @readonly
*/
get currentTime() {
if (this.master)
return this.master.currentTime;
return undefined;
}
/**
* The time engine's current (master) audio time.
*
* @type {Number}
* @memberof TimeEngine
* @readonly
*/
get audioTime() {
if (this.master)
return this.master.audioTime;
return undefined;
}
/**
* The time engine's current (master) position.
*
* @type {Number}
* @memberof TimeEngine
* @readonly
*/
get currentPosition() {
var master = this.master;
if (master && master.currentPosition !== undefined)
return master.currentPosition;
return undefined;
}
/**
* Scheduled interface
* - advanceTime(time), called to generate next event at given time, returns next time
*
* @static
* @memberof TimeEngine
*/
static implementsScheduled(engine) {
return (engine.advanceTime && engine.advanceTime instanceof Function);
}
resetTime(time = undefined) {
if (this.master)
this.master.resetEngineTime(this, time);
}
/**
* Transported interface
* - syncPosition(time, position, speed), called to reposition TimeEngine, returns next position
* - advancePosition(time, position, speed), called to generate next event at given time and position, returns next position
*
* @static
* @memberof TimeEngine
*/
static implementsTransported(engine) {
return (
engine.syncPosition && engine.syncPosition instanceof Function &&
engine.advancePosition && engine.advancePosition instanceof Function
);
}
resetPosition(position = undefined) {
if (this.master)
this.master.resetEnginePosition(this, position);
}
/**
* Speed-controlled interface
* - syncSpeed(time, position, speed, ), called to
*
* @static
* @memberof TimeEngine
*/
static implementsSpeedControlled(engine) {
return (engine.syncSpeed && engine.syncSpeed instanceof Function);
}
}
export default TimeEngine;