Skip to content

Commit ede99a4

Browse files
committed
Implement sequencer instance for worklet
1 parent 10c83ed commit ede99a4

File tree

4 files changed

+90
-8
lines changed

4 files changed

+90
-8
lines changed

src/main/AudioWorkletNodeSynthesizer.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11

22
import { SynthesizerDefaultValues, InterpolationValues } from './Constants';
3+
import ISequencer from './ISequencer';
34
import ISynthesizer from './ISynthesizer';
45

6+
import WorkletSequencer from './WorkletSequencer';
7+
58
import * as MethodMessaging from './MethodMessaging';
69

710
/** @internal */
@@ -213,4 +216,19 @@ export default class AudioWorkletNodeSynthesizer implements ISynthesizer {
213216
public waitForPlayerStopped() {
214217
return MethodMessaging.postCallWithPromise<void>(this._messaging!, 'waitForPlayerStopped', []);
215218
}
219+
220+
/**
221+
* Creates a sequencer instance associated with this worklet node.
222+
*/
223+
public createSequencer(): Promise<ISequencer> {
224+
const channel = new MessageChannel();
225+
return MethodMessaging.postCallWithPromise<void>(this._messaging!, 'createSequencer', [channel.port2]).then(() => {
226+
return new WorkletSequencer(channel.port1);
227+
});
228+
}
229+
230+
/** @internal */
231+
public _getRawSynthesizer(): Promise<number> {
232+
return MethodMessaging.postCallWithPromise<number>(this._messaging!, 'getRawSynthesizer', []);
233+
}
216234
}

src/main/MethodMessaging.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,30 @@ export interface ReturnMessageInstance {
109109
/** @internal */
110110
export function initializeReturnPort(
111111
port: MessagePort,
112-
promiseInitialized: Promise<void>,
112+
promiseInitialized: Promise<void> | null,
113113
targetObjectHolder: () => any,
114114
hookMessage?: HookCallMessageCallback | undefined
115115
): ReturnMessageInstance {
116116
const instance: ReturnMessageInstance = {
117117
port: port
118118
};
119-
port.addEventListener('message', (e) => {
120-
const data = e.data;
121-
if (!data) {
122-
return;
123-
}
124-
promiseInitialized.then(() => processCallMessage(instance.port, data, targetObjectHolder, hookMessage));
125-
});
119+
if (promiseInitialized) {
120+
port.addEventListener('message', (e) => {
121+
const data = e.data;
122+
if (!data) {
123+
return;
124+
}
125+
promiseInitialized.then(() => processCallMessage(instance.port, data, targetObjectHolder, hookMessage));
126+
});
127+
} else {
128+
port.addEventListener('message', (e) => {
129+
const data = e.data;
130+
if (!data) {
131+
return;
132+
}
133+
processCallMessage(instance.port, data, targetObjectHolder, hookMessage);
134+
});
135+
}
126136
port.start();
127137
return instance;
128138
}

src/main/WorkletSequencer.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
import ISequencer from './ISequencer';
3+
import ISynthesizer from './ISynthesizer';
4+
import SequencerEvent from './SequencerEvent';
5+
6+
import AudioWorkletNodeSynthesizer from './AudioWorkletNodeSynthesizer';
7+
8+
import * as MethodMessaging from './MethodMessaging';
9+
10+
/** @internal */
11+
export default class WorkletSequencer implements ISequencer {
12+
/** @internal */
13+
private _messaging: MethodMessaging.CallMessageInstance | null;
14+
15+
constructor(port: MessagePort) {
16+
this._messaging = MethodMessaging.initializeCallPort(port);
17+
}
18+
19+
public close(): void {
20+
MethodMessaging.postCall(this._messaging!, 'close', []);
21+
}
22+
public registerSynthesizer(synth: ISynthesizer | number): Promise<void> {
23+
let val: Promise<number>;
24+
if (synth instanceof AudioWorkletNodeSynthesizer) {
25+
val = synth._getRawSynthesizer();
26+
} else {
27+
return Promise.reject(new TypeError('\'synth\' is not a compatible type instance'));
28+
}
29+
return val.then((v) => MethodMessaging.postCallWithPromise<void>(this._messaging!, 'registerSynthesizer', [v]));
30+
}
31+
public setTimeScale(scale: number): void {
32+
MethodMessaging.postCall(this._messaging!, 'setTimeScale', [scale]);
33+
}
34+
public getTimeScale(): Promise<number> {
35+
return MethodMessaging.postCallWithPromise<number>(this._messaging!, 'getTimeScale', []);
36+
}
37+
public getTick(): Promise<number> {
38+
return MethodMessaging.postCallWithPromise<number>(this._messaging!, 'getTick', []);
39+
}
40+
public sendEventAt(event: SequencerEvent, tick: number, isAbsolute: boolean): void {
41+
MethodMessaging.postCall(this._messaging!, 'sendEventAt', [event, tick, isAbsolute]);
42+
}
43+
}

src/main/registerAudioWorkletProcessor.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export default function registerAudioWorkletProcessor() {
4545
if (data.method === 'init') {
4646
this.synth!.init(sampleRate);
4747
return true;
48+
} else if (data.method === 'createSequencer') {
49+
this.doCreateSequencer(data.args[0]).then(() => {
50+
postReturn(this._messaging!, data.id, data.method, void (0));
51+
});
52+
return true;
4853
}
4954
return false;
5055
});
@@ -56,6 +61,12 @@ export default function registerAudioWorkletProcessor() {
5661
this.synth.init(sampleRate);
5762
}
5863

64+
private doCreateSequencer(port: MessagePort): Promise<void> {
65+
return Synthesizer.createSequencer().then((seq) => {
66+
initializeReturnPort(port, null, () => seq);
67+
});
68+
}
69+
5970
public process(_inputs: Float32Array[][], outputs: Float32Array[][]) {
6071
if (!this.synth) {
6172
return true;

0 commit comments

Comments
 (0)