-
Notifications
You must be signed in to change notification settings - Fork 3
/
scheduler.js
64 lines (53 loc) · 2.02 KB
/
scheduler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
importScripts("./pkg/ruffbox_pattern.js")
const { Scheduler } = wasm_bindgen;
// In a previous version, more of this was done in the Rust part using
// stdweb's `js!` snippet macro, but that stopped working and didn't
// seem to be very elegant.
// using web_sys and js_sys to patch everything together in rust
// also seems more hassle than it's worth, so until wasm_thread allows to call
// postMessage, or std::thread becomes available so that all the scheduling
// can be done on the rust side, with completely invisible web workers,
// this solution seems to be the best compromise to me.
function time_step(start, init_time) {
const current_time = performance.now();
if (start === true) {
self.scheduler.start(init_time, current_time);
}
// generate the event list ...
let next_events = self.scheduler.generate_events();
// dispatch events to audio worklet ..
next_events.forEach((event) => {
postMessage( {
source_type: event.source_type,
timestamp: event.timestamp,
sample_id: event.sample_id,
params: event.params } );
});
// time compensation is necessary because the setTimeout function
// isn't all that precise ... the real time thread in the worklet is
// running a bit ahead so all the events have time to arrive
const next_time_step = self.scheduler.compensate_time(current_time);
self.sched_timeout = setTimeout(time_step, next_time_step, false);
}
// fetch the scheduler instance
wasm_bindgen("./pkg/ruffbox_pattern_bg.wasm").then(wasm => {
self.scheduler = Scheduler.new();
// now that we have a scheduler, set scheduler controls
self.onmessage = function(e) {
console.log("scheduler command: " + e.data.cmd);
switch (e.data.cmd) {
case 'start':
time_step(true, e.data.timestamp);
break;
case 'stop':
clearTimeout(self.sched_timeout);
break;
case 'evaluate_loop':
self.scheduler.evaluate(e.data.loop_data);
break;
case 'set_tempo':
self.scheduler.set_tempo(e.data.tempo);
break;
}
}
});