@opendaw/studio-core 0.0.37 → 0.0.38
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/dist/Engine.d.ts +2 -1
- package/dist/Engine.d.ts.map +1 -1
- package/dist/EngineFacade.d.ts +1 -0
- package/dist/EngineFacade.d.ts.map +1 -1
- package/dist/EngineFacade.js +3 -1
- package/dist/EngineWorklet.d.ts +1 -0
- package/dist/EngineWorklet.d.ts.map +1 -1
- package/dist/EngineWorklet.js +9 -2
- package/dist/RecordingWorklet.d.ts.map +1 -1
- package/dist/RecordingWorklet.js +12 -5
- package/dist/capture/CaptureMidi.js +12 -12
- package/dist/capture/RecordAudio.d.ts +2 -2
- package/dist/capture/RecordAudio.d.ts.map +1 -1
- package/dist/clouds/CloudAuthManager.d.ts.map +1 -1
- package/dist/clouds/CloudAuthManager.js +10 -2
- package/dist/clouds/CloudBackupSamples.d.ts.map +1 -1
- package/dist/clouds/CloudBackupSamples.js +6 -1
- package/dist/index.d.ts +1 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -7
- package/dist/midi/MIDIMessageSubscriber.js +4 -4
- package/dist/midi/MidiDevices.d.ts +6 -2
- package/dist/midi/MidiDevices.d.ts.map +1 -1
- package/dist/midi/MidiDevices.js +11 -2
- package/dist/midi/SoftwareMIDIInput.d.ts +27 -0
- package/dist/midi/SoftwareMIDIInput.d.ts.map +1 -0
- package/dist/midi/SoftwareMIDIInput.js +42 -0
- package/dist/processors.js +3 -3
- package/dist/processors.js.map +3 -3
- package/dist/project/Project.d.ts +3 -3
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +3 -1
- package/dist/project/ProjectBundle.d.ts.map +1 -1
- package/dist/project/ProjectBundle.js +1 -1
- package/dist/project/ProjectEnv.d.ts +2 -2
- package/dist/project/ProjectEnv.d.ts.map +1 -1
- package/dist/samples/{MainThreadSampleLoader.d.ts → DefaultSampleLoader.d.ts} +4 -4
- package/dist/samples/DefaultSampleLoader.d.ts.map +1 -0
- package/dist/samples/{MainThreadSampleLoader.js → DefaultSampleLoader.js} +7 -2
- package/dist/samples/{MainThreadSampleManager.d.ts → DefaultSampleLoaderManager.d.ts} +4 -5
- package/dist/samples/DefaultSampleLoaderManager.d.ts.map +1 -0
- package/dist/samples/DefaultSampleLoaderManager.js +19 -0
- package/dist/samples/OpenSampleAPI.d.ts.map +1 -1
- package/dist/samples/OpenSampleAPI.js +3 -2
- package/dist/samples/P2PSampleProvider.d.ts +13 -0
- package/dist/samples/P2PSampleProvider.d.ts.map +1 -0
- package/dist/samples/P2PSampleProvider.js +350 -0
- package/dist/samples/SampleStorage.d.ts +7 -1
- package/dist/samples/SampleStorage.d.ts.map +1 -1
- package/dist/samples/SampleStorage.js +1 -1
- package/dist/samples/index.d.ts +9 -0
- package/dist/samples/index.d.ts.map +1 -0
- package/dist/samples/index.js +8 -0
- package/dist/workers-main.js +2 -2
- package/dist/workers-main.js.map +3 -3
- package/package.json +15 -14
- package/dist/samples/MainThreadSampleLoader.d.ts.map +0 -1
- package/dist/samples/MainThreadSampleManager.d.ts.map +0 -1
- package/dist/samples/MainThreadSampleManager.js +0 -22
package/dist/Engine.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { ppqn } from "@opendaw/lib-dsp";
|
2
|
-
import { int, Nullable, ObservableValue, Observer, Subscription, Terminable, UUID } from "@opendaw/lib-std";
|
2
|
+
import { int, MutableObservableValue, Nullable, ObservableValue, Observer, Subscription, Terminable, UUID } from "@opendaw/lib-std";
|
3
3
|
import { ClipNotification, NoteSignal } from "@opendaw/studio-adapters";
|
4
4
|
import { Project } from "./project/Project";
|
5
5
|
export interface Engine extends Terminable {
|
@@ -24,6 +24,7 @@ export interface Engine extends Terminable {
|
|
24
24
|
get isCountingIn(): ObservableValue<boolean>;
|
25
25
|
get metronomeEnabled(): ObservableValue<boolean>;
|
26
26
|
get playbackTimestamp(): ObservableValue<ppqn>;
|
27
|
+
get playbackTimestampEnabled(): MutableObservableValue<boolean>;
|
27
28
|
get countInBeatsTotal(): ObservableValue<int>;
|
28
29
|
get countInBeatsRemaining(): ObservableValue<number>;
|
29
30
|
get markerState(): ObservableValue<Nullable<[UUID.Bytes, int]>>;
|
package/dist/Engine.d.ts.map
CHANGED
@@ -1 +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,
|
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,GAAG,EACH,sBAAsB,EACtB,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,gBAAgB,EAAE,UAAU,EAAC,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAA;AAEzC,MAAM,WAAW,MAAO,SAAQ,UAAU;IACtC,IAAI,IAAI,IAAI,CAAA;IACZ,IAAI,IAAI,IAAI,CAAA;IACZ,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAA;IACjC,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACtC,aAAa,IAAI,IAAI,CAAA;IACrB,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,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAA;IACpC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY,CAAA;IAC5D,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IACxC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAA;IAC1D,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAA;IAC3D,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY,CAAA;IAE7E,IAAI,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,CAAA;IACrC,IAAI,SAAS,IAAI,eAAe,CAAC,OAAO,CAAC,CAAA;IACzC,IAAI,WAAW,IAAI,eAAe,CAAC,OAAO,CAAC,CAAA;IAC3C,IAAI,YAAY,IAAI,eAAe,CAAC,OAAO,CAAC,CAAA;IAC5C,IAAI,gBAAgB,IAAI,eAAe,CAAC,OAAO,CAAC,CAAA;IAChD,IAAI,iBAAiB,IAAI,eAAe,CAAC,IAAI,CAAC,CAAA;IAC9C,IAAI,wBAAwB,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAA;IAC/D,IAAI,iBAAiB,IAAI,eAAe,CAAC,GAAG,CAAC,CAAA;IAC7C,IAAI,qBAAqB,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;IACpD,IAAI,WAAW,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;IAC/D,IAAI,OAAO,IAAI,OAAO,CAAA;CACzB"}
|
package/dist/EngineFacade.d.ts
CHANGED
@@ -21,6 +21,7 @@ export declare class EngineFacade implements Engine {
|
|
21
21
|
get isCountingIn(): ObservableValue<boolean>;
|
22
22
|
get metronomeEnabled(): MutableObservableValue<boolean>;
|
23
23
|
get playbackTimestamp(): ObservableValue<ppqn>;
|
24
|
+
get playbackTimestampEnabled(): MutableObservableValue<boolean>;
|
24
25
|
get countInBeatsTotal(): ObservableValue<int>;
|
25
26
|
get countInBeatsRemaining(): ObservableValue<int>;
|
26
27
|
get markerState(): DefaultObservableValue<Nullable<[UUID.Bytes, int]>>;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"EngineFacade.d.ts","sourceRoot":"","sources":["../src/EngineFacade.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,sBAAsB,EACtB,GAAG,EACH,sBAAsB,EACtB,QAAQ,EACR,eAAe,EACf,QAAQ,EAER,YAAY,EAEZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACrC,OAAO,EAAC,gBAAgB,EAAE,UAAU,EAAC,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAA;AAEzC,qBAAa,YAAa,YAAW,MAAM;;;
|
1
|
+
{"version":3,"file":"EngineFacade.d.ts","sourceRoot":"","sources":["../src/EngineFacade.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,sBAAsB,EACtB,GAAG,EACH,sBAAsB,EACtB,QAAQ,EACR,eAAe,EACf,QAAQ,EAER,YAAY,EAEZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACrC,OAAO,EAAC,gBAAgB,EAAE,UAAU,EAAC,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAA;AAEzC,qBAAa,YAAa,YAAW,MAAM;;;IAmBvC,UAAU,CAAC,OAAO,EAAE,aAAa;IAmBjC,aAAa,IAAI,IAAI;IAErB,cAAc,IAAI,IAAI;IAMtB,IAAI,IAAI,IAAI;IACZ,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,IAAI;IAClC,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IACjC,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IACtC,aAAa,IAAI,IAAI;IAErB,IAAI,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,CAAwB;IAC7D,IAAI,SAAS,IAAI,eAAe,CAAC,OAAO,CAAC,CAAyB;IAClE,IAAI,WAAW,IAAI,eAAe,CAAC,OAAO,CAAC,CAA2B;IACtE,IAAI,YAAY,IAAI,eAAe,CAAC,OAAO,CAAC,CAA4B;IACxE,IAAI,gBAAgB,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAgC;IACvF,IAAI,iBAAiB,IAAI,eAAe,CAAC,IAAI,CAAC,CAAiC;IAC/E,IAAI,wBAAwB,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAwC;IACvG,IAAI,iBAAiB,IAAI,eAAe,CAAC,GAAG,CAAC,CAAiC;IAC9E,IAAI,qBAAqB,IAAI,eAAe,CAAC,GAAG,CAAC,CAAqC;IACtF,IAAI,WAAW,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAA2B;IACjG,IAAI,OAAO,IAAI,OAAO,CAAmE;IAEzF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACxB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;IAGxC,KAAK,IAAI,IAAI;IACb,UAAU,IAAI,MAAM;IACpB,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY;IAG7E,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY;IAG5D,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI;IAGxC,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAGpC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI;IAG1D,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI;IAI3D,SAAS,IAAI,IAAI;CAIpB"}
|
package/dist/EngineFacade.js
CHANGED
@@ -3,6 +3,7 @@ export class EngineFacade {
|
|
3
3
|
#terminator = new Terminator();
|
4
4
|
#lifecycle = this.#terminator.own(new Terminator());
|
5
5
|
#playbackTimestamp = new DefaultObservableValue(0.0);
|
6
|
+
#playbackTimestampEnabled = new DefaultObservableValue(true);
|
6
7
|
#countInBeatsTotal = new DefaultObservableValue(4);
|
7
8
|
#countInBeatsRemaining = new DefaultObservableValue(0);
|
8
9
|
#position = new DefaultObservableValue(0.0);
|
@@ -16,7 +17,7 @@ export class EngineFacade {
|
|
16
17
|
setWorklet(worklet) {
|
17
18
|
this.#worklet = Option.wrap(worklet);
|
18
19
|
this.#lifecycle.terminate();
|
19
|
-
this.#lifecycle.ownAll(worklet.playbackTimestamp.catchupAndSubscribe(owner => this.#playbackTimestamp.setValue(owner.getValue())), worklet.countInBeatsTotal.catchupAndSubscribe(owner => this.#countInBeatsTotal.setValue(owner.getValue())), worklet.countInBeatsRemaining.catchupAndSubscribe(owner => this.#countInBeatsRemaining.setValue(owner.getValue())), worklet.position.catchupAndSubscribe(owner => this.#position.setValue(owner.getValue())), worklet.isPlaying.catchupAndSubscribe(owner => this.#isPlaying.setValue(owner.getValue())), worklet.isRecording.catchupAndSubscribe(owner => this.#isRecording.setValue(owner.getValue())), worklet.isCountingIn.catchupAndSubscribe(owner => this.#isCountingIn.setValue(owner.getValue())), worklet.metronomeEnabled.catchupAndSubscribe(owner => this.#metronomeEnabled.setValue(owner.getValue())), worklet.markerState.catchupAndSubscribe(owner => this.#markerState.setValue(owner.getValue())), this
|
20
|
+
this.#lifecycle.ownAll(worklet.playbackTimestamp.catchupAndSubscribe(owner => this.#playbackTimestamp.setValue(owner.getValue())), worklet.playbackTimestampEnabled.catchupAndSubscribe(owner => this.#playbackTimestampEnabled.setValue(owner.getValue())), worklet.countInBeatsTotal.catchupAndSubscribe(owner => this.#countInBeatsTotal.setValue(owner.getValue())), worklet.countInBeatsRemaining.catchupAndSubscribe(owner => this.#countInBeatsRemaining.setValue(owner.getValue())), worklet.position.catchupAndSubscribe(owner => this.#position.setValue(owner.getValue())), worklet.isPlaying.catchupAndSubscribe(owner => this.#isPlaying.setValue(owner.getValue())), worklet.isRecording.catchupAndSubscribe(owner => this.#isRecording.setValue(owner.getValue())), worklet.isCountingIn.catchupAndSubscribe(owner => this.#isCountingIn.setValue(owner.getValue())), worklet.metronomeEnabled.catchupAndSubscribe(owner => this.#metronomeEnabled.setValue(owner.getValue())), worklet.markerState.catchupAndSubscribe(owner => this.#markerState.setValue(owner.getValue())), this.#metronomeEnabled.catchupAndSubscribe(owner => worklet.metronomeEnabled.setValue(owner.getValue())), this.#playbackTimestampEnabled.catchupAndSubscribe(owner => worklet.playbackTimestampEnabled.setValue(owner.getValue())));
|
20
21
|
}
|
21
22
|
assertWorklet() { this.#worklet.unwrap("No worklet available"); }
|
22
23
|
releaseWorklet() {
|
@@ -35,6 +36,7 @@ export class EngineFacade {
|
|
35
36
|
get isCountingIn() { return this.#isCountingIn; }
|
36
37
|
get metronomeEnabled() { return this.#metronomeEnabled; }
|
37
38
|
get playbackTimestamp() { return this.#playbackTimestamp; }
|
39
|
+
get playbackTimestampEnabled() { return this.#playbackTimestampEnabled; }
|
38
40
|
get countInBeatsTotal() { return this.#countInBeatsTotal; }
|
39
41
|
get countInBeatsRemaining() { return this.#countInBeatsRemaining; }
|
40
42
|
get markerState() { return this.#markerState; }
|
package/dist/EngineWorklet.d.ts
CHANGED
@@ -21,6 +21,7 @@ export declare class EngineWorklet extends AudioWorkletNode implements Engine {
|
|
21
21
|
get countInBeatsRemaining(): ObservableValue<number>;
|
22
22
|
get position(): ObservableValue<ppqn>;
|
23
23
|
get playbackTimestamp(): MutableObservableValue<number>;
|
24
|
+
get playbackTimestampEnabled(): MutableObservableValue<boolean>;
|
24
25
|
get metronomeEnabled(): MutableObservableValue<boolean>;
|
25
26
|
get markerState(): ObservableValue<Nullable<[UUID.Bytes, int]>>;
|
26
27
|
get project(): Project;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"EngineWorklet.d.ts","sourceRoot":"","sources":["../src/EngineWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,GAAG,EACH,sBAAsB,EAEtB,QAAQ,EACR,eAAe,EACf,QAAQ,EAER,YAAY,EAGZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAIrC,OAAO,EAEH,gBAAgB,EAOhB,wBAAwB,EACxB,UAAU,EACV,gBAAgB,EACnB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAA;AACzC,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAA;AAE/B,qBAAa,aAAc,SAAQ,gBAAiB,YAAW,MAAM;;IACjE,MAAM,CAAC,EAAE,EAAE,GAAG,CAAQ;IAEtB,QAAQ,CAAC,EAAE,SAAqB;
|
1
|
+
{"version":3,"file":"EngineWorklet.d.ts","sourceRoot":"","sources":["../src/EngineWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,GAAG,EACH,sBAAsB,EAEtB,QAAQ,EACR,eAAe,EACf,QAAQ,EAER,YAAY,EAGZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAIrC,OAAO,EAEH,gBAAgB,EAOhB,wBAAwB,EACxB,UAAU,EACV,gBAAgB,EACnB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAA;AACzC,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAA;AAE/B,qBAAa,aAAc,SAAQ,gBAAiB,YAAW,MAAM;;IACjE,MAAM,CAAC,EAAE,EAAE,GAAG,CAAQ;IAEtB,QAAQ,CAAC,EAAE,SAAqB;gBAqBpB,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,OAAO,EAChB,mBAAmB,CAAC,EAAE,wBAAwB,EAC9C,OAAO,CAAC,EAAE,gBAAgB;IAsGtC,IAAI,IAAI,IAAI;IACZ,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,IAAI;IAClC,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IACjC,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IACtC,aAAa,IAAI,IAAI;IACrB,KAAK,IAAI,IAAI;IAEb,IAAI,SAAS,IAAI,eAAe,CAAC,OAAO,CAAC,CAAyB;IAClE,IAAI,WAAW,IAAI,eAAe,CAAC,OAAO,CAAC,CAA2B;IACtE,IAAI,YAAY,IAAI,eAAe,CAAC,OAAO,CAAC,CAA4B;IACxE,IAAI,iBAAiB,IAAI,eAAe,CAAC,GAAG,CAAC,CAAiC;IAC9E,IAAI,qBAAqB,IAAI,eAAe,CAAC,MAAM,CAAC,CAAqC;IACzF,IAAI,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,CAAwB;IAC7D,IAAI,iBAAiB,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAiC;IACxF,IAAI,wBAAwB,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAwC;IACvG,IAAI,gBAAgB,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAgC;IACvF,IAAI,WAAW,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAA2B;IAC1F,IAAI,OAAO,IAAI,OAAO,CAAuB;IAE7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACxB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;IACxC,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IACpC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY;IAC5D,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI;IACxC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI;IAI1D,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI;IAG3D,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY;IAQ7E,SAAS,IAAI,IAAI;CAIpB"}
|
package/dist/EngineWorklet.js
CHANGED
@@ -9,6 +9,7 @@ export class EngineWorklet extends AudioWorkletNode {
|
|
9
9
|
#terminator = new Terminator();
|
10
10
|
#project;
|
11
11
|
#playbackTimestamp = new DefaultObservableValue(0.0);
|
12
|
+
#playbackTimestampEnabled = new DefaultObservableValue(true);
|
12
13
|
#position = new DefaultObservableValue(0.0);
|
13
14
|
#isPlaying = new DefaultObservableValue(false);
|
14
15
|
#isRecording = new DefaultObservableValue(false);
|
@@ -57,7 +58,12 @@ export class EngineWorklet extends AudioWorkletNode {
|
|
57
58
|
setPosition(position) { dispatcher.dispatchAndForget(this.setPosition, position); }
|
58
59
|
startRecording(countIn) { dispatcher.dispatchAndForget(this.startRecording, countIn); }
|
59
60
|
stopRecording() { dispatcher.dispatchAndForget(this.stopRecording); }
|
60
|
-
setMetronomeEnabled(enabled) {
|
61
|
+
setMetronomeEnabled(enabled) {
|
62
|
+
dispatcher.dispatchAndForget(this.setMetronomeEnabled, enabled);
|
63
|
+
}
|
64
|
+
setPlaybackTimestampEnabled(enabled) {
|
65
|
+
dispatcher.dispatchAndForget(this.setPlaybackTimestampEnabled, enabled);
|
66
|
+
}
|
61
67
|
queryLoadingComplete() {
|
62
68
|
return dispatcher.dispatchAndReturn(this.queryLoadingComplete);
|
63
69
|
}
|
@@ -104,7 +110,7 @@ export class EngineWorklet extends AudioWorkletNode {
|
|
104
110
|
},
|
105
111
|
switchMarkerState: (state) => this.#markerState.setValue(state)
|
106
112
|
});
|
107
|
-
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.#metronomeEnabled.catchupAndSubscribe(owner => this.#commands.setMetronomeEnabled(owner.getValue())));
|
113
|
+
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.#metronomeEnabled.catchupAndSubscribe(owner => this.#commands.setMetronomeEnabled(owner.getValue())), this.#playbackTimestampEnabled.catchupAndSubscribe(owner => this.#commands.setPlaybackTimestampEnabled(owner.getValue())));
|
108
114
|
}
|
109
115
|
play() { this.#commands.play(); }
|
110
116
|
stop(reset = false) { this.#commands.stop(reset); }
|
@@ -119,6 +125,7 @@ export class EngineWorklet extends AudioWorkletNode {
|
|
119
125
|
get countInBeatsRemaining() { return this.#countInBeatsRemaining; }
|
120
126
|
get position() { return this.#position; }
|
121
127
|
get playbackTimestamp() { return this.#playbackTimestamp; }
|
128
|
+
get playbackTimestampEnabled() { return this.#playbackTimestampEnabled; }
|
122
129
|
get metronomeEnabled() { return this.#metronomeEnabled; }
|
123
130
|
get markerState() { return this.#markerState; }
|
124
131
|
get project() { return this.#project; }
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"RecordingWorklet.d.ts","sourceRoot":"","sources":["../src/RecordingWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,GAAG,EAEH,QAAQ,EACR,MAAM,
|
1
|
+
{"version":3,"file":"RecordingWorklet.d.ts","sourceRoot":"","sources":["../src/RecordingWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,GAAG,EAEH,QAAQ,EACR,MAAM,EAGN,YAAY,EACZ,UAAU,EAEV,IAAI,EACP,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAC,KAAK,EAAc,MAAM,qBAAqB,CAAA;AACtD,OAAO,EACH,SAAS,EAET,UAAU,EACV,YAAY,EACZ,iBAAiB,EAEpB,MAAM,0BAA0B,CAAA;AAMjC,qBAAa,gBAAiB,SAAQ,gBAAiB,YAAW,UAAU,EAAE,YAAY;;IAGtF,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAkB;gBAa/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM;IA2BvF,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;IAE3C,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IAEvB,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IAE/B,IAAI,cAAc,IAAI,GAAG,CAA6C;IACtE,IAAI,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAoB;IACjD,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAA6E;IACvG,IAAI,KAAK,IAAI,iBAAiB,CAAqB;IAEnD,UAAU,IAAI,IAAI;IAElB,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,YAAY;IAQ9D,SAAS,IAAI,IAAI;IAMjB,QAAQ,IAAI,MAAM;CAyCrB"}
|
package/dist/RecordingWorklet.js
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
import { ByteArrayInput, Notifier, Option, Progress, Terminable, Terminator, UUID } from "@opendaw/lib-std";
|
1
|
+
import { ByteArrayInput, Notifier, Option, panic, Progress, Terminable, Terminator, UUID } from "@opendaw/lib-std";
|
2
2
|
import { BPMTools } from "@opendaw/lib-dsp";
|
3
3
|
import { SamplePeaks } from "@opendaw/lib-fusion";
|
4
4
|
import { mergeChunkPlanes, RingBuffer } from "@opendaw/studio-adapters";
|
5
|
-
import { SampleStorage } from "./samples
|
5
|
+
import { SampleStorage } from "./samples";
|
6
6
|
import { RenderQuantum } from "./RenderQuantum";
|
7
7
|
import { Workers } from "./Workers";
|
8
8
|
import { PeaksWriter } from "./PeaksWriter";
|
@@ -68,7 +68,7 @@ export class RecordingWorklet extends AudioWorkletNode {
|
|
68
68
|
this.#isRecording = false;
|
69
69
|
this.#reader.stop();
|
70
70
|
if (this.#output.length === 0) {
|
71
|
-
return;
|
71
|
+
return panic("No recording data available");
|
72
72
|
}
|
73
73
|
const totalSamples = this.#limitSamples;
|
74
74
|
const sample_rate = this.context.sampleRate;
|
@@ -88,10 +88,17 @@ export class RecordingWorklet extends AudioWorkletNode {
|
|
88
88
|
this.#peaks = Option.wrap(SamplePeaks.from(new ByteArrayInput(peaks)));
|
89
89
|
const bpm = BPMTools.detect(frames[0], sample_rate);
|
90
90
|
const duration = totalSamples / sample_rate;
|
91
|
-
const meta = { name: "Recording", bpm, sample_rate, duration };
|
92
|
-
|
91
|
+
const meta = { name: "Recording", bpm, sample_rate, duration, origin: "recording" };
|
92
|
+
const sample = {
|
93
|
+
uuid: this.uuid,
|
94
|
+
audio: audioData,
|
95
|
+
peaks: peaks,
|
96
|
+
meta
|
97
|
+
};
|
98
|
+
await SampleStorage.saveSample(sample);
|
93
99
|
this.#setState({ type: "loaded" });
|
94
100
|
this.terminate();
|
101
|
+
return sample;
|
95
102
|
}
|
96
103
|
#setState(value) {
|
97
104
|
this.#state = value;
|
@@ -38,28 +38,28 @@ export class CaptureMidi extends Capture {
|
|
38
38
|
notify(signal) { this.#notifier.notify(signal); }
|
39
39
|
subscribeNotes(observer) { return this.#notifier.subscribe(observer); }
|
40
40
|
get label() {
|
41
|
-
return MidiDevices.get().mapOr(
|
41
|
+
return MidiDevices.get().mapOr(() => this.deviceId.getValue().match({
|
42
42
|
none: () => this.armed.getValue() ? this.#filterChannel.match({
|
43
43
|
none: () => `Listening to all devices`,
|
44
44
|
some: channel => `Listening to all devices on channel '${channel}'`
|
45
45
|
}) : "Arm to listen to MIDI device...",
|
46
46
|
some: id => {
|
47
|
-
const device =
|
48
|
-
if (
|
47
|
+
const device = MidiDevices.findInputDeviceById(id);
|
48
|
+
if (device.isEmpty()) {
|
49
49
|
return `⚠️ Could not find device with id '${id}'`;
|
50
50
|
}
|
51
|
-
const deviceName = device.name ?? "Unknown device";
|
51
|
+
const deviceName = device.unwrapOrUndefined()?.name ?? "Unknown device";
|
52
52
|
return this.#filterChannel.match({
|
53
53
|
none: () => `Listening to ${deviceName}`,
|
54
|
-
some: channel => `Listening to ${deviceName} on channel
|
54
|
+
some: channel => `Listening to ${deviceName} on channel #${channel + 1}`
|
55
55
|
});
|
56
56
|
}
|
57
57
|
}), "MIDI not available");
|
58
58
|
}
|
59
59
|
get deviceLabel() {
|
60
60
|
return this.deviceId.getValue()
|
61
|
-
.flatMap(deviceId => MidiDevices.
|
62
|
-
.map(
|
61
|
+
.flatMap(deviceId => MidiDevices.findInputDeviceById(deviceId)
|
62
|
+
.map(device => device.name));
|
63
63
|
}
|
64
64
|
async prepareRecording() {
|
65
65
|
if (MidiDevices.get().isEmpty()) {
|
@@ -70,7 +70,7 @@ export class CaptureMidi extends Capture {
|
|
70
70
|
return Errors.warn("MIDI not available");
|
71
71
|
}
|
72
72
|
}
|
73
|
-
const optInputs = MidiDevices.
|
73
|
+
const optInputs = MidiDevices.inputDevices();
|
74
74
|
if (optInputs.isEmpty()) {
|
75
75
|
return Errors.warn("MIDI not available");
|
76
76
|
}
|
@@ -87,16 +87,16 @@ export class CaptureMidi extends Capture {
|
|
87
87
|
}
|
88
88
|
}
|
89
89
|
startRecording() {
|
90
|
-
const
|
91
|
-
assert(
|
90
|
+
const availableInputDevices = MidiDevices.inputDevices();
|
91
|
+
assert(availableInputDevices.nonEmpty(), "No MIDI input devices found");
|
92
92
|
return RecordMidi.start({ notifier: this.#notifier, project: this.manager.project, capture: this });
|
93
93
|
}
|
94
94
|
async #updateStream() {
|
95
95
|
if (MidiDevices.get().isEmpty()) {
|
96
96
|
await MidiDevices.requestPermission();
|
97
97
|
}
|
98
|
-
const
|
99
|
-
const available =
|
98
|
+
const availableInputDevices = MidiDevices.inputDevices();
|
99
|
+
const available = availableInputDevices.unwrap();
|
100
100
|
const capturing = this.deviceId.getValue().match({
|
101
101
|
none: () => available,
|
102
102
|
some: id => available.filter(device => id === device.id)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Terminable } from "@opendaw/lib-std";
|
2
|
-
import {
|
2
|
+
import { SampleLoaderManager } from "@opendaw/studio-adapters";
|
3
3
|
import { Project } from "../project/Project";
|
4
4
|
import { RecordingWorklet } from "../RecordingWorklet";
|
5
5
|
import { Capture } from "./Capture";
|
@@ -7,7 +7,7 @@ export declare namespace RecordAudio {
|
|
7
7
|
type RecordAudioContext = {
|
8
8
|
recordingWorklet: RecordingWorklet;
|
9
9
|
mediaStream: MediaStream;
|
10
|
-
sampleManager:
|
10
|
+
sampleManager: SampleLoaderManager;
|
11
11
|
audioContext: AudioContext;
|
12
12
|
project: Project;
|
13
13
|
capture: Capture;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGvG,OAAO,EAAC,
|
1
|
+
{"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGvG,OAAO,EAAC,mBAAmB,EAAY,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAIjC,yBAAiB,WAAW,CAAC;IACzB,KAAK,kBAAkB,GAAG;QACtB,gBAAgB,EAAE,gBAAgB,CAAA;QAClC,WAAW,EAAE,WAAW,CAAA;QACxB,aAAa,EAAE,mBAAmB,CAAA;QAClC,YAAY,EAAE,YAAY,CAAA;QAC1B,OAAO,EAAE,OAAO,CAAA;QAChB,OAAO,EAAE,OAAO,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;KACjB,CAAA;IAED,MAAM,CAAC,MAAM,KAAK,GACd,0FAAwF,kBAAkB,KACxG,UAqEL,CAAA;;CACJ"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"CloudAuthManager.d.ts","sourceRoot":"","sources":["../../src/clouds/CloudAuthManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAI3C,qBAAa,gBAAgB;;IACzB,MAAM,CAAC,MAAM,IAAI,gBAAgB;IAqBjC,QAAQ,CAAC,EAAE,SAAyB;IAIpC,OAAO;IAED,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;
|
1
|
+
{"version":3,"file":"CloudAuthManager.d.ts","sourceRoot":"","sources":["../../src/clouds/CloudAuthManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAI3C,qBAAa,gBAAgB;;IACzB,MAAM,CAAC,MAAM,IAAI,gBAAgB;IAqBjC,QAAQ,CAAC,EAAE,SAAyB;IAIpC,OAAO;IAED,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;CAuLjE"}
|
@@ -71,10 +71,15 @@ export class CloudAuthManager {
|
|
71
71
|
message: "Please wait for authentication...",
|
72
72
|
cancel: () => reject("cancelled")
|
73
73
|
});
|
74
|
+
let handled = false;
|
74
75
|
channel.onmessage = async (event) => {
|
75
76
|
const data = asDefined(event.data, "No data");
|
76
77
|
console.debug("[CloudAuth] Received via BroadcastChannel:", this.id, data);
|
77
78
|
if (data.type === "auth-callback" && isDefined(data.code)) {
|
79
|
+
if (handled) {
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
handled = true;
|
78
83
|
console.debug("[CloudAuth] Processing code from BroadcastChannel...", data.type, data.code);
|
79
84
|
try {
|
80
85
|
const tokenParams = new URLSearchParams({
|
@@ -108,8 +113,11 @@ export class CloudAuthManager {
|
|
108
113
|
}
|
109
114
|
}
|
110
115
|
else if (data.type === "closed") {
|
111
|
-
|
112
|
-
|
116
|
+
// Only reject if we did not already start handling a code
|
117
|
+
if (!handled) {
|
118
|
+
console.debug("[CloudAuth] Callback window closed before code received");
|
119
|
+
reject(null);
|
120
|
+
}
|
113
121
|
}
|
114
122
|
};
|
115
123
|
return promise.finally(() => {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"CloudBackupSamples.d.ts","sourceRoot":"","sources":["../../src/clouds/CloudBackupSamples.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,SAAS,EAAE,QAAQ,EAAmB,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAGlG,OAAO,EAAY,MAAM,EAAC,MAAM,0BAA0B,CAAA;AAG1D,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAM3C,qBAAa,kBAAkB;;IAC3B,MAAM,CAAC,QAAQ,CAAC,UAAU,aAAY;IACtC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAAkC;IACnE,MAAM,CAAC,QAAQ,CAAC,eAAe,GAAI,aAAW,MAAM,EAAE,aAAW,MAAM,aAAY;IAEnF,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM;WAE5B,KAAK,CAAC,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC;IAgBzC,OAAO;
|
1
|
+
{"version":3,"file":"CloudBackupSamples.d.ts","sourceRoot":"","sources":["../../src/clouds/CloudBackupSamples.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,SAAS,EAAE,QAAQ,EAAmB,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAGlG,OAAO,EAAY,MAAM,EAAC,MAAM,0BAA0B,CAAA;AAG1D,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAM3C,qBAAa,kBAAkB;;IAC3B,MAAM,CAAC,QAAQ,CAAC,UAAU,aAAY;IACtC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAAkC;IACnE,MAAM,CAAC,QAAQ,CAAC,eAAe,GAAI,aAAW,MAAM,EAAE,aAAW,MAAM,aAAY;IAEnF,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM;WAE5B,KAAK,CAAC,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC;IAgBzC,OAAO;CA2HV"}
|
@@ -114,7 +114,12 @@ export class CloudBackupSamples {
|
|
114
114
|
};
|
115
115
|
const shifts = SamplePeaks.findBestFit(audioData.numberOfFrames);
|
116
116
|
const peaks = await Workers.Peak.generateAsync(Progress.Empty, shifts, audioData.frames, audioData.numberOfFrames, audioData.numberOfChannels);
|
117
|
-
await SampleStorage.saveSample(
|
117
|
+
await SampleStorage.saveSample({
|
118
|
+
uuid: UUID.parse(sample.uuid),
|
119
|
+
audio: audioData,
|
120
|
+
peaks: peaks,
|
121
|
+
meta: sample
|
122
|
+
});
|
118
123
|
return sample;
|
119
124
|
}));
|
120
125
|
this.#log("Download samples complete.");
|
package/dist/index.d.ts
CHANGED
@@ -18,13 +18,7 @@ export * from "./project/ProjectPaths";
|
|
18
18
|
export * from "./project/ProjectProfile";
|
19
19
|
export * from "./project/ProjectSignals";
|
20
20
|
export * from "./project/ProjectStorage";
|
21
|
-
export * from "./samples/
|
22
|
-
export * from "./samples/MainThreadSampleLoader";
|
23
|
-
export * from "./samples/MainThreadSampleManager";
|
24
|
-
export * from "./samples/OpenSampleAPI";
|
25
|
-
export * from "./samples/SampleAPI";
|
26
|
-
export * from "./samples/SampleImporter";
|
27
|
-
export * from "./samples/SampleProvider";
|
21
|
+
export * from "./samples/index";
|
28
22
|
export * from "./sync-log/Commit";
|
29
23
|
export * from "./sync-log/SyncLogReader";
|
30
24
|
export * from "./sync-log/SyncLogWriter";
|
package/dist/index.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,+BAA+B,CAAA;AAE7C,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AAExC,cAAc,
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,+BAA+B,CAAA;AAE7C,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AAExC,cAAc,iBAAiB,CAAA;AAE/B,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AAExC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AAEpC,cAAc,oBAAoB,CAAA;AAElC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA;AACjC,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,yBAAyB,CAAA;AACvC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA"}
|
package/dist/index.js
CHANGED
@@ -18,13 +18,7 @@ export * from "./project/ProjectPaths";
|
|
18
18
|
export * from "./project/ProjectProfile";
|
19
19
|
export * from "./project/ProjectSignals";
|
20
20
|
export * from "./project/ProjectStorage";
|
21
|
-
export * from "./samples/
|
22
|
-
export * from "./samples/MainThreadSampleLoader";
|
23
|
-
export * from "./samples/MainThreadSampleManager";
|
24
|
-
export * from "./samples/OpenSampleAPI";
|
25
|
-
export * from "./samples/SampleAPI";
|
26
|
-
export * from "./samples/SampleImporter";
|
27
|
-
export * from "./samples/SampleProvider";
|
21
|
+
export * from "./samples/index";
|
28
22
|
export * from "./sync-log/Commit";
|
29
23
|
export * from "./sync-log/SyncLogReader";
|
30
24
|
export * from "./sync-log/SyncLogWriter";
|
@@ -3,7 +3,7 @@ import { Events } from "@opendaw/lib-dom";
|
|
3
3
|
import { MidiData } from "@opendaw/lib-midi";
|
4
4
|
export class MIDIMessageSubscriber {
|
5
5
|
static subscribeMessageEvents(access, observer, channel) {
|
6
|
-
const
|
6
|
+
const listenToMIDIMessages = (input) => isDefined(channel)
|
7
7
|
? Events.subscribe(input, "midimessage", (event) => {
|
8
8
|
if (event.data === null || MidiData.readChannel(event.data) !== channel) {
|
9
9
|
return;
|
@@ -11,7 +11,7 @@ export class MIDIMessageSubscriber {
|
|
11
11
|
observer(event);
|
12
12
|
}) : Events.subscribe(input, "midimessage", observer);
|
13
13
|
const connections = Array.from(access.inputs.values())
|
14
|
-
.map(input => ([input,
|
14
|
+
.map(input => ([input, listenToMIDIMessages(input)]));
|
15
15
|
const stateSubscription = Events.subscribe(access, "statechange", (event) => {
|
16
16
|
const port = event.port;
|
17
17
|
if (!isInstanceOf(port, MIDIInput)) {
|
@@ -19,14 +19,14 @@ export class MIDIMessageSubscriber {
|
|
19
19
|
}
|
20
20
|
for (const [input, subscription] of connections) {
|
21
21
|
if (input === port) {
|
22
|
-
// Well, this
|
22
|
+
// Well, this seems odd, but if you start listening to a midi-input initially,
|
23
23
|
// it will change its state to 'connected', so we clean up the first old subscriptions.
|
24
24
|
subscription.terminate();
|
25
25
|
break;
|
26
26
|
}
|
27
27
|
}
|
28
28
|
if (port.state === "connected") {
|
29
|
-
connections.push([port,
|
29
|
+
connections.push([port, listenToMIDIMessages(port)]);
|
30
30
|
}
|
31
31
|
});
|
32
32
|
return {
|
@@ -1,12 +1,16 @@
|
|
1
1
|
import { byte, MutableObservableValue, ObservableOption, Observer, Option, Subscription } from "@opendaw/lib-std";
|
2
|
+
import { SoftwareMIDIInput } from "./SoftwareMIDIInput";
|
2
3
|
export declare class MidiDevices {
|
3
4
|
#private;
|
4
5
|
static canRequestMidiAccess(): boolean;
|
6
|
+
static readonly softwareMIDIInput: SoftwareMIDIInput;
|
5
7
|
static requestPermission(): Promise<undefined>;
|
6
8
|
static get(): ObservableOption<MIDIAccess>;
|
7
9
|
static subscribeMessageEvents(observer: Observer<MIDIMessageEvent>, channel?: byte): Subscription;
|
8
|
-
static
|
9
|
-
static
|
10
|
+
static inputDevices(): Option<ReadonlyArray<MIDIInput>>;
|
11
|
+
static findInputDeviceById(id: string): Option<MIDIInput>;
|
12
|
+
static externalInputDevices(): Option<ReadonlyArray<MIDIInput>>;
|
13
|
+
static externalOutputDevices(): Option<ReadonlyArray<MIDIOutput>>;
|
10
14
|
static panic(): void;
|
11
15
|
static available(): MutableObservableValue<boolean>;
|
12
16
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"MidiDevices.d.ts","sourceRoot":"","sources":["../../src/midi/MidiDevices.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,IAAI,EAIJ,sBAAsB,EAEtB,gBAAgB,EAEhB,QAAQ,EACR,MAAM,EACN,YAAY,EAEf,MAAM,kBAAkB,CAAA;
|
1
|
+
{"version":3,"file":"MidiDevices.d.ts","sourceRoot":"","sources":["../../src/midi/MidiDevices.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,IAAI,EAIJ,sBAAsB,EAEtB,gBAAgB,EAEhB,QAAQ,EACR,MAAM,EACN,YAAY,EAEf,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAC,iBAAiB,EAAC,MAAM,qBAAqB,CAAA;AAErD,qBAAa,WAAW;;IACpB,MAAM,CAAC,oBAAoB,IAAI,OAAO;IAEtC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAA0B;WAIjE,iBAAiB;IAiB9B,MAAM,CAAC,GAAG,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAE1C,MAAM,CAAC,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI,GAAG,YAAY;IAWjG,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAKvD,MAAM,CAAC,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC;IAIzD,MAAM,CAAC,oBAAoB,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAI/D,MAAM,CAAC,qBAAqB,IAAI,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAIjE,MAAM,CAAC,KAAK,IAAI,IAAI;IAkBpB,MAAM,CAAC,SAAS,IAAI,sBAAsB,CAAC,OAAO,CAAC;CAqCtD"}
|
package/dist/midi/MidiDevices.js
CHANGED
@@ -11,8 +11,10 @@ import { Errors, Lazy, MutableObservableOption, MutableObservableValue, Notifier
|
|
11
11
|
import { MidiData } from "@opendaw/lib-midi";
|
12
12
|
import { Promises } from "@opendaw/lib-runtime";
|
13
13
|
import { MIDIMessageSubscriber } from "./MIDIMessageSubscriber";
|
14
|
+
import { SoftwareMIDIInput } from "./SoftwareMIDIInput";
|
14
15
|
export class MidiDevices {
|
15
16
|
static canRequestMidiAccess() { return "requestMIDIAccess" in navigator; }
|
17
|
+
static softwareMIDIInput = new SoftwareMIDIInput();
|
16
18
|
static #memoizedRequest = Promises.memoizeAsync(() => navigator.requestMIDIAccess({ sysex: false }));
|
17
19
|
static async requestPermission() {
|
18
20
|
if (this.canRequestMidiAccess()) {
|
@@ -41,10 +43,17 @@ export class MidiDevices {
|
|
41
43
|
some: midi => MIDIMessageSubscriber.subscribeMessageEvents(midi, observer, channel)
|
42
44
|
});
|
43
45
|
}
|
44
|
-
static
|
46
|
+
static inputDevices() {
|
47
|
+
return this.externalInputDevices()
|
48
|
+
.map((inputs) => Array.from(inputs.values()).concat(this.softwareMIDIInput));
|
49
|
+
}
|
50
|
+
static findInputDeviceById(id) {
|
51
|
+
return this.inputDevices().map(inputs => inputs.find(input => input.id === id));
|
52
|
+
}
|
53
|
+
static externalInputDevices() {
|
45
54
|
return this.get().map(({ inputs }) => Array.from(inputs.values()));
|
46
55
|
}
|
47
|
-
static
|
56
|
+
static externalOutputDevices() {
|
48
57
|
return this.get().map(({ outputs }) => Array.from(outputs.values()));
|
49
58
|
}
|
50
59
|
static panic() {
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { byte, Terminable, unitValue } from "@opendaw/lib-std";
|
2
|
+
export declare class SoftwareMIDIInput implements MIDIInput, Terminable {
|
3
|
+
#private;
|
4
|
+
readonly manufacturer: string | null;
|
5
|
+
readonly connection: MIDIPortConnectionState;
|
6
|
+
readonly id: string;
|
7
|
+
readonly name: string | null;
|
8
|
+
readonly state: MIDIPortDeviceState;
|
9
|
+
readonly type: MIDIPortType;
|
10
|
+
readonly version: string | null;
|
11
|
+
onmidimessage: ((this: MIDIInput, ev: MIDIMessageEvent) => any) | null;
|
12
|
+
onstatechange: ((this: MIDIPort, ev: MIDIConnectionEvent) => any) | null;
|
13
|
+
channel: byte;
|
14
|
+
constructor();
|
15
|
+
sendNoteOnEvent(note: byte, velocity?: unitValue): void;
|
16
|
+
sendNoteOffEvent(note: byte): void;
|
17
|
+
sendMIDIMessageData(data: Uint8Array): void;
|
18
|
+
open(): Promise<MIDIPort>;
|
19
|
+
close(): Promise<MIDIPort>;
|
20
|
+
addEventListener<K extends keyof MIDIInputEventMap>(type: K, listener: (this: MIDIInput, ev: MIDIInputEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
21
|
+
addEventListener<K extends keyof MIDIPortEventMap>(type: K, listener: (this: MIDIPort, ev: MIDIPortEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
22
|
+
dispatchEvent(event: MIDIMessageEvent): boolean;
|
23
|
+
removeEventListener<K extends keyof MIDIInputEventMap>(type: K, listener: (this: MIDIInput, ev: MIDIInputEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
24
|
+
removeEventListener<K extends keyof MIDIPortEventMap>(type: K, listener: (this: MIDIPort, ev: MIDIPortEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
25
|
+
terminate(): void;
|
26
|
+
}
|
27
|
+
//# sourceMappingURL=SoftwareMIDIInput.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"SoftwareMIDIInput.d.ts","sourceRoot":"","sources":["../../src/midi/SoftwareMIDIInput.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAsB,UAAU,EAAE,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAGhF,qBAAa,iBAAkB,YAAW,SAAS,EAAE,UAAU;;IAC3D,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAY;IAChD,QAAQ,CAAC,UAAU,EAAE,uBAAuB,CAAS;IACrD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAwB;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAsB;IAClD,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAc;IACjD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAU;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAU;IAIzC,aAAa,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,gBAAgB,KAAK,GAAG,CAAC,GAAG,IAAI,CAAO;IAC7E,aAAa,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,mBAAmB,KAAK,GAAG,CAAC,GAAG,IAAI,CAAO;IAC/E,OAAO,EAAE,IAAI,CAAI;;IAIjB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAE,SAAe,GAAG,IAAI;IAK5D,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAIlC,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAK3C,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC;IACzB,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC;IAC1B,gBAAgB,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAAG,IAAI;IAC7K,gBAAgB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAAG,IAAI;IAI1K,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO;IAI/C,mBAAmB,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GAAG,IAAI;IAC7K,mBAAmB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GAAG,IAAI;IAK1K,SAAS,IAAI,IAAI;CAGpB"}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { clamp, safeExecute } from "@opendaw/lib-std";
|
2
|
+
import { MidiData } from "@opendaw/lib-midi";
|
3
|
+
export class SoftwareMIDIInput {
|
4
|
+
manufacturer = "openDAW";
|
5
|
+
connection = "open";
|
6
|
+
id = "software-midi-input";
|
7
|
+
name = "Software Keyboard";
|
8
|
+
state = "connected";
|
9
|
+
type = "input";
|
10
|
+
version = "1.0.0";
|
11
|
+
#dispatcher;
|
12
|
+
onmidimessage = null;
|
13
|
+
onstatechange = null; // has no effect. always on.
|
14
|
+
channel = 0; // 0...16
|
15
|
+
constructor() { this.#dispatcher = new EventTarget(); }
|
16
|
+
sendNoteOnEvent(note, velocity = 1.0) {
|
17
|
+
const velocityByte = Math.round(clamp(velocity, 0, 1) * 127);
|
18
|
+
this.sendMIDIMessageData(MidiData.noteOn(this.channel, note, velocityByte));
|
19
|
+
}
|
20
|
+
sendNoteOffEvent(note) {
|
21
|
+
this.sendMIDIMessageData(MidiData.noteOff(this.channel, note));
|
22
|
+
}
|
23
|
+
sendMIDIMessageData(data) {
|
24
|
+
const eventInit = { data };
|
25
|
+
this.dispatchEvent(new MessageEvent("midimessage", eventInit));
|
26
|
+
}
|
27
|
+
open() { return Promise.resolve(this); }
|
28
|
+
close() { return Promise.resolve(this); }
|
29
|
+
addEventListener(type, listener, options) {
|
30
|
+
this.#dispatcher.addEventListener(type, listener, options);
|
31
|
+
}
|
32
|
+
dispatchEvent(event) {
|
33
|
+
safeExecute(this.onmidimessage, event);
|
34
|
+
return this.#dispatcher.dispatchEvent(event);
|
35
|
+
}
|
36
|
+
removeEventListener(type, listener, options) {
|
37
|
+
this.#dispatcher.removeEventListener(type, listener, options);
|
38
|
+
}
|
39
|
+
terminate() {
|
40
|
+
this.#dispatcher.dispatchEvent(new Event("close"));
|
41
|
+
}
|
42
|
+
}
|