@opendaw/studio-core 0.0.6
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 +1 -0
- package/dist/Engine.d.ts +21 -0
- package/dist/Engine.d.ts.map +1 -0
- package/dist/Engine.js +1 -0
- package/dist/EngineFacade.d.ts +28 -0
- package/dist/EngineFacade.d.ts.map +1 -0
- package/dist/EngineFacade.js +50 -0
- package/dist/EngineWorklet.d.ts +30 -0
- package/dist/EngineWorklet.d.ts.map +1 -0
- package/dist/EngineWorklet.js +168 -0
- package/dist/MeterWorklet.d.ts +15 -0
- package/dist/MeterWorklet.d.ts.map +1 -0
- package/dist/MeterWorklet.js +33 -0
- package/dist/Mixer.d.ts +13 -0
- package/dist/Mixer.d.ts.map +1 -0
- package/dist/Mixer.js +110 -0
- package/dist/Project.d.ts +41 -0
- package/dist/Project.d.ts.map +1 -0
- package/dist/Project.js +173 -0
- package/dist/ProjectEnv.d.ts +5 -0
- package/dist/ProjectEnv.d.ts.map +1 -0
- package/dist/ProjectEnv.js +1 -0
- package/dist/RecordingWorklet.d.ts +9 -0
- package/dist/RecordingWorklet.d.ts.map +1 -0
- package/dist/RecordingWorklet.js +42 -0
- package/dist/Wav.d.ts +6 -0
- package/dist/Wav.d.ts.map +1 -0
- package/dist/Wav.js +46 -0
- package/dist/WorkletFactory.d.ts +8 -0
- package/dist/WorkletFactory.d.ts.map +1 -0
- package/dist/WorkletFactory.js +9 -0
- package/dist/Worklets.d.ts +22 -0
- package/dist/Worklets.d.ts.map +1 -0
- package/dist/Worklets.js +36 -0
- package/dist/engine-processor.js +6 -0
- package/dist/engine-processor.js.map +7 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/meter-processor.js +2 -0
- package/dist/meter-processor.js.map +7 -0
- package/dist/recording-processor.js +4 -0
- package/dist/recording-processor.js.map +7 -0
- package/dist/sync-log/Commit.d.ts +26 -0
- package/dist/sync-log/Commit.d.ts.map +1 -0
- package/dist/sync-log/Commit.js +76 -0
- package/dist/sync-log/SyncLogReader.d.ts +12 -0
- package/dist/sync-log/SyncLogReader.d.ts.map +1 -0
- package/dist/sync-log/SyncLogReader.js +51 -0
- package/dist/sync-log/SyncLogWriter.d.ts +10 -0
- package/dist/sync-log/SyncLogWriter.d.ts.map +1 -0
- package/dist/sync-log/SyncLogWriter.js +49 -0
- package/package.json +48 -0
package/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
This package is part of the openDAW SDK
|
package/dist/Engine.d.ts
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import { ppqn } from "@opendaw/lib-dsp";
|
2
|
+
import { byte, DefaultObservableValue, int, MutableObservableValue, Nullable, ObservableValue, Observer, Subscription, unitValue, UUID } from "@opendaw/lib-std";
|
3
|
+
import { ClipNotification } from "@opendaw/studio-adapters";
|
4
|
+
export interface Engine {
|
5
|
+
position(): ObservableValue<ppqn>;
|
6
|
+
isPlaying(): MutableObservableValue<boolean>;
|
7
|
+
isRecording(): MutableObservableValue<boolean>;
|
8
|
+
metronomeEnabled(): MutableObservableValue<boolean>;
|
9
|
+
isReady(): Promise<void>;
|
10
|
+
queryLoadingComplete(): Promise<boolean>;
|
11
|
+
stop(): void;
|
12
|
+
panic(): void;
|
13
|
+
noteOn(uuid: UUID.Format, pitch: byte, velocity: unitValue): void;
|
14
|
+
noteOff(uuid: UUID.Format, pitch: byte): void;
|
15
|
+
scheduleClipPlay(...clipIds: ReadonlyArray<UUID.Format>): void;
|
16
|
+
scheduleClipStop(...trackIds: ReadonlyArray<UUID.Format>): void;
|
17
|
+
requestPosition(position: ppqn): void;
|
18
|
+
subscribeClipNotification(observer: Observer<ClipNotification>): Subscription;
|
19
|
+
markerState(): DefaultObservableValue<Nullable<[UUID.Format, int]>>;
|
20
|
+
}
|
21
|
+
//# sourceMappingURL=Engine.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../src/Engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACrC,OAAO,EACH,IAAI,EACJ,sBAAsB,EACtB,GAAG,EACH,sBAAsB,EACtB,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,gBAAgB,EAAC,MAAM,0BAA0B,CAAA;AAEzD,MAAM,WAAW,MAAM;IACnB,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,CAAA;IACjC,SAAS,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAA;IAC5C,WAAW,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAA;IAC9C,gBAAgB,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAA;IACnD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IACxC,IAAI,IAAI,IAAI,CAAA;IACZ,KAAK,IAAI,IAAI,CAAA;IACb,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAA;IACjE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI,CAAA;IAC7C,gBAAgB,CAAC,GAAG,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;IAC9D,gBAAgB,CAAC,GAAG,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;IAC/D,eAAe,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAA;IACrC,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY,CAAA;IAC7E,WAAW,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;CACtE"}
|
package/dist/Engine.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { byte, DefaultObservableValue, int, MutableObservableValue, Nullable, ObservableValue, Observer, Subscription, unitValue, UUID } from "@opendaw/lib-std";
|
2
|
+
import { ppqn } from "@opendaw/lib-dsp";
|
3
|
+
import { ClipNotification } from "@opendaw/studio-adapters";
|
4
|
+
import { Engine } from "./Engine";
|
5
|
+
import { EngineWorklet } from "./EngineWorklet";
|
6
|
+
export declare class EngineFacade implements Engine {
|
7
|
+
#private;
|
8
|
+
setClient(client: EngineWorklet): void;
|
9
|
+
playbackTimestamp(): MutableObservableValue<ppqn>;
|
10
|
+
position(): ObservableValue<ppqn>;
|
11
|
+
isPlaying(): MutableObservableValue<boolean>;
|
12
|
+
isRecording(): MutableObservableValue<boolean>;
|
13
|
+
metronomeEnabled(): MutableObservableValue<boolean>;
|
14
|
+
markerState(): DefaultObservableValue<Nullable<[UUID.Format, int]>>;
|
15
|
+
isReady(): Promise<void>;
|
16
|
+
queryLoadingComplete(): Promise<boolean>;
|
17
|
+
stop(): void;
|
18
|
+
panic(): void;
|
19
|
+
sampleRate(): number;
|
20
|
+
subscribeClipNotification(observer: Observer<ClipNotification>): Subscription;
|
21
|
+
noteOn(uuid: UUID.Format, pitch: byte, velocity: unitValue): void;
|
22
|
+
noteOff(uuid: UUID.Format, pitch: byte): void;
|
23
|
+
scheduleClipPlay(...clipIds: ReadonlyArray<UUID.Format>): void;
|
24
|
+
scheduleClipStop(...trackIds: ReadonlyArray<UUID.Format>): void;
|
25
|
+
requestPosition(position: ppqn): void;
|
26
|
+
terminate(): void;
|
27
|
+
}
|
28
|
+
//# sourceMappingURL=EngineFacade.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"EngineFacade.d.ts","sourceRoot":"","sources":["../src/EngineFacade.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,IAAI,EACJ,sBAAsB,EACtB,GAAG,EACH,sBAAsB,EACtB,QAAQ,EACR,eAAe,EACf,QAAQ,EAER,YAAY,EAEZ,SAAS,EACT,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACrC,OAAO,EAAC,gBAAgB,EAAC,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAE7C,qBAAa,YAAa,YAAW,MAAM;;IAWvC,SAAS,CAAC,MAAM,EAAE,aAAa;IAuB/B,iBAAiB,IAAI,sBAAsB,CAAC,IAAI,CAAC;IACjD,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC;IACjC,SAAS,IAAI,sBAAsB,CAAC,OAAO,CAAC;IAC5C,WAAW,IAAI,sBAAsB,CAAC,OAAO,CAAC;IAC9C,gBAAgB,IAAI,sBAAsB,CAAC,OAAO,CAAC;IACnD,WAAW,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACnE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACxB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;IAGxC,IAAI,IAAI,IAAI;IACZ,KAAK,IAAI,IAAI;IACb,UAAU,IAAI,MAAM;IACpB,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY;IAG7E,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;IAGjE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI;IAC7C,gBAAgB,CAAC,GAAG,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI;IAC9D,gBAAgB,CAAC,GAAG,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI;IAC/D,eAAe,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IAErC,SAAS,IAAI,IAAI;CAKpB"}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { DefaultObservableValue, Option, Terminator } from "@opendaw/lib-std";
|
2
|
+
export class EngineFacade {
|
3
|
+
#terminator = new Terminator();
|
4
|
+
#playbackTimestamp = new DefaultObservableValue(0.0);
|
5
|
+
#position = new DefaultObservableValue(0.0);
|
6
|
+
#isPlaying = new DefaultObservableValue(false);
|
7
|
+
#isRecording = new DefaultObservableValue(false);
|
8
|
+
#metronomeEnabled = new DefaultObservableValue(false);
|
9
|
+
#markerState = new DefaultObservableValue(null);
|
10
|
+
#client = Option.None;
|
11
|
+
setClient(client) {
|
12
|
+
this.#client = Option.wrap(client);
|
13
|
+
this.#terminator.terminate();
|
14
|
+
this.#terminator.ownAll(client.playbackTimestamp().subscribe(owner => this.#playbackTimestamp.setValue(owner.getValue())), client.position().subscribe(owner => this.#position.setValue(owner.getValue())), client.isPlaying().subscribe(owner => this.#isPlaying.setValue(owner.getValue())), client.isRecording().subscribe(owner => this.#isRecording.setValue(owner.getValue())), client.metronomeEnabled().subscribe(owner => this.#metronomeEnabled.setValue(owner.getValue())), client.markerState().subscribe(owner => this.#markerState.setValue(owner.getValue())), this.position().subscribe(owner => client.position().setValue(owner.getValue())), this.isPlaying().subscribe(owner => client.isPlaying().setValue(owner.getValue())), this.isRecording().subscribe(owner => client.isRecording().setValue(owner.getValue())), this.metronomeEnabled().subscribe(owner => client.metronomeEnabled().setValue(owner.getValue())));
|
15
|
+
this.#playbackTimestamp.setValue(client.playbackTimestamp().getValue());
|
16
|
+
this.#position.setValue(client.position().getValue());
|
17
|
+
this.#isPlaying.setValue(client.isPlaying().getValue());
|
18
|
+
this.#isRecording.setValue(client.isRecording().getValue());
|
19
|
+
this.#metronomeEnabled.setValue(client.metronomeEnabled().getValue());
|
20
|
+
this.#markerState.setValue(client.markerState().getValue());
|
21
|
+
}
|
22
|
+
playbackTimestamp() { return this.#playbackTimestamp; }
|
23
|
+
position() { return this.#position; }
|
24
|
+
isPlaying() { return this.#isPlaying; }
|
25
|
+
isRecording() { return this.#isRecording; }
|
26
|
+
metronomeEnabled() { return this.#metronomeEnabled; }
|
27
|
+
markerState() { return this.#markerState; }
|
28
|
+
isReady() { return this.#client.mapOr(client => client.isReady(), Promise.resolve()); }
|
29
|
+
queryLoadingComplete() {
|
30
|
+
return this.#client.mapOr(client => client.queryLoadingComplete(), Promise.resolve(false));
|
31
|
+
}
|
32
|
+
stop() { this.#client.ifSome(client => client.stop()); }
|
33
|
+
panic() { this.#client.ifSome(client => client.panic()); }
|
34
|
+
sampleRate() { return this.#client.isEmpty() ? 44_100 : this.#client.unwrap().context.sampleRate; }
|
35
|
+
subscribeClipNotification(observer) {
|
36
|
+
return this.#client.unwrap().subscribeClipNotification(observer);
|
37
|
+
}
|
38
|
+
noteOn(uuid, pitch, velocity) {
|
39
|
+
this.#client.unwrap("No engine").noteOn(uuid, pitch, velocity);
|
40
|
+
}
|
41
|
+
noteOff(uuid, pitch) { this.#client.unwrap("No engine").noteOff(uuid, pitch); }
|
42
|
+
scheduleClipPlay(...clipIds) { this.#client.unwrap("No engine").scheduleClipPlay(...clipIds); }
|
43
|
+
scheduleClipStop(...trackIds) { this.#client.unwrap("No engine").scheduleClipStop(...trackIds); }
|
44
|
+
requestPosition(position) { this.#client.unwrap("No engine").requestPosition(position); }
|
45
|
+
terminate() {
|
46
|
+
this.#terminator.terminate();
|
47
|
+
this.#client.ifSome(client => client.terminate());
|
48
|
+
this.#client = Option.None;
|
49
|
+
}
|
50
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { byte, DefaultObservableValue, int, MutableObservableValue, Nullable, Observer, Subscription, unitValue, UUID } from "@opendaw/lib-std";
|
2
|
+
import { ppqn } from "@opendaw/lib-dsp";
|
3
|
+
import { ClipNotification, ExportStemsConfiguration } from "@opendaw/studio-adapters";
|
4
|
+
import { Project } from "./Project";
|
5
|
+
import { WorkletFactory } from "./WorkletFactory";
|
6
|
+
export declare class EngineWorklet extends AudioWorkletNode {
|
7
|
+
#private;
|
8
|
+
static bootFactory(context: BaseAudioContext, url: string): Promise<WorkletFactory<EngineWorklet>>;
|
9
|
+
static ID: int;
|
10
|
+
readonly id: number;
|
11
|
+
constructor(context: BaseAudioContext, project: Readonly<Project>, exportConfiguration?: ExportStemsConfiguration);
|
12
|
+
stop(): void;
|
13
|
+
panic(): void;
|
14
|
+
isPlaying(): MutableObservableValue<boolean>;
|
15
|
+
isRecording(): MutableObservableValue<boolean>;
|
16
|
+
playbackTimestamp(): DefaultObservableValue<number>;
|
17
|
+
position(): MutableObservableValue<ppqn>;
|
18
|
+
metronomeEnabled(): DefaultObservableValue<boolean>;
|
19
|
+
isReady(): Promise<void>;
|
20
|
+
queryLoadingComplete(): Promise<boolean>;
|
21
|
+
noteOn(uuid: UUID.Format, pitch: byte, velocity: unitValue): void;
|
22
|
+
noteOff(uuid: UUID.Format, pitch: byte): void;
|
23
|
+
scheduleClipPlay(...clipIds: ReadonlyArray<UUID.Format>): void;
|
24
|
+
scheduleClipStop(...trackIds: ReadonlyArray<UUID.Format>): void;
|
25
|
+
requestPosition(position: ppqn): void;
|
26
|
+
subscribeClipNotification(observer: Observer<ClipNotification>): Subscription;
|
27
|
+
markerState(): DefaultObservableValue<Nullable<[UUID.Format, int]>>;
|
28
|
+
terminate(): void;
|
29
|
+
}
|
30
|
+
//# sourceMappingURL=EngineWorklet.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"EngineWorklet.d.ts","sourceRoot":"","sources":["../src/EngineWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,IAAI,EACJ,sBAAsB,EACtB,GAAG,EACH,sBAAsB,EAEtB,QAAQ,EACR,QAAQ,EAER,YAAY,EAGZ,SAAS,EACT,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACrC,OAAO,EAEH,gBAAgB,EAOhB,wBAAwB,EAC3B,MAAM,0BAA0B,CAAA;AAKjC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAE/C,qBAAa,aAAc,SAAQ,gBAAgB;;IAC/C,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;IAIlG,MAAM,CAAC,EAAE,EAAE,GAAG,CAAQ;IAEtB,QAAQ,CAAC,EAAE,SAAqB;gBAgBpB,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,EAC1B,mBAAmB,CAAC,EAAE,wBAAwB;IA2G1D,IAAI,IAAI,IAAI;IASZ,KAAK,IAAI,IAAI;IACb,SAAS,IAAI,sBAAsB,CAAC,OAAO,CAAC;IAC5C,WAAW,IAAI,sBAAsB,CAAC,OAAO,CAAC;IAC9C,iBAAiB,IAAI,sBAAsB,CAAC,MAAM,CAAC;IACnD,QAAQ,IAAI,sBAAsB,CAAC,IAAI,CAAC;IACxC,gBAAgB,IAAI,sBAAsB,CAAC,OAAO,CAAC;IACnD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACxB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;IACxC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;IACjE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI;IAC7C,gBAAgB,CAAC,GAAG,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI;IAK9D,gBAAgB,CAAC,GAAG,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI;IAG/D,eAAe,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IAIrC,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY;IAQ7E,WAAW,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAInE,SAAS,IAAI,IAAI;CAKpB"}
|
@@ -0,0 +1,168 @@
|
|
1
|
+
import { Arrays, DefaultObservableValue, Notifier, Option, SyncStream, Terminator, UUID } from "@opendaw/lib-std";
|
2
|
+
import { EngineStateSchema, ExportStemsConfiguration } from "@opendaw/studio-adapters";
|
3
|
+
import { SyncSource } from "@opendaw/lib-box";
|
4
|
+
import { AnimationFrame } from "@opendaw/lib-dom";
|
5
|
+
import { Communicator, Messenger } from "@opendaw/lib-runtime";
|
6
|
+
import { WorkletFactory } from "./WorkletFactory";
|
7
|
+
export class EngineWorklet extends AudioWorkletNode {
|
8
|
+
static bootFactory(context, url) {
|
9
|
+
return WorkletFactory.boot(context, url);
|
10
|
+
}
|
11
|
+
static ID = 0 | 0;
|
12
|
+
id = EngineWorklet.ID++;
|
13
|
+
#terminator = new Terminator();
|
14
|
+
#playbackTimestamp = new DefaultObservableValue(0.0);
|
15
|
+
#position = new DefaultObservableValue(0.0);
|
16
|
+
#isPlaying = new DefaultObservableValue(false);
|
17
|
+
#isRecording = new DefaultObservableValue(false);
|
18
|
+
#metronomeEnabled = new DefaultObservableValue(false);
|
19
|
+
#markerState = new DefaultObservableValue(null);
|
20
|
+
#notifyClipNotification;
|
21
|
+
#playingClips;
|
22
|
+
#commands;
|
23
|
+
#isReady;
|
24
|
+
#ignoreUpdates = false;
|
25
|
+
constructor(context, project, exportConfiguration) {
|
26
|
+
console.debug("constructor");
|
27
|
+
const numberOfChannels = ExportStemsConfiguration.countStems(Option.wrap(exportConfiguration)) * 2;
|
28
|
+
const reader = SyncStream.reader(EngineStateSchema(), state => {
|
29
|
+
this.#ignoreUpdates = true;
|
30
|
+
this.#position.setValue(state.position);
|
31
|
+
this.#ignoreUpdates = false;
|
32
|
+
});
|
33
|
+
super(context, "engine-processor", {
|
34
|
+
numberOfInputs: 0,
|
35
|
+
numberOfOutputs: 1,
|
36
|
+
outputChannelCount: [numberOfChannels],
|
37
|
+
processorOptions: {
|
38
|
+
sab: reader.buffer,
|
39
|
+
project: project.toArrayBuffer(),
|
40
|
+
exportConfiguration
|
41
|
+
}
|
42
|
+
});
|
43
|
+
const { resolve, promise } = Promise.withResolvers();
|
44
|
+
const messenger = Messenger.for(this.port);
|
45
|
+
this.#isReady = promise;
|
46
|
+
this.#notifyClipNotification = this.#terminator.own(new Notifier());
|
47
|
+
this.#playingClips = [];
|
48
|
+
this.#commands = this.#terminator.own(Communicator.sender(messenger.channel("engine-commands"), dispatcher => new class {
|
49
|
+
setPlaying(value) { dispatcher.dispatchAndForget(this.setPlaying, value); }
|
50
|
+
setRecording(value) { dispatcher.dispatchAndForget(this.setRecording, value); }
|
51
|
+
setPosition(position) { dispatcher.dispatchAndForget(this.setPosition, position); }
|
52
|
+
setMetronomeEnabled(enabled) { dispatcher.dispatchAndForget(this.setMetronomeEnabled, enabled); }
|
53
|
+
stopAndReset() { dispatcher.dispatchAndForget(this.stopAndReset); }
|
54
|
+
queryLoadingComplete() {
|
55
|
+
return dispatcher.dispatchAndReturn(this.queryLoadingComplete);
|
56
|
+
}
|
57
|
+
panic() { dispatcher.dispatchAndForget(this.panic); }
|
58
|
+
noteOn(uuid, pitch, velocity) {
|
59
|
+
dispatcher.dispatchAndForget(this.noteOn, uuid, pitch, velocity);
|
60
|
+
}
|
61
|
+
noteOff(uuid, pitch) {
|
62
|
+
dispatcher.dispatchAndForget(this.noteOff, uuid, pitch);
|
63
|
+
}
|
64
|
+
scheduleClipPlay(clipIds) {
|
65
|
+
dispatcher.dispatchAndForget(this.scheduleClipPlay, clipIds);
|
66
|
+
}
|
67
|
+
scheduleClipStop(trackIds) {
|
68
|
+
dispatcher.dispatchAndForget(this.scheduleClipStop, trackIds);
|
69
|
+
}
|
70
|
+
terminate() { dispatcher.dispatchAndForget(this.terminate); }
|
71
|
+
}));
|
72
|
+
Communicator.executor(messenger.channel("engine-to-client"), {
|
73
|
+
log: (message) => console.log("WORKLET", message),
|
74
|
+
ready: () => resolve(),
|
75
|
+
fetchAudio: (uuid) => {
|
76
|
+
return new Promise((resolve, reject) => {
|
77
|
+
const handler = project.audioManager.getOrCreate(uuid);
|
78
|
+
handler.subscribe(state => {
|
79
|
+
if (state.type === "error") {
|
80
|
+
reject(state.reason);
|
81
|
+
}
|
82
|
+
else if (state.type === "loaded") {
|
83
|
+
resolve(handler.data.unwrap());
|
84
|
+
}
|
85
|
+
});
|
86
|
+
});
|
87
|
+
},
|
88
|
+
notifyClipSequenceChanges: (changes) => {
|
89
|
+
changes.stopped.forEach(uuid => {
|
90
|
+
for (let i = 0; i < this.#playingClips.length; i++) {
|
91
|
+
if (UUID.equals(this.#playingClips[i], uuid)) {
|
92
|
+
this.#playingClips.splice(i, 1);
|
93
|
+
break;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
});
|
97
|
+
changes.started.forEach(uuid => this.#playingClips.push(uuid));
|
98
|
+
this.#notifyClipNotification.notify({ type: "sequencing", changes });
|
99
|
+
},
|
100
|
+
switchMarkerState: (state) => this.#markerState.setValue(state)
|
101
|
+
});
|
102
|
+
this.#terminator.ownAll(AnimationFrame.add(() => reader.tryRead()), project.liveStreamReceiver.connect(messenger.channel("engine-live-data")), new SyncSource(project.boxGraph, messenger.channel("engine-sync"), false), this.#isPlaying.catchupAndSubscribe(owner => {
|
103
|
+
const isPlaying = owner.getValue();
|
104
|
+
if (isPlaying) {
|
105
|
+
this.#commands.setPosition(this.#playbackTimestamp.getValue());
|
106
|
+
}
|
107
|
+
else if (this.#isRecording.getValue()) {
|
108
|
+
this.#isRecording.setValue(false);
|
109
|
+
}
|
110
|
+
this.#commands.setPlaying(isPlaying);
|
111
|
+
}), this.#isRecording.subscribe(owner => {
|
112
|
+
const willRecord = owner.getValue();
|
113
|
+
this.#commands.setPlaying(willRecord);
|
114
|
+
this.#commands.setRecording(willRecord);
|
115
|
+
}), this.#metronomeEnabled.catchupAndSubscribe(owner => this.#commands.setMetronomeEnabled(owner.getValue())), this.#position.catchupAndSubscribe(owner => {
|
116
|
+
if (!this.#ignoreUpdates) {
|
117
|
+
this.#commands.setPosition(owner.getValue());
|
118
|
+
}
|
119
|
+
}));
|
120
|
+
}
|
121
|
+
stop() {
|
122
|
+
if (!this.#isPlaying.getValue() && this.#position.getValue() === 0.0) {
|
123
|
+
this.#commands.stopAndReset();
|
124
|
+
}
|
125
|
+
else {
|
126
|
+
this.#isRecording.setValue(false);
|
127
|
+
this.#isPlaying.setValue(false);
|
128
|
+
this.requestPosition(0.0);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
panic() { this.#commands.panic(); }
|
132
|
+
isPlaying() { return this.#isPlaying; }
|
133
|
+
isRecording() { return this.#isRecording; }
|
134
|
+
playbackTimestamp() { return this.#playbackTimestamp; }
|
135
|
+
position() { return this.#position; }
|
136
|
+
metronomeEnabled() { return this.#metronomeEnabled; }
|
137
|
+
isReady() { return this.#isReady; }
|
138
|
+
queryLoadingComplete() { return this.#commands.queryLoadingComplete(); }
|
139
|
+
noteOn(uuid, pitch, velocity) { this.#commands.noteOn(uuid, pitch, velocity); }
|
140
|
+
noteOff(uuid, pitch) { this.#commands.noteOff(uuid, pitch); }
|
141
|
+
scheduleClipPlay(...clipIds) {
|
142
|
+
this.#notifyClipNotification.notify({ type: "waiting", clips: clipIds });
|
143
|
+
this.#commands.scheduleClipPlay(clipIds);
|
144
|
+
this.#isPlaying.setValue(true); // must be second, since they might be executed in different blocks
|
145
|
+
}
|
146
|
+
scheduleClipStop(...trackIds) {
|
147
|
+
this.#commands.scheduleClipStop(trackIds);
|
148
|
+
}
|
149
|
+
requestPosition(position) {
|
150
|
+
this.#playbackTimestamp.setValue(position);
|
151
|
+
this.#commands.setPosition(position);
|
152
|
+
}
|
153
|
+
subscribeClipNotification(observer) {
|
154
|
+
observer({
|
155
|
+
type: "sequencing",
|
156
|
+
changes: { started: this.#playingClips, stopped: Arrays.empty(), obsolete: Arrays.empty() }
|
157
|
+
});
|
158
|
+
return this.#notifyClipNotification.subscribe(observer);
|
159
|
+
}
|
160
|
+
markerState() {
|
161
|
+
return this.#markerState;
|
162
|
+
}
|
163
|
+
terminate() {
|
164
|
+
console.debug(`terminate EngineClient id: ${this.id}`);
|
165
|
+
this.#terminator.terminate();
|
166
|
+
this.disconnect();
|
167
|
+
}
|
168
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { int, Observer, Subscription, Terminable } from "@opendaw/lib-std";
|
2
|
+
import { WorkletFactory } from "./WorkletFactory";
|
3
|
+
export type PeakSchema = {
|
4
|
+
peak: Float32Array;
|
5
|
+
rms: Float32Array;
|
6
|
+
};
|
7
|
+
export declare class MeterWorklet extends AudioWorkletNode implements Terminable {
|
8
|
+
#private;
|
9
|
+
static bootFactory(context: BaseAudioContext, url: string): Promise<WorkletFactory<MeterWorklet>>;
|
10
|
+
static create(factory: WorkletFactory<MeterWorklet>, numChannels: int): MeterWorklet;
|
11
|
+
private constructor();
|
12
|
+
subscribe(observer: Observer<PeakSchema>): Subscription;
|
13
|
+
terminate(): void;
|
14
|
+
}
|
15
|
+
//# sourceMappingURL=MeterWorklet.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"MeterWorklet.d.ts","sourceRoot":"","sources":["../src/MeterWorklet.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAY,QAAQ,EAAU,YAAY,EAAc,UAAU,EAAa,MAAM,kBAAkB,CAAA;AAElH,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAE/C,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,YAAY,CAAA;CAAE,CAAA;AAElE,qBAAa,YAAa,SAAQ,gBAAiB,YAAW,UAAU;;WACvD,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IAIvG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,EAAE,WAAW,EAAE,GAAG,GAAG,YAAY;IAOpF,OAAO;IAmBP,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY;IAEvD,SAAS,IAAI,IAAI;CACpB"}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import { Notifier, Schema, SyncStream, Terminator } from "@opendaw/lib-std";
|
2
|
+
import { AnimationFrame } from "@opendaw/lib-dom";
|
3
|
+
import { WorkletFactory } from "./WorkletFactory";
|
4
|
+
export class MeterWorklet extends AudioWorkletNode {
|
5
|
+
static async bootFactory(context, url) {
|
6
|
+
return WorkletFactory.boot(context, url);
|
7
|
+
}
|
8
|
+
static create(factory, numChannels) {
|
9
|
+
return factory.create(context => new MeterWorklet(context, numChannels));
|
10
|
+
}
|
11
|
+
#terminator = new Terminator();
|
12
|
+
#notifier = new Notifier();
|
13
|
+
constructor(context, numberOfChannels) {
|
14
|
+
const receiver = SyncStream.reader(Schema.createBuilder({
|
15
|
+
peak: Schema.floats(numberOfChannels),
|
16
|
+
rms: Schema.floats(numberOfChannels)
|
17
|
+
})(), (data) => this.#notifier.notify(data));
|
18
|
+
super(context, "peak-meter-processor", {
|
19
|
+
numberOfInputs: 1,
|
20
|
+
channelCount: numberOfChannels,
|
21
|
+
channelCountMode: "explicit",
|
22
|
+
processorOptions: {
|
23
|
+
sab: receiver.buffer,
|
24
|
+
numberOfChannels,
|
25
|
+
rmsWindowInSeconds: 0.100,
|
26
|
+
valueDecay: 0.200
|
27
|
+
}
|
28
|
+
});
|
29
|
+
this.#terminator.own(AnimationFrame.add(() => receiver.tryRead()));
|
30
|
+
}
|
31
|
+
subscribe(observer) { return this.#notifier.subscribe(observer); }
|
32
|
+
terminate() { this.#terminator.terminate(); }
|
33
|
+
}
|
package/dist/Mixer.d.ts
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Terminable } from "@opendaw/lib-std";
|
2
|
+
import { Pointers } from "@opendaw/studio-enums";
|
3
|
+
import { AudioUnitBoxAdapter, SortedBoxAdapterCollection } from "@opendaw/studio-adapters";
|
4
|
+
export interface ChannelStripView {
|
5
|
+
silent(value: boolean): void;
|
6
|
+
}
|
7
|
+
export declare class Mixer implements Terminable {
|
8
|
+
#private;
|
9
|
+
constructor(audioUnits: SortedBoxAdapterCollection<AudioUnitBoxAdapter, Pointers.AudioUnits>);
|
10
|
+
registerChannelStrip({ uuid }: AudioUnitBoxAdapter, view: ChannelStripView): Terminable;
|
11
|
+
terminate(): void;
|
12
|
+
}
|
13
|
+
//# sourceMappingURL=Mixer.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"Mixer.d.ts","sourceRoot":"","sources":["../src/Mixer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwD,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AACpH,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAE9C,OAAO,EAAC,mBAAmB,EAAE,0BAA0B,EAAC,MAAM,0BAA0B,CAAA;AAIxF,MAAM,WAAW,gBAAgB;IAC7B,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;CAC/B;AAQD,qBAAa,KAAM,YAAW,UAAU;;gBAOxB,UAAU,EAAE,0BAA0B,CAAC,mBAAmB,EAAE,QAAQ,CAAC,UAAU,CAAC;IAuC5F,oBAAoB,CAAC,EAAC,IAAI,EAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,gBAAgB,GAAG,UAAU;IASrF,SAAS,IAAI,IAAI;CAqDpB"}
|
package/dist/Mixer.js
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
import { Arrays, asDefined, EmptyExec, Terminable, Terminator, UUID } from "@opendaw/lib-std";
|
2
|
+
import { Pointers } from "@opendaw/studio-enums";
|
3
|
+
import { deferNextFrame } from "@opendaw/lib-dom";
|
4
|
+
export class Mixer {
|
5
|
+
#terminator = new Terminator();
|
6
|
+
#states;
|
7
|
+
#solo;
|
8
|
+
#virtualSolo;
|
9
|
+
#deferUpdate;
|
10
|
+
constructor(audioUnits) {
|
11
|
+
this.#states = UUID.newSet(({ adapter: { uuid } }) => uuid);
|
12
|
+
this.#solo = new Set();
|
13
|
+
this.#virtualSolo = new Set();
|
14
|
+
this.#deferUpdate = this.#terminator.own(deferNextFrame(() => this.#updateStates()));
|
15
|
+
this.#terminator.own(audioUnits.catchupAndSubscribe({
|
16
|
+
onAdd: (adapter) => {
|
17
|
+
const { mute, solo } = adapter.namedParameter;
|
18
|
+
const views = [];
|
19
|
+
this.#states.add({
|
20
|
+
adapter,
|
21
|
+
views,
|
22
|
+
subscription: Terminable.many(mute.catchupAndSubscribe(owner => {
|
23
|
+
if (owner.getControlledValue()) {
|
24
|
+
views.forEach(view => view.silent(true));
|
25
|
+
}
|
26
|
+
else {
|
27
|
+
this.#deferUpdate.request();
|
28
|
+
}
|
29
|
+
}), solo.catchupAndSubscribe(owner => {
|
30
|
+
if (owner.getControlledValue()) {
|
31
|
+
this.#solo.add(adapter);
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
this.#solo.delete(adapter);
|
35
|
+
}
|
36
|
+
this.#deferUpdate.request();
|
37
|
+
}))
|
38
|
+
});
|
39
|
+
},
|
40
|
+
onRemove: (adapter) => {
|
41
|
+
this.#solo.delete(adapter);
|
42
|
+
this.#states.removeByKey(adapter.uuid).subscription.terminate();
|
43
|
+
this.#deferUpdate.request();
|
44
|
+
},
|
45
|
+
onReorder: EmptyExec
|
46
|
+
}));
|
47
|
+
}
|
48
|
+
registerChannelStrip({ uuid }, view) {
|
49
|
+
this.#states.get(uuid).views.push(view);
|
50
|
+
this.#deferUpdate.request();
|
51
|
+
return Terminable.create(() => {
|
52
|
+
this.#states.opt(uuid).ifSome(({ views }) => Arrays.remove(views, view));
|
53
|
+
this.#deferUpdate.request();
|
54
|
+
});
|
55
|
+
}
|
56
|
+
terminate() { this.#terminator.terminate(); }
|
57
|
+
#updateStates() {
|
58
|
+
this.#virtualSolo.clear();
|
59
|
+
this.#processChannelStrips();
|
60
|
+
this.#updateChannelStripViews();
|
61
|
+
}
|
62
|
+
#processChannelStrips() {
|
63
|
+
const touched = new Set();
|
64
|
+
const processUpstreamChannels = (adapter) => {
|
65
|
+
if (touched.has(adapter)) {
|
66
|
+
return;
|
67
|
+
}
|
68
|
+
touched.add(adapter);
|
69
|
+
adapter.input.getValue().ifSome(input => {
|
70
|
+
if (input.type === "bus") {
|
71
|
+
input.box.input.pointerHub
|
72
|
+
.filter(Pointers.AudioOutput)
|
73
|
+
.map(pointer => this.#resolveAdapter(pointer.box))
|
74
|
+
.forEach((adapter) => {
|
75
|
+
const { namedParameter: { solo } } = adapter;
|
76
|
+
if (!solo.getControlledValue()) {
|
77
|
+
this.#virtualSolo.add(adapter);
|
78
|
+
}
|
79
|
+
processUpstreamChannels(adapter);
|
80
|
+
});
|
81
|
+
}
|
82
|
+
});
|
83
|
+
};
|
84
|
+
this.#states.forEach(({ adapter }) => {
|
85
|
+
const { namedParameter: { solo } } = adapter;
|
86
|
+
if (solo.getControlledValue()) {
|
87
|
+
processUpstreamChannels(adapter);
|
88
|
+
}
|
89
|
+
});
|
90
|
+
}
|
91
|
+
#resolveAdapter(box) {
|
92
|
+
return asDefined(box.accept({
|
93
|
+
visitAudioUnitBox: ({ address: { uuid } }) => this.#states.get(uuid).adapter,
|
94
|
+
visitAuxSendBox: ({ audioUnit: { targetVertex } }) => this.#states.get(targetVertex.unwrap().address.uuid).adapter
|
95
|
+
}), "Could not resolve entry");
|
96
|
+
}
|
97
|
+
#updateChannelStripViews() {
|
98
|
+
this.#states.forEach(({ adapter, views }) => {
|
99
|
+
const { mute, solo } = adapter.namedParameter;
|
100
|
+
if (mute.getControlledValue()) {
|
101
|
+
views.forEach(view => view.silent(true));
|
102
|
+
}
|
103
|
+
else {
|
104
|
+
const isSolo = solo.getControlledValue() || this.#virtualSolo.has(adapter);
|
105
|
+
const value = this.#solo.size > 0 && !isSolo && !adapter.isOutput;
|
106
|
+
views.forEach(view => view.silent(value));
|
107
|
+
}
|
108
|
+
});
|
109
|
+
}
|
110
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { Terminable, TerminableOwner, Terminator } from "@opendaw/lib-std";
|
2
|
+
import { BoxGraph, Editing } from "@opendaw/lib-box";
|
3
|
+
import { AudioBusBox, AudioUnitBox, BoxIO, RootBox, TimelineBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
4
|
+
import { AudioLoaderManager, BoxAdapters, BoxAdaptersContext, ClipSequencing, ParameterFieldAdapters, RootBoxAdapter, TimelineBoxAdapter, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
|
5
|
+
import { LiveStreamBroadcaster, LiveStreamReceiver } from "@opendaw/lib-fusion";
|
6
|
+
import { ProjectEnv } from "./ProjectEnv";
|
7
|
+
import { Mixer } from "./Mixer";
|
8
|
+
export declare class Project implements BoxAdaptersContext, Terminable, TerminableOwner {
|
9
|
+
#private;
|
10
|
+
static new(env: ProjectEnv): Project;
|
11
|
+
static load(env: ProjectEnv, arrayBuffer: ArrayBuffer): Project;
|
12
|
+
readonly boxGraph: BoxGraph<BoxIO.TypeMap>;
|
13
|
+
readonly rootBox: RootBox;
|
14
|
+
readonly userInterfaceBox: UserInterfaceBox;
|
15
|
+
readonly masterBusBox: AudioBusBox;
|
16
|
+
readonly masterAudioUnit: AudioUnitBox;
|
17
|
+
readonly timelineBox: TimelineBox;
|
18
|
+
readonly editing: Editing;
|
19
|
+
readonly selection: VertexSelection;
|
20
|
+
readonly boxAdapters: BoxAdapters;
|
21
|
+
readonly userEditingManager: UserEditingManager;
|
22
|
+
readonly parameterFieldAdapters: ParameterFieldAdapters;
|
23
|
+
readonly liveStreamReceiver: LiveStreamReceiver;
|
24
|
+
readonly mixer: Mixer;
|
25
|
+
private constructor();
|
26
|
+
own<T extends Terminable>(terminable: T): T;
|
27
|
+
ownAll<T extends Terminable>(...terminables: Array<T>): void;
|
28
|
+
spawn(): Terminator;
|
29
|
+
get bpm(): number;
|
30
|
+
get rootBoxAdapter(): RootBoxAdapter;
|
31
|
+
get timelineBoxAdapter(): TimelineBoxAdapter;
|
32
|
+
get audioManager(): AudioLoaderManager;
|
33
|
+
get clipSequencing(): ClipSequencing;
|
34
|
+
get isAudioContext(): boolean;
|
35
|
+
get isMainThread(): boolean;
|
36
|
+
get liveStreamBroadcaster(): LiveStreamBroadcaster;
|
37
|
+
toArrayBuffer(): ArrayBufferLike;
|
38
|
+
copy(): Project;
|
39
|
+
terminate(): void;
|
40
|
+
}
|
41
|
+
//# sourceMappingURL=Project.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../src/Project.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,UAAU,EACV,eAAe,EACf,UAAU,EAEb,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,QAAQ,EAAE,OAAO,EAAC,MAAM,kBAAkB,CAAA;AAClD,OAAO,EACH,WAAW,EACX,YAAY,EACZ,KAAK,EAGL,OAAO,EACP,WAAW,EACX,gBAAgB,EAInB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACH,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,cAAc,EAGd,sBAAsB,EAEtB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EAClB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,qBAAqB,EAAE,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AAE7E,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AACvC,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAA;AAI7B,qBAAa,OAAQ,YAAW,kBAAkB,EAAE,UAAU,EAAE,eAAe;;IAC3E,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO;IAuCpC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO;IA8D/D,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAE1C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAA;IAC3C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAA;IAClC,QAAQ,CAAC,eAAe,EAAE,YAAY,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IAEjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAA;IAC/C,QAAQ,CAAC,sBAAsB,EAAE,sBAAsB,CAAA;IACvD,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAA;IAC/C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IAErB,OAAO;IA6BP,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;IAC3C,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,GAAG,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI;IAC5D,KAAK,IAAI,UAAU;IAEnB,IAAI,GAAG,IAAI,MAAM,CAAyC;IAC1D,IAAI,cAAc,IAAI,cAAc,CAAmE;IACvG,IAAI,kBAAkB,IAAI,kBAAkB,CAA2E;IACvH,IAAI,YAAY,IAAI,kBAAkB,CAAgC;IACtE,IAAI,cAAc,IAAI,cAAc,CAAkD;IACtF,IAAI,cAAc,IAAI,OAAO,CAAe;IAC5C,IAAI,YAAY,IAAI,OAAO,CAAc;IACzC,IAAI,qBAAqB,IAAI,qBAAqB,CAAkD;IAEpG,aAAa,IAAI,eAAe;IAiBhC,IAAI,IAAI,OAAO;IAEf,SAAS,IAAI,IAAI;CACpB"}
|