Event Timeline for Web Audio API
This module is developed based on the idea of this article.
npm:
npm install web-audio-scheduler
bower:
bower install web-audio-scheduler
downloads:
var audioContext = new AudioContext();
var scheduler = new WebAudioScheduler({
context: audioContext
});
function metronome(e) {
scheduler.insert(e.playbackTime + 0.000, ticktack, [ 880, 1.00 ]);
scheduler.insert(e.playbackTime + 0.500, ticktack, [ 440, 0.05 ]);
scheduler.insert(e.playbackTime + 1.000, ticktack, [ 440, 0.05 ]);
scheduler.insert(e.playbackTime + 1.500, ticktack, [ 440, 0.05 ]);
scheduler.insert(e.playbackTime + 2.000, metronome);
}
function ticktack(e, freq, dur) {
var t0 = e.playbackTime;
var t1 = t0 + dur;
var osc = audioContext.createOscillator();
var amp = audioContext.createGain();
osc.frequency.value = freq;
amp.gain.setValueAtTime(0.5, t0);
amp.gain.exponentialRampToValueAtTime(1e-6, t1);
osc.start(t0);
osc.connect(amp);
amp.connect(audioContext.destination);
scheduler.insert(t1, function(e) {
osc.stop(e.playbackTime);
scheduler.nextTick(function() {
osc.disconnect();
amp.disconnect();
});
});
}
function start() {
scheduler.start(metronome);
}
function stop() {
scheduler.stop(true);
}
-
WebAudioScheduler(opts={})
context: AudioContext
interval: number
default: 0.025 (25ms)aheadTime: number
default: 0.1 (100ms)offsetTime: number
default: 0.005 (5ms)timerAPI: object
default:window || global
toSeconds: function
default:(value)=> +value
context: AudioContext
interval: number
aheadTime: number
offsetTime: number
timerAPI: object
toSeconds: function
currentTime: number
- Current time of the audio context
playbackTime: number
- Playback time of the timeline
events: object[]
- Sorted list of scheduled items
start([callback: function]): self
- Start the timeline.
- The
callback
is inserted in the head of the event list if given.
stop([reset: boolean]): self
- Stop the timeline.
- The event list is cleared if
reset
is truthy.
insert(time: number, callback: function, [args: any[]]): number
- Insert the
callback
into the event list. - The return value is
schedId
. It is used to.remove()
the callback.
- Insert the
nextTick(callback: function, [args: any[]]): number
- Same as
.insert()
, but this callback is called at next tick. - This method is used to disconnect an audio node at the proper timing.
- Same as
remove([schedId: number]): number
- Remove a callback function from the event list.
- Remove all callback functions from the event list if
schedId
is omitted.
A callback function receives a schedule event and given arguments at .insert()
.
A schedule event has two parameters.
target: WebAudioScheduler
playbackTime: number
scheduler.insert(0, callback, [ 1, 2 ]);
function callback(e, arg1, arg2) {
assert(this === scheduler);
assert(e.target === scheduler);
assert(e.playbackTime === 0 + scheduler.offsetTime);
assert(arg1 === 1);
assert(arg2 === 2);
}
time(ms) 0----25---50---75---100--125--150--175--200---->
*====|====|====|====| | | | |
| *====|====|====|====| | | |
| | *====|====|====|====| | |
| | | | *==|====|====|====|== |
| | | | | *==|====|====|====|==
: : : : : : : : :
|<-->| : : |<------------------>|
interval (25ms) aheadTime (100ms)
* offset (5ms) = range of execution to events
The below example is the same configuration as defaults.
var sched = new WebAudioScheduler({
interval: 0.025,
aheadTime: 0.1,
offsetTime: 0.005
});
TimerAPI is used instead of the native timer API. TimerAPI should have two functions, setInterval
and clearInterval
.
- mohayonao/worker-timer
- A timer that is stable in any situation. e.g. tabs in background, the invisible state page.
- mohayonao/tickable-timer
- Manual ticking
setTimeout
/setInterval
(for test CI)
- Manual ticking
The below example uses stable-timer instead of the native timer API.
var shced = new WebAudioScheduler({
timerAPI: StableTimer
});
ToSeconds should be a function. This function receives value: any
and an instance of scheduler when calling insert()
, and should return time: number
. e.g. the below example supports relative time syntax.
function toSeconds(value, scheduler) {
if (typeof value === "number") {
return value;
}
if (typeof value === "string") {
if (value.charAt(0) === "+") {
return scheduler.currentTime + +value.substr(1);
}
}
return 0;
};
var sched = new WebAudioScheduler({ toSeconds: toSeconds });
sched.insert("+0.5", function(e) {
// this event will be called at currentTime + 500 milliseconds
});
MIT