@libraz/libsonare 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +277 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +333 -55
- package/dist/index.js.map +1 -1
- package/dist/sonare-rt-module.js +1 -1
- package/dist/sonare-rt.js +1 -1
- package/dist/sonare-rt.wasm +0 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/worklet.d.ts +397 -9
- package/dist/worklet.js +1259 -87
- package/dist/worklet.js.map +1 -1
- package/package.json +1 -1
- package/src/effects_mastering.ts +16 -0
- package/src/errors.ts +44 -0
- package/src/index.ts +15 -1
- package/src/mixer.ts +11 -0
- package/src/module_state.ts +180 -4
- package/src/opfs_clip_pages.ts +43 -9
- package/src/realtime_engine.ts +174 -109
- package/src/sonare.js.d.ts +65 -0
- package/src/web_midi.ts +15 -11
- package/src/worklet.ts +1402 -66
package/src/realtime_engine.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { ErrorCode, SonareError } from './errors';
|
|
1
2
|
import { getSonareModule } from './module_state';
|
|
2
3
|
import type { SynthPatch } from './project';
|
|
4
|
+
import type { EqBand } from './public_types';
|
|
3
5
|
import type {
|
|
4
6
|
WasmClipPageRequest,
|
|
5
7
|
WasmEngineAutomationPoint,
|
|
@@ -16,6 +18,8 @@ import type {
|
|
|
16
18
|
WasmEngineParameterInfo,
|
|
17
19
|
WasmEngineProcessWithMonitorResult,
|
|
18
20
|
WasmEngineTelemetry,
|
|
21
|
+
WasmEngineTempoSegment,
|
|
22
|
+
WasmEngineTimeSignatureSegment,
|
|
19
23
|
WasmEngineTransportState,
|
|
20
24
|
WasmRealtimeEngine,
|
|
21
25
|
} from './sonare.js';
|
|
@@ -35,6 +39,49 @@ export type EngineFreezeResult = WasmEngineFreezeResult;
|
|
|
35
39
|
export type EngineTelemetry = WasmEngineTelemetry;
|
|
36
40
|
export type EngineMeterTelemetry = WasmEngineMeterTelemetry;
|
|
37
41
|
export type EngineTransportState = WasmEngineTransportState;
|
|
42
|
+
export type EngineTempoSegment = WasmEngineTempoSegment;
|
|
43
|
+
export type EngineTimeSignatureSegment = WasmEngineTimeSignatureSegment;
|
|
44
|
+
|
|
45
|
+
export interface EngineTrackSend {
|
|
46
|
+
busId: number;
|
|
47
|
+
levelDb?: number;
|
|
48
|
+
enabled?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface EngineTrackLane {
|
|
52
|
+
trackId: number;
|
|
53
|
+
sends?: EngineTrackSend[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface EngineBus {
|
|
57
|
+
busId: number;
|
|
58
|
+
gainDb?: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface EngineMidiEvent {
|
|
62
|
+
renderFrame: number;
|
|
63
|
+
word0?: number;
|
|
64
|
+
word1?: number;
|
|
65
|
+
word2?: number;
|
|
66
|
+
word3?: number;
|
|
67
|
+
wordCount?: number;
|
|
68
|
+
group?: number;
|
|
69
|
+
sysexHandle?: number;
|
|
70
|
+
data0?: number;
|
|
71
|
+
data1?: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface EngineMidiClipSchedule {
|
|
75
|
+
id?: number;
|
|
76
|
+
trackId?: number;
|
|
77
|
+
destinationId?: number;
|
|
78
|
+
startSample?: number;
|
|
79
|
+
startPpq?: number;
|
|
80
|
+
lengthSamples?: number;
|
|
81
|
+
loop?: boolean;
|
|
82
|
+
loopLengthSamples?: number;
|
|
83
|
+
events: EngineMidiEvent[];
|
|
84
|
+
}
|
|
38
85
|
|
|
39
86
|
export const EXPECTED_ENGINE_ABI_VERSION = 3;
|
|
40
87
|
|
|
@@ -75,91 +122,9 @@ export function engineCapabilities(): EngineCapabilities {
|
|
|
75
122
|
};
|
|
76
123
|
}
|
|
77
124
|
|
|
78
|
-
// Methods added to the embind RealtimeEngine that the generated `sonare.js`
|
|
79
|
-
// declarations only gain after a WASM rebuild. The native handle is cast to this
|
|
80
|
-
// shape so the wrapper can reach them without a stale type error.
|
|
81
|
-
interface WasmRealtimeEngineExt {
|
|
82
|
-
setBuiltinInstrument: (destinationId: number, config: object) => void;
|
|
83
|
-
setSynthInstrument: (destinationId: number, patch: object | string) => void;
|
|
84
|
-
loadSoundFont: (data: Uint8Array) => void;
|
|
85
|
-
setSf2Instrument: (destinationId: number, config: object) => void;
|
|
86
|
-
clearMidiInstrument: (destinationId: number) => void;
|
|
87
|
-
midiInstrumentCount: () => number;
|
|
88
|
-
bindMidiCc: (
|
|
89
|
-
channel: number,
|
|
90
|
-
controller: number,
|
|
91
|
-
paramId: number,
|
|
92
|
-
minValue: number,
|
|
93
|
-
maxValue: number,
|
|
94
|
-
) => void;
|
|
95
|
-
clearMidiCcBindings: () => void;
|
|
96
|
-
midiCcBindingCount: () => number;
|
|
97
|
-
setMidiFx: (destinationId: number, configJson: string) => void;
|
|
98
|
-
clearMidiFx: (destinationId: number) => void;
|
|
99
|
-
setMidiInputSource: (destinationId: number) => void;
|
|
100
|
-
clearMidiInputSource: () => void;
|
|
101
|
-
midiInputPendingCount: () => number;
|
|
102
|
-
createClipPageProvider: (numChannels: number, numSamples: number, pageFrames: number) => number;
|
|
103
|
-
supplyClipPage: (providerId: number, pageIndex: number, channels: Float32Array[]) => void;
|
|
104
|
-
clearClipPage: (providerId: number, pageIndex: number) => void;
|
|
105
|
-
destroyClipPageProvider: (providerId: number) => void;
|
|
106
|
-
popClipPageRequest: () => ClipPageRequest | null;
|
|
107
|
-
pushMidiInputNoteOn: (
|
|
108
|
-
group: number,
|
|
109
|
-
channel: number,
|
|
110
|
-
note: number,
|
|
111
|
-
velocity: number,
|
|
112
|
-
portTimeSamples: number,
|
|
113
|
-
) => void;
|
|
114
|
-
pushMidiInputNoteOff: (
|
|
115
|
-
group: number,
|
|
116
|
-
channel: number,
|
|
117
|
-
note: number,
|
|
118
|
-
velocity: number,
|
|
119
|
-
portTimeSamples: number,
|
|
120
|
-
) => void;
|
|
121
|
-
pushMidiInputCc: (
|
|
122
|
-
group: number,
|
|
123
|
-
channel: number,
|
|
124
|
-
controller: number,
|
|
125
|
-
value: number,
|
|
126
|
-
portTimeSamples: number,
|
|
127
|
-
) => void;
|
|
128
|
-
pushMidiNoteOn: (
|
|
129
|
-
destinationId: number,
|
|
130
|
-
group: number,
|
|
131
|
-
channel: number,
|
|
132
|
-
note: number,
|
|
133
|
-
velocity: number,
|
|
134
|
-
renderFrame: number,
|
|
135
|
-
) => void;
|
|
136
|
-
pushMidiNoteOff: (
|
|
137
|
-
destinationId: number,
|
|
138
|
-
group: number,
|
|
139
|
-
channel: number,
|
|
140
|
-
note: number,
|
|
141
|
-
velocity: number,
|
|
142
|
-
renderFrame: number,
|
|
143
|
-
) => void;
|
|
144
|
-
pushMidiCc: (
|
|
145
|
-
destinationId: number,
|
|
146
|
-
group: number,
|
|
147
|
-
channel: number,
|
|
148
|
-
controller: number,
|
|
149
|
-
value: number,
|
|
150
|
-
renderFrame: number,
|
|
151
|
-
) => void;
|
|
152
|
-
pushMidiPanic: (renderFrame: number) => void;
|
|
153
|
-
clearParameters: () => void;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
125
|
export class RealtimeEngine {
|
|
157
126
|
private native: WasmRealtimeEngine;
|
|
158
127
|
|
|
159
|
-
private nativeExt(): WasmRealtimeEngineExt {
|
|
160
|
-
return this.native as unknown as WasmRealtimeEngineExt;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
128
|
constructor(
|
|
164
129
|
sampleRate = 48000,
|
|
165
130
|
maxBlockSize = 128,
|
|
@@ -200,11 +165,19 @@ export class RealtimeEngine {
|
|
|
200
165
|
this.native.setParameterSmoothed(paramId, value, renderFrame);
|
|
201
166
|
}
|
|
202
167
|
|
|
168
|
+
setSoloMute(laneIndex: number, solo: boolean, mute: boolean, renderFrame = -1): void {
|
|
169
|
+
this.native.setSoloMute(laneIndex, solo, mute, renderFrame);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
setMidiClips(clips: readonly EngineMidiClipSchedule[]): void {
|
|
173
|
+
this.native.setMidiClips(clips);
|
|
174
|
+
}
|
|
175
|
+
|
|
203
176
|
setBuiltinInstrument(
|
|
204
177
|
config: { destinationId?: number } & Record<string, unknown> = {},
|
|
205
178
|
destinationId = config.destinationId ?? 0,
|
|
206
179
|
): void {
|
|
207
|
-
this.
|
|
180
|
+
this.native.setBuiltinInstrument(destinationId, config);
|
|
208
181
|
}
|
|
209
182
|
|
|
210
183
|
/**
|
|
@@ -220,7 +193,7 @@ export class RealtimeEngine {
|
|
|
220
193
|
patch: SynthPatch | string = {},
|
|
221
194
|
destinationId = (typeof patch === 'object' ? patch.destinationId : undefined) ?? 0,
|
|
222
195
|
): void {
|
|
223
|
-
this.
|
|
196
|
+
this.native.setSynthInstrument(destinationId, patch);
|
|
224
197
|
}
|
|
225
198
|
|
|
226
199
|
/**
|
|
@@ -230,7 +203,7 @@ export class RealtimeEngine {
|
|
|
230
203
|
* not referenced afterwards. Replaces any previously loaded SoundFont.
|
|
231
204
|
*/
|
|
232
205
|
loadSoundFont(data: Uint8Array): void {
|
|
233
|
-
this.
|
|
206
|
+
this.native.loadSoundFont(data);
|
|
234
207
|
}
|
|
235
208
|
|
|
236
209
|
/**
|
|
@@ -246,15 +219,15 @@ export class RealtimeEngine {
|
|
|
246
219
|
config: { destinationId?: number; gain?: number; polyphony?: number } = {},
|
|
247
220
|
destinationId = config.destinationId ?? 0,
|
|
248
221
|
): void {
|
|
249
|
-
this.
|
|
222
|
+
this.native.setSf2Instrument(destinationId, config);
|
|
250
223
|
}
|
|
251
224
|
|
|
252
225
|
clearMidiInstrument(destinationId = 0): void {
|
|
253
|
-
this.
|
|
226
|
+
this.native.clearMidiInstrument(destinationId);
|
|
254
227
|
}
|
|
255
228
|
|
|
256
229
|
midiInstrumentCount(): number {
|
|
257
|
-
return this.
|
|
230
|
+
return this.native.midiInstrumentCount();
|
|
258
231
|
}
|
|
259
232
|
|
|
260
233
|
/**
|
|
@@ -268,7 +241,7 @@ export class RealtimeEngine {
|
|
|
268
241
|
paramId: number,
|
|
269
242
|
options: MidiCcBindOptions = {},
|
|
270
243
|
): void {
|
|
271
|
-
this.
|
|
244
|
+
this.native.bindMidiCc(
|
|
272
245
|
channel,
|
|
273
246
|
controller,
|
|
274
247
|
paramId,
|
|
@@ -278,33 +251,33 @@ export class RealtimeEngine {
|
|
|
278
251
|
}
|
|
279
252
|
|
|
280
253
|
clearMidiCcBindings(): void {
|
|
281
|
-
this.
|
|
254
|
+
this.native.clearMidiCcBindings();
|
|
282
255
|
}
|
|
283
256
|
|
|
284
257
|
midiCcBindingCount(): number {
|
|
285
|
-
return this.
|
|
258
|
+
return this.native.midiCcBindingCount();
|
|
286
259
|
}
|
|
287
260
|
|
|
288
261
|
/** Install/replace a live non-destructive MIDI-FX insert for one destination. */
|
|
289
262
|
setMidiFx(destinationId: number, configJson: string): void {
|
|
290
|
-
this.
|
|
263
|
+
this.native.setMidiFx(destinationId, configJson);
|
|
291
264
|
}
|
|
292
265
|
|
|
293
266
|
clearMidiFx(destinationId = 0): void {
|
|
294
|
-
this.
|
|
267
|
+
this.native.clearMidiFx(destinationId);
|
|
295
268
|
}
|
|
296
269
|
|
|
297
270
|
/** Enable the engine-owned live MIDI input source for a destination. */
|
|
298
271
|
setMidiInputSource(destinationId = 0): void {
|
|
299
|
-
this.
|
|
272
|
+
this.native.setMidiInputSource(destinationId);
|
|
300
273
|
}
|
|
301
274
|
|
|
302
275
|
clearMidiInputSource(): void {
|
|
303
|
-
this.
|
|
276
|
+
this.native.clearMidiInputSource();
|
|
304
277
|
}
|
|
305
278
|
|
|
306
279
|
midiInputPendingCount(): number {
|
|
307
|
-
return this.
|
|
280
|
+
return this.native.midiInputPendingCount();
|
|
308
281
|
}
|
|
309
282
|
|
|
310
283
|
pushMidiInputNoteOn(
|
|
@@ -314,7 +287,7 @@ export class RealtimeEngine {
|
|
|
314
287
|
velocity: number,
|
|
315
288
|
portTimeSamples = 0,
|
|
316
289
|
): void {
|
|
317
|
-
this.
|
|
290
|
+
this.native.pushMidiInputNoteOn(group, channel, note, velocity, portTimeSamples);
|
|
318
291
|
}
|
|
319
292
|
|
|
320
293
|
pushMidiInputNoteOff(
|
|
@@ -324,7 +297,7 @@ export class RealtimeEngine {
|
|
|
324
297
|
velocity = 0,
|
|
325
298
|
portTimeSamples = 0,
|
|
326
299
|
): void {
|
|
327
|
-
this.
|
|
300
|
+
this.native.pushMidiInputNoteOff(group, channel, note, velocity, portTimeSamples);
|
|
328
301
|
}
|
|
329
302
|
|
|
330
303
|
pushMidiInputCc(
|
|
@@ -334,7 +307,7 @@ export class RealtimeEngine {
|
|
|
334
307
|
value: number,
|
|
335
308
|
portTimeSamples = 0,
|
|
336
309
|
): void {
|
|
337
|
-
this.
|
|
310
|
+
this.native.pushMidiInputCc(group, channel, controller, value, portTimeSamples);
|
|
338
311
|
}
|
|
339
312
|
|
|
340
313
|
pushMidiNoteOn(
|
|
@@ -345,7 +318,7 @@ export class RealtimeEngine {
|
|
|
345
318
|
velocity: number,
|
|
346
319
|
renderFrame = -1,
|
|
347
320
|
): void {
|
|
348
|
-
this.
|
|
321
|
+
this.native.pushMidiNoteOn(destinationId, group, channel, note, velocity, renderFrame);
|
|
349
322
|
}
|
|
350
323
|
|
|
351
324
|
pushMidiNoteOff(
|
|
@@ -356,7 +329,7 @@ export class RealtimeEngine {
|
|
|
356
329
|
velocity = 0,
|
|
357
330
|
renderFrame = -1,
|
|
358
331
|
): void {
|
|
359
|
-
this.
|
|
332
|
+
this.native.pushMidiNoteOff(destinationId, group, channel, note, velocity, renderFrame);
|
|
360
333
|
}
|
|
361
334
|
|
|
362
335
|
/**
|
|
@@ -373,7 +346,7 @@ export class RealtimeEngine {
|
|
|
373
346
|
value: number,
|
|
374
347
|
renderFrame = -1,
|
|
375
348
|
): void {
|
|
376
|
-
this.
|
|
349
|
+
this.native.pushMidiCc(destinationId, group, channel, controller, value, renderFrame);
|
|
377
350
|
}
|
|
378
351
|
|
|
379
352
|
/**
|
|
@@ -381,7 +354,7 @@ export class RealtimeEngine {
|
|
|
381
354
|
* `renderFrame` (-1 = immediate). Mirrors the C-ABI `pushMidiPanic`.
|
|
382
355
|
*/
|
|
383
356
|
pushMidiPanic(renderFrame = -1): void {
|
|
384
|
-
this.
|
|
357
|
+
this.native.pushMidiPanic(renderFrame);
|
|
385
358
|
}
|
|
386
359
|
|
|
387
360
|
/**
|
|
@@ -389,7 +362,7 @@ export class RealtimeEngine {
|
|
|
389
362
|
* only; not realtime-safe. Mirrors the C-ABI `clearParameters`.
|
|
390
363
|
*/
|
|
391
364
|
clearParameters(): void {
|
|
392
|
-
this.
|
|
365
|
+
this.native.clearParameters();
|
|
393
366
|
}
|
|
394
367
|
|
|
395
368
|
/** Read back the current transport state snapshot. */
|
|
@@ -417,10 +390,22 @@ export class RealtimeEngine {
|
|
|
417
390
|
this.native.setTempo(bpm);
|
|
418
391
|
}
|
|
419
392
|
|
|
393
|
+
setTempoSegments(segments: readonly EngineTempoSegment[]): void {
|
|
394
|
+
this.native.setTempoSegments([...segments]);
|
|
395
|
+
}
|
|
396
|
+
|
|
420
397
|
setTimeSignature(numerator: number, denominator: number): void {
|
|
421
398
|
this.native.setTimeSignature(numerator, denominator);
|
|
422
399
|
}
|
|
423
400
|
|
|
401
|
+
setTimeSignatureSegments(segments: readonly EngineTimeSignatureSegment[]): void {
|
|
402
|
+
this.native.setTimeSignatureSegments([...segments]);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
sampleAtPpq(ppq: number): number {
|
|
406
|
+
return Number(this.native.sampleAtPpq(ppq));
|
|
407
|
+
}
|
|
408
|
+
|
|
424
409
|
setLoop(startPpq: number, endPpq: number, enabled = true): void {
|
|
425
410
|
this.native.setLoop(startPpq, endPpq, enabled);
|
|
426
411
|
}
|
|
@@ -513,29 +498,109 @@ export class RealtimeEngine {
|
|
|
513
498
|
return this.native.clipCount();
|
|
514
499
|
}
|
|
515
500
|
|
|
501
|
+
setTrackLanes(lanes: Array<number | EngineTrackLane>): void {
|
|
502
|
+
this.native.setTrackLanes(
|
|
503
|
+
lanes.map((lane) => (typeof lane === 'number' ? { trackId: lane } : lane)),
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
setTrackBuses(buses: EngineBus[]): void {
|
|
508
|
+
this.native.setTrackBuses(buses);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
setBusStripJson(busId: number, sceneJson: string): void {
|
|
512
|
+
try {
|
|
513
|
+
JSON.parse(sceneJson);
|
|
514
|
+
} catch (error) {
|
|
515
|
+
const message = error instanceof Error ? error.message : 'invalid bus strip JSON';
|
|
516
|
+
throw new SonareError(ErrorCode.InvalidFormat, 'InvalidFormat', message);
|
|
517
|
+
}
|
|
518
|
+
this.native.setBusStripJson(busId, sceneJson);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
setTrackStripJson(trackId: number, sceneJson: string): void {
|
|
522
|
+
try {
|
|
523
|
+
JSON.parse(sceneJson);
|
|
524
|
+
} catch (error) {
|
|
525
|
+
const message = error instanceof Error ? error.message : 'invalid track strip JSON';
|
|
526
|
+
throw new SonareError(ErrorCode.InvalidFormat, 'InvalidFormat', message);
|
|
527
|
+
}
|
|
528
|
+
this.native.setTrackStripJson(trackId, sceneJson);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
setTrackStripEqBand(trackId: number, bandIndex: number, band: EqBand | string): void {
|
|
532
|
+
this.native.setTrackStripEqBandJson(
|
|
533
|
+
trackId,
|
|
534
|
+
bandIndex,
|
|
535
|
+
typeof band === 'string' ? band : JSON.stringify(band),
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
setTrackStripEqBandJson(trackId: number, bandIndex: number, bandJson: string): void {
|
|
540
|
+
this.native.setTrackStripEqBandJson(trackId, bandIndex, bandJson);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
setTrackStripInsertBypassed(
|
|
544
|
+
trackId: number,
|
|
545
|
+
insertIndex: number,
|
|
546
|
+
bypassed: boolean,
|
|
547
|
+
resetOnBypass = false,
|
|
548
|
+
): void {
|
|
549
|
+
this.native.setTrackStripInsertBypassed(trackId, insertIndex, bypassed, resetOnBypass);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
setMasterStripJson(sceneJson: string): void {
|
|
553
|
+
try {
|
|
554
|
+
JSON.parse(sceneJson);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
const message = error instanceof Error ? error.message : 'invalid master strip JSON';
|
|
557
|
+
throw new SonareError(ErrorCode.InvalidFormat, 'InvalidFormat', message);
|
|
558
|
+
}
|
|
559
|
+
this.native.setMasterStripJson(sceneJson);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
setMasterStripEqBand(bandIndex: number, band: EqBand | string): void {
|
|
563
|
+
this.native.setMasterStripEqBandJson(
|
|
564
|
+
bandIndex,
|
|
565
|
+
typeof band === 'string' ? band : JSON.stringify(band),
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
setMasterStripEqBandJson(bandIndex: number, bandJson: string): void {
|
|
570
|
+
this.native.setMasterStripEqBandJson(bandIndex, bandJson);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
setMasterStripInsertBypassed(
|
|
574
|
+
insertIndex: number,
|
|
575
|
+
bypassed: boolean,
|
|
576
|
+
resetOnBypass = false,
|
|
577
|
+
): void {
|
|
578
|
+
this.native.setMasterStripInsertBypassed(insertIndex, bypassed, resetOnBypass);
|
|
579
|
+
}
|
|
580
|
+
|
|
516
581
|
createClipPageProvider(
|
|
517
582
|
numChannels: number,
|
|
518
583
|
numSamples: number,
|
|
519
584
|
pageFrames: number,
|
|
520
585
|
): ClipPageProvider {
|
|
521
|
-
const id = this.
|
|
586
|
+
const id = this.native.createClipPageProvider(numChannels, numSamples, pageFrames);
|
|
522
587
|
return new ClipPageProvider(this, id);
|
|
523
588
|
}
|
|
524
589
|
|
|
525
590
|
supplyClipPage(providerId: number, pageIndex: number, channels: Float32Array[]): void {
|
|
526
|
-
this.
|
|
591
|
+
this.native.supplyClipPage(providerId, pageIndex, channels);
|
|
527
592
|
}
|
|
528
593
|
|
|
529
594
|
clearClipPage(providerId: number, pageIndex: number): void {
|
|
530
|
-
this.
|
|
595
|
+
this.native.clearClipPage(providerId, pageIndex);
|
|
531
596
|
}
|
|
532
597
|
|
|
533
598
|
destroyClipPageProvider(providerId: number): void {
|
|
534
|
-
this.
|
|
599
|
+
this.native.destroyClipPageProvider(providerId);
|
|
535
600
|
}
|
|
536
601
|
|
|
537
602
|
popClipPageRequest(): ClipPageRequest | null {
|
|
538
|
-
return this.
|
|
603
|
+
return this.native.popClipPageRequest();
|
|
539
604
|
}
|
|
540
605
|
|
|
541
606
|
setCaptureBuffer(numChannels: number, capacityFrames: number): void {
|
package/src/sonare.js.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
export interface SonareModuleOptions {
|
|
6
6
|
locateFile?: (path: string, prefix: string) => string;
|
|
7
|
+
wasmBinary?: ArrayBuffer | Uint8Array;
|
|
7
8
|
onRuntimeInitialized?: () => void;
|
|
8
9
|
print?: (text: string) => void;
|
|
9
10
|
printErr?: (text: string) => void;
|
|
@@ -518,6 +519,7 @@ export interface WasmMixResult {
|
|
|
518
519
|
|
|
519
520
|
export interface WasmEngineClip {
|
|
520
521
|
id?: number;
|
|
522
|
+
trackId?: number;
|
|
521
523
|
channels?: Float32Array[];
|
|
522
524
|
startPpq: number;
|
|
523
525
|
lengthSamples?: number;
|
|
@@ -531,6 +533,22 @@ export interface WasmEngineClip {
|
|
|
531
533
|
pageProvider?: number | { readonly id: number };
|
|
532
534
|
}
|
|
533
535
|
|
|
536
|
+
export interface WasmEngineTrackSend {
|
|
537
|
+
busId: number;
|
|
538
|
+
levelDb?: number;
|
|
539
|
+
enabled?: boolean;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
export interface WasmEngineTrackLane {
|
|
543
|
+
trackId: number;
|
|
544
|
+
sends?: WasmEngineTrackSend[];
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export interface WasmEngineBus {
|
|
548
|
+
busId: number;
|
|
549
|
+
gainDb?: number;
|
|
550
|
+
}
|
|
551
|
+
|
|
534
552
|
export interface WasmClipPageRequest {
|
|
535
553
|
clipId: number;
|
|
536
554
|
channel: number;
|
|
@@ -696,6 +714,18 @@ export interface WasmEngineProcessWithMonitorResult {
|
|
|
696
714
|
monitor: Float32Array[];
|
|
697
715
|
}
|
|
698
716
|
|
|
717
|
+
export interface WasmEngineTempoSegment {
|
|
718
|
+
startPpq: number;
|
|
719
|
+
bpm: number;
|
|
720
|
+
endBpm?: number;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
export interface WasmEngineTimeSignatureSegment {
|
|
724
|
+
startPpq: number;
|
|
725
|
+
numerator: number;
|
|
726
|
+
denominator: number;
|
|
727
|
+
}
|
|
728
|
+
|
|
699
729
|
export interface WasmRealtimeEngine {
|
|
700
730
|
prepare: (
|
|
701
731
|
sampleRate: number,
|
|
@@ -705,13 +735,17 @@ export interface WasmRealtimeEngine {
|
|
|
705
735
|
) => void;
|
|
706
736
|
setParameter: (paramId: number, value: number, renderFrame: number) => void;
|
|
707
737
|
setParameterSmoothed: (paramId: number, value: number, renderFrame: number) => void;
|
|
738
|
+
setSoloMute: (laneIndex: number, solo: boolean, mute: boolean, renderFrame: number) => void;
|
|
708
739
|
getTransportState: () => WasmEngineTransportState;
|
|
709
740
|
play: (renderFrame: number) => void;
|
|
710
741
|
stop: (renderFrame: number) => void;
|
|
711
742
|
seekSample: (timelineSample: number, renderFrame: number) => void;
|
|
712
743
|
seekPpq: (ppq: number, renderFrame: number) => void;
|
|
713
744
|
setTempo: (bpm: number) => void;
|
|
745
|
+
setTempoSegments: (segments: WasmEngineTempoSegment[]) => void;
|
|
714
746
|
setTimeSignature: (numerator: number, denominator: number) => void;
|
|
747
|
+
setTimeSignatureSegments: (segments: WasmEngineTimeSignatureSegment[]) => void;
|
|
748
|
+
sampleAtPpq: (ppq: number) => number;
|
|
715
749
|
setLoop: (startPpq: number, endPpq: number, enabled: boolean) => void;
|
|
716
750
|
addParameter: (info: WasmEngineParameterInfo) => void;
|
|
717
751
|
parameterCount: () => number;
|
|
@@ -733,6 +767,24 @@ export interface WasmRealtimeEngine {
|
|
|
733
767
|
graphConnectionCount: () => number;
|
|
734
768
|
setClips: (clips: WasmEngineClip[]) => void;
|
|
735
769
|
clipCount: () => number;
|
|
770
|
+
setTrackLanes: (lanes: Array<number | WasmEngineTrackLane>) => void;
|
|
771
|
+
setTrackBuses: (buses: WasmEngineBus[]) => void;
|
|
772
|
+
setBusStripJson: (busId: number, sceneJson: string) => void;
|
|
773
|
+
setTrackStripJson: (trackId: number, sceneJson: string) => void;
|
|
774
|
+
setTrackStripEqBandJson: (trackId: number, bandIndex: number, bandJson: string) => void;
|
|
775
|
+
setTrackStripInsertBypassed: (
|
|
776
|
+
trackId: number,
|
|
777
|
+
insertIndex: number,
|
|
778
|
+
bypassed: boolean,
|
|
779
|
+
resetOnBypass: boolean,
|
|
780
|
+
) => void;
|
|
781
|
+
setMasterStripJson: (sceneJson: string) => void;
|
|
782
|
+
setMasterStripEqBandJson: (bandIndex: number, bandJson: string) => void;
|
|
783
|
+
setMasterStripInsertBypassed: (
|
|
784
|
+
insertIndex: number,
|
|
785
|
+
bypassed: boolean,
|
|
786
|
+
resetOnBypass: boolean,
|
|
787
|
+
) => void;
|
|
736
788
|
createClipPageProvider: (numChannels: number, numSamples: number, pageFrames: number) => number;
|
|
737
789
|
supplyClipPage: (providerId: number, pageIndex: number, channels: Float32Array[]) => void;
|
|
738
790
|
clearClipPage: (providerId: number, pageIndex: number) => void;
|
|
@@ -747,7 +799,11 @@ export interface WasmRealtimeEngine {
|
|
|
747
799
|
resetCapture: () => void;
|
|
748
800
|
captureStatus: () => WasmEngineCaptureStatus;
|
|
749
801
|
capturedAudio: () => Float32Array[];
|
|
802
|
+
setMidiClips: (clips: readonly object[]) => void;
|
|
750
803
|
setBuiltinInstrument: (destinationId: number, config: object) => void;
|
|
804
|
+
setSynthInstrument: (destinationId: number, patch: object | string) => void;
|
|
805
|
+
loadSoundFont: (data: Uint8Array) => void;
|
|
806
|
+
setSf2Instrument: (destinationId: number, config: object) => void;
|
|
751
807
|
clearMidiInstrument: (destinationId: number) => void;
|
|
752
808
|
midiInstrumentCount: () => number;
|
|
753
809
|
bindMidiCc: (
|
|
@@ -759,6 +815,8 @@ export interface WasmRealtimeEngine {
|
|
|
759
815
|
) => void;
|
|
760
816
|
clearMidiCcBindings: () => void;
|
|
761
817
|
midiCcBindingCount: () => number;
|
|
818
|
+
setMidiFx: (destinationId: number, configJson: string) => void;
|
|
819
|
+
clearMidiFx: (destinationId: number) => void;
|
|
762
820
|
setMidiInputSource: (destinationId: number) => void;
|
|
763
821
|
clearMidiInputSource: () => void;
|
|
764
822
|
midiInputPendingCount: () => number;
|
|
@@ -808,6 +866,7 @@ export interface WasmRealtimeEngine {
|
|
|
808
866
|
renderFrame: number,
|
|
809
867
|
) => void;
|
|
810
868
|
pushMidiPanic: (renderFrame: number) => void;
|
|
869
|
+
clearParameters: () => void;
|
|
811
870
|
process: (channels: Float32Array[]) => Float32Array[];
|
|
812
871
|
prepareChannels: (numChannels: number, maxFrames: number) => void;
|
|
813
872
|
getChannelBuffer: (channel: number, numFrames: number) => Float32Array;
|
|
@@ -1845,6 +1904,11 @@ export interface SonareModule {
|
|
|
1845
1904
|
|
|
1846
1905
|
// Mixing - scene-based Mixer
|
|
1847
1906
|
createMixerFromSceneJson: (json: string, sampleRate: number, blockSize: number) => WasmMixer;
|
|
1907
|
+
|
|
1908
|
+
// Decodes a thrown native exception-object pointer (emscripten classic EH
|
|
1909
|
+
// surfaces a C++ throw as the raw pointer number) into a structured error.
|
|
1910
|
+
// Consumed by the module-error wrapper in module_state.ts.
|
|
1911
|
+
sonareExceptionInfo: (ptr: number) => { code: number; codeName: string; message: string };
|
|
1848
1912
|
}
|
|
1849
1913
|
|
|
1850
1914
|
export interface WasmStreamingMasteringChain {
|
|
@@ -1947,6 +2011,7 @@ export interface WasmMixer {
|
|
|
1947
2011
|
outputRightView: () => Float32Array;
|
|
1948
2012
|
processPreparedStereo: (numSamples: number) => void;
|
|
1949
2013
|
stripCount: () => number;
|
|
2014
|
+
sceneWarnings: () => string[];
|
|
1950
2015
|
scheduleInsertAutomation: (
|
|
1951
2016
|
stripIndex: number,
|
|
1952
2017
|
insertIndex: number,
|
package/src/web_midi.ts
CHANGED
|
@@ -93,6 +93,7 @@ export interface WebMidiBinding {
|
|
|
93
93
|
type BoundInput = {
|
|
94
94
|
input: MidiInputLike;
|
|
95
95
|
listener: (event: MidiMessageEventLike) => void;
|
|
96
|
+
runningStatus: number;
|
|
96
97
|
};
|
|
97
98
|
|
|
98
99
|
export function isWebMidiAvailable(): boolean {
|
|
@@ -128,7 +129,6 @@ export async function bindWebMidi(
|
|
|
128
129
|
|
|
129
130
|
const bound = new Map<string, BoundInput>();
|
|
130
131
|
let closed = false;
|
|
131
|
-
let runningStatus = 0;
|
|
132
132
|
|
|
133
133
|
const shouldBind = (input: MidiInputLike) =>
|
|
134
134
|
input.state !== 'disconnected' && (selectedIds.size === 0 || selectedIds.has(input.id));
|
|
@@ -147,22 +147,26 @@ export async function bindWebMidi(
|
|
|
147
147
|
if (bound.has(input.id) || !shouldBind(input)) {
|
|
148
148
|
return;
|
|
149
149
|
}
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
150
|
+
const entry: BoundInput = {
|
|
151
|
+
input,
|
|
152
|
+
listener: (event: MidiMessageEventLike) => {
|
|
153
|
+
entry.runningStatus = dispatchMidiMessage(
|
|
154
|
+
engine,
|
|
155
|
+
event,
|
|
156
|
+
group,
|
|
157
|
+
entry.runningStatus,
|
|
158
|
+
options.timestampToSamples,
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
runningStatus: 0,
|
|
159
162
|
};
|
|
163
|
+
const listener = entry.listener;
|
|
160
164
|
if (input.addEventListener) {
|
|
161
165
|
input.addEventListener('midimessage', listener);
|
|
162
166
|
} else {
|
|
163
167
|
input.onmidimessage = listener;
|
|
164
168
|
}
|
|
165
|
-
bound.set(input.id,
|
|
169
|
+
bound.set(input.id, entry);
|
|
166
170
|
};
|
|
167
171
|
|
|
168
172
|
const unbindInput = (input: MidiInputLike) => {
|