@opendaw/studio-core 0.0.38 → 0.0.40
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/AudioOfflineRenderer.d.ts.map +1 -1
- package/dist/AudioOfflineRenderer.js +4 -1
- package/dist/InstrumentFactories.d.ts.map +1 -1
- package/dist/InstrumentFactories.js +15 -12
- package/dist/capture/CaptureMidi.d.ts.map +1 -1
- package/dist/capture/CaptureMidi.js +9 -16
- package/dist/capture/RecordAudio.d.ts.map +1 -1
- package/dist/capture/RecordAudio.js +2 -1
- package/dist/capture/Recording.d.ts.map +1 -1
- package/dist/capture/Recording.js +1 -2
- package/dist/clouds/CloudAuthManager.js +2 -2
- package/dist/dawproject/DawProjectImport.d.ts +2 -2
- package/dist/dawproject/DawProjectImport.d.ts.map +1 -1
- package/dist/dawproject/DawProjectImport.js +4 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/midi/MidiDevices.d.ts +1 -1
- package/dist/midi/MidiDevices.d.ts.map +1 -1
- package/dist/midi/MidiDevices.js +3 -3
- package/dist/midi/SoftwareMIDIInput.d.ts +16 -9
- package/dist/midi/SoftwareMIDIInput.d.ts.map +1 -1
- package/dist/midi/SoftwareMIDIInput.js +60 -18
- package/dist/processors.js +3 -3
- package/dist/processors.js.map +4 -4
- package/dist/project/Project.d.ts +3 -3
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +5 -4
- package/dist/project/ProjectMigration.d.ts +2 -2
- package/dist/project/ProjectMigration.d.ts.map +1 -1
- package/dist/project/ProjectMigration.js +0 -1
- package/dist/project/ProjectValidation.d.ts +5 -0
- package/dist/project/ProjectValidation.d.ts.map +1 -0
- package/dist/project/ProjectValidation.js +50 -0
- package/dist/ui/TimelineRange.d.ts +3 -1
- package/dist/ui/TimelineRange.d.ts.map +1 -1
- package/dist/ui/TimelineRange.js +7 -5
- package/dist/utils/AutofitUtils.d.ts +7 -0
- package/dist/utils/AutofitUtils.d.ts.map +1 -0
- package/dist/utils/AutofitUtils.js +78 -0
- package/dist/workers-main.js +2 -2
- package/dist/workers-main.js.map +3 -3
- package/dist/yjs/YMapper.d.ts +9 -0
- package/dist/yjs/YMapper.d.ts.map +1 -0
- package/dist/yjs/YMapper.js +45 -0
- package/dist/yjs/YService.d.ts +7 -0
- package/dist/yjs/YService.d.ts.map +1 -0
- package/dist/yjs/YService.js +69 -0
- package/dist/yjs/YSync.d.ts +17 -0
- package/dist/yjs/YSync.d.ts.map +1 -0
- package/dist/yjs/YSync.js +195 -0
- package/package.json +15 -15
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"AudioOfflineRenderer.d.ts","sourceRoot":"","sources":["../src/AudioOfflineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,GAAG,EAAE,MAAM,EAAmC,MAAM,kBAAkB,CAAA;AAI9G,OAAO,EAAC,wBAAwB,EAAC,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAA;AAIjD,yBAAiB,oBAAoB,CAAC;IAC3B,MAAM,KAAK,GAAU,QAAQ,OAAO,EACf,MAAM,WAAW,EACjB,wBAAwB,MAAM,CAAC,wBAAwB,CAAC,EACxD,aAAY,GAAY,KAAG,OAAO,CAAC,IAAI,
|
1
|
+
{"version":3,"file":"AudioOfflineRenderer.d.ts","sourceRoot":"","sources":["../src/AudioOfflineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,GAAG,EAAE,MAAM,EAAmC,MAAM,kBAAkB,CAAA;AAI9G,OAAO,EAAC,wBAAwB,EAAC,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAA;AAIjD,yBAAiB,oBAAoB,CAAC;IAC3B,MAAM,KAAK,GAAU,QAAQ,OAAO,EACf,MAAM,WAAW,EACjB,wBAAwB,MAAM,CAAC,wBAAwB,CAAC,EACxD,aAAY,GAAY,KAAG,OAAO,CAAC,IAAI,CAgClE,CAAA;CAiDJ"}
|
@@ -8,8 +8,11 @@ import { AudioWorklets } from "./AudioWorklets";
|
|
8
8
|
export var AudioOfflineRenderer;
|
9
9
|
(function (AudioOfflineRenderer) {
|
10
10
|
AudioOfflineRenderer.start = async (source, meta, optExportConfiguration, sampleRate = 48_000) => {
|
11
|
-
const project = source.copy();
|
12
11
|
const numStems = ExportStemsConfiguration.countStems(optExportConfiguration);
|
12
|
+
if (numStems === 0) {
|
13
|
+
return panic("Nothing to export");
|
14
|
+
}
|
15
|
+
const project = source.copy();
|
13
16
|
const progress = new DefaultObservableValue(0.0);
|
14
17
|
const dialog = RuntimeNotifier.progress({ headline: "Rendering...", progress });
|
15
18
|
project.boxGraph.beginTransaction();
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"InstrumentFactories.d.ts","sourceRoot":"","sources":["../src/InstrumentFactories.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,iBAAiB,EAAC,MAAM,qBAAqB,CAAA;AAGrD,yBAAiB,mBAAmB,CAAC;IAC1B,MAAM,IAAI,EAAE,iBAelB,CAAA;IAEM,MAAM,IAAI,EAAE,
|
1
|
+
{"version":3,"file":"InstrumentFactories.d.ts","sourceRoot":"","sources":["../src/InstrumentFactories.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,iBAAiB,EAAC,MAAM,qBAAqB,CAAA;AAGrD,yBAAiB,mBAAmB,CAAC;IAC1B,MAAM,IAAI,EAAE,iBAelB,CAAA;IAEM,MAAM,IAAI,EAAE,iBAoBlB,CAAA;IAEM,MAAM,SAAS,EAAE,iBAkCvB,CAAA;IAEM,MAAM,YAAY,EAAE,iBAiB1B,CAAA;IAEM,MAAM,KAAK;;;;;KAAwC,CAAA;IAC1D,KAAY,IAAI,GAAG,MAAM,OAAO,KAAK,CAAA;CAQxC"}
|
@@ -26,9 +26,11 @@ export var InstrumentFactories;
|
|
26
26
|
trackType: TrackType.Notes,
|
27
27
|
create: (boxGraph, host, name, icon) => {
|
28
28
|
const fileUUID = UUID.parse("c1678daa-4a47-4cba-b88f-4f4e384663c3");
|
29
|
+
const fileDuration = 5.340;
|
29
30
|
const audioFileBox = boxGraph.findBox(fileUUID)
|
30
31
|
.unwrapOrElse(() => AudioFileBox.create(boxGraph, fileUUID, box => {
|
31
32
|
box.fileName.setValue("Rhode");
|
33
|
+
box.endInSeconds.setValue(fileDuration);
|
32
34
|
}));
|
33
35
|
return NanoDeviceBox.create(boxGraph, UUID.generate(), box => {
|
34
36
|
box.label.setValue(name);
|
@@ -50,17 +52,17 @@ export var InstrumentFactories;
|
|
50
52
|
box.host.refer(host);
|
51
53
|
});
|
52
54
|
const files = [
|
53
|
-
useFile(boxGraph, UUID.parse("8bb2c6e8-9a6d-4d32-b7ec-1263594ef367"), "909 Bassdrum"),
|
54
|
-
useFile(boxGraph, UUID.parse("0017fa18-a5eb-4d9d-b6f2-e2ddd30a3010"), "909 Snare"),
|
55
|
-
useFile(boxGraph, UUID.parse("28d14cb9-1dc6-4193-9dd7-4e881f25f520"), "909 Low Tom"),
|
56
|
-
useFile(boxGraph, UUID.parse("21f92306-d6e7-446c-a34b-b79620acfefc"), "909 Mid Tom"),
|
57
|
-
useFile(boxGraph, UUID.parse("ad503883-8a72-46ab-a05b-a84149953e17"), "909 High Tom"),
|
58
|
-
useFile(boxGraph, UUID.parse("cfee850b-7658-4d08-9e3b-79d196188504"), "909 Rimshot"),
|
59
|
-
useFile(boxGraph, UUID.parse("32a6f36f-06eb-4b84-bb57-5f51103eb9e6"), "909 Clap"),
|
60
|
-
useFile(boxGraph, UUID.parse("e0ac4b39-23fb-4a56-841d-c9e0ff440cab"), "909 Closed Hat"),
|
61
|
-
useFile(boxGraph, UUID.parse("51c5eea4-391c-4743-896a-859692ec1105"), "909 Open Hat"),
|
62
|
-
useFile(boxGraph, UUID.parse("42a56ff6-89b6-4f2e-8a66-5a41d316f4cb"), "909 Crash"),
|
63
|
-
useFile(boxGraph, UUID.parse("87cde966-b799-4efc-a994-069e703478d3"), "909 Ride")
|
55
|
+
useFile(boxGraph, UUID.parse("8bb2c6e8-9a6d-4d32-b7ec-1263594ef367"), "909 Bassdrum", 0.509),
|
56
|
+
useFile(boxGraph, UUID.parse("0017fa18-a5eb-4d9d-b6f2-e2ddd30a3010"), "909 Snare", 0.235),
|
57
|
+
useFile(boxGraph, UUID.parse("28d14cb9-1dc6-4193-9dd7-4e881f25f520"), "909 Low Tom", 0.509),
|
58
|
+
useFile(boxGraph, UUID.parse("21f92306-d6e7-446c-a34b-b79620acfefc"), "909 Mid Tom", 0.385),
|
59
|
+
useFile(boxGraph, UUID.parse("ad503883-8a72-46ab-a05b-a84149953e17"), "909 High Tom", 0.511),
|
60
|
+
useFile(boxGraph, UUID.parse("cfee850b-7658-4d08-9e3b-79d196188504"), "909 Rimshot", 0.150),
|
61
|
+
useFile(boxGraph, UUID.parse("32a6f36f-06eb-4b84-bb57-5f51103eb9e6"), "909 Clap", 0.507),
|
62
|
+
useFile(boxGraph, UUID.parse("e0ac4b39-23fb-4a56-841d-c9e0ff440cab"), "909 Closed Hat", 0.154),
|
63
|
+
useFile(boxGraph, UUID.parse("51c5eea4-391c-4743-896a-859692ec1105"), "909 Open Hat", 0.502),
|
64
|
+
useFile(boxGraph, UUID.parse("42a56ff6-89b6-4f2e-8a66-5a41d316f4cb"), "909 Crash", 1.055),
|
65
|
+
useFile(boxGraph, UUID.parse("87cde966-b799-4efc-a994-069e703478d3"), "909 Ride", 1.720)
|
64
66
|
];
|
65
67
|
const samples = files.map((file, index) => PlayfieldSampleBox.create(boxGraph, UUID.generate(), box => {
|
66
68
|
box.device.refer(deviceBox.samples);
|
@@ -90,8 +92,9 @@ export var InstrumentFactories;
|
|
90
92
|
})
|
91
93
|
};
|
92
94
|
InstrumentFactories.Named = { Vaporisateur: InstrumentFactories.Vaporisateur, Playfield: InstrumentFactories.Playfield, Nano: InstrumentFactories.Nano, Tape: InstrumentFactories.Tape };
|
93
|
-
const useFile = (boxGraph, fileUUID, name) => boxGraph.findBox(fileUUID)
|
95
|
+
const useFile = (boxGraph, fileUUID, name, duration) => boxGraph.findBox(fileUUID)
|
94
96
|
.unwrapOrElse(() => AudioFileBox.create(boxGraph, fileUUID, box => {
|
95
97
|
box.fileName.setValue(name);
|
98
|
+
box.endInSeconds.setValue(duration);
|
96
99
|
}));
|
97
100
|
})(InstrumentFactories || (InstrumentFactories = {}));
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"CaptureMidi.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureMidi.ts"],"names":[],"mappings":"AAAA,OAAO,
|
1
|
+
{"version":3,"file":"CaptureMidi.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAOH,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,UAAU,EACb,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAC,YAAY,EAAE,cAAc,EAAC,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAA;AAEnD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAI/C,qBAAa,WAAY,SAAQ,OAAO,CAAC,cAAc,CAAC;;gBAOxC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc;IA+B/F,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAEhC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY;IAE5D,IAAI,KAAK,IAAI,MAAM,CAgBlB;IAED,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAIhC;IAEK,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBvC,cAAc,IAAI,UAAU;CA6C/B"}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { Errors, isDefined, isUndefined, Notifier, Option, Terminable } from "@opendaw/lib-std";
|
2
2
|
import { Events } from "@opendaw/lib-dom";
|
3
3
|
import { MidiData } from "@opendaw/lib-midi";
|
4
4
|
import { Promises } from "@opendaw/lib-runtime";
|
@@ -33,7 +33,7 @@ export class CaptureMidi extends Capture {
|
|
33
33
|
else {
|
34
34
|
this.#stopStream();
|
35
35
|
}
|
36
|
-
}), this.#notifier.subscribe((signal) => manager.project.engine.noteSignal(signal)));
|
36
|
+
}), this.#notifier.subscribe((signal) => manager.project.engine.noteSignal(signal)), Terminable.create(() => this.#stopStream()));
|
37
37
|
}
|
38
38
|
notify(signal) { this.#notifier.notify(signal); }
|
39
39
|
subscribeNotes(observer) { return this.#notifier.subscribe(observer); }
|
@@ -70,11 +70,7 @@ export class CaptureMidi extends Capture {
|
|
70
70
|
return Errors.warn("MIDI not available");
|
71
71
|
}
|
72
72
|
}
|
73
|
-
const
|
74
|
-
if (optInputs.isEmpty()) {
|
75
|
-
return Errors.warn("MIDI not available");
|
76
|
-
}
|
77
|
-
const inputs = optInputs.unwrap();
|
73
|
+
const inputs = MidiDevices.inputDevices();
|
78
74
|
if (inputs.length === 0) {
|
79
75
|
return;
|
80
76
|
}
|
@@ -87,23 +83,20 @@ export class CaptureMidi extends Capture {
|
|
87
83
|
}
|
88
84
|
}
|
89
85
|
startRecording() {
|
90
|
-
const availableInputDevices = MidiDevices.inputDevices();
|
91
|
-
assert(availableInputDevices.nonEmpty(), "No MIDI input devices found");
|
92
86
|
return RecordMidi.start({ notifier: this.#notifier, project: this.manager.project, capture: this });
|
93
87
|
}
|
94
88
|
async #updateStream() {
|
95
|
-
if (MidiDevices.get().isEmpty()) {
|
89
|
+
if (MidiDevices.get().isEmpty() && MidiDevices.canRequestMidiAccess()) {
|
96
90
|
await MidiDevices.requestPermission();
|
97
91
|
}
|
98
|
-
const
|
99
|
-
const
|
100
|
-
|
101
|
-
|
102
|
-
some: id => available.filter(device => id === device.id)
|
92
|
+
const inputs = MidiDevices.inputDevices();
|
93
|
+
const explicit = this.deviceId.getValue().match({
|
94
|
+
none: () => inputs,
|
95
|
+
some: id => inputs.filter(device => id === device.id)
|
103
96
|
});
|
104
97
|
const activeNotes = new Int8Array(128);
|
105
98
|
this.#stream.ifSome(terminable => terminable.terminate());
|
106
|
-
this.#stream = Option.wrap(Terminable.many(...
|
99
|
+
this.#stream = Option.wrap(Terminable.many(...explicit.map(input => Events.subscribe(input, "midimessage", (event) => {
|
107
100
|
const data = event.data;
|
108
101
|
if (isDefined(data) &&
|
109
102
|
this.#filterChannel.mapOr(channel => MidiData.readChannel(data) === channel, true)) {
|
@@ -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,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,
|
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,UAsEL,CAAA;;CACJ"}
|
@@ -48,8 +48,9 @@ export var RecordAudio;
|
|
48
48
|
recordingWorklet.terminate();
|
49
49
|
}
|
50
50
|
else {
|
51
|
-
const { regionBox: { duration } } = recordingData.unwrap("No recording data available");
|
51
|
+
const { regionBox: { duration }, fileBox } = recordingData.unwrap("No recording data available");
|
52
52
|
recordingWorklet.limit(PPQN.pulsesToSamples(duration.getValue(), bpm, sampleRate) | 0);
|
53
|
+
fileBox.endInSeconds.setValue(recordingWorklet.numberOfFrames / sampleRate);
|
53
54
|
}
|
54
55
|
}), engine.position.catchupAndSubscribe(owner => {
|
55
56
|
if (!engine.isRecording.getValue()) {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"Recording.d.ts","sourceRoot":"","sources":["../../src/capture/Recording.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,UAAU,EAAa,MAAM,kBAAkB,CAAA;AAK7F,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAE1C,qBAAa,SAAS;;IAClB,MAAM,KAAK,WAAW,IAAI,OAAO,CAA2B;WAE/C,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;
|
1
|
+
{"version":3,"file":"Recording.d.ts","sourceRoot":"","sources":["../../src/capture/Recording.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,UAAU,EAAa,MAAM,kBAAkB,CAAA;AAK7F,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAE1C,qBAAa,SAAS;;IAClB,MAAM,KAAK,WAAW,IAAI,OAAO,CAA2B;WAE/C,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IA6D3E,OAAO;CACV"}
|
@@ -31,8 +31,7 @@ export class Recording {
|
|
31
31
|
if (isRecording.getValue() || isCountingIn.getValue()) {
|
32
32
|
return;
|
33
33
|
}
|
34
|
-
editing.
|
35
|
-
terminator.terminate();
|
34
|
+
editing.modify(() => terminator.terminate()); // finalizes recording
|
36
35
|
this.#isRecording = false;
|
37
36
|
};
|
38
37
|
terminator.ownAll(engine.isRecording.subscribe(stop), engine.isCountingIn.subscribe(stop), Terminable.create(() => Recording.#instance = Option.None));
|
@@ -130,7 +130,7 @@ export class CloudAuthManager {
|
|
130
130
|
async #oauthDropbox() {
|
131
131
|
return this.#oauthPkceFlow({
|
132
132
|
service: "dropbox",
|
133
|
-
clientId: "
|
133
|
+
clientId: asDefined(import.meta.env?.VITE_DROPBOX_CLIENT_ID, "Missing VITE_DROPBOX_CLIENT_ID"),
|
134
134
|
authUrlBase: "https://www.dropbox.com/oauth2/authorize",
|
135
135
|
tokenUrl: "https://api.dropboxapi.com/oauth2/token",
|
136
136
|
scope: "", // Dropbox scope is optional
|
@@ -140,7 +140,7 @@ export class CloudAuthManager {
|
|
140
140
|
});
|
141
141
|
}
|
142
142
|
async #oauthGoogle() {
|
143
|
-
const clientId =
|
143
|
+
const clientId = asDefined(import.meta.env?.VITE_GOOGLE_CLIENT_ID, "Missing VITE_GOOGLE_CLIENT_ID");
|
144
144
|
const scope = "https://www.googleapis.com/auth/drive.appdata";
|
145
145
|
const redirectUri = `${location.origin}/auth-callback.html`;
|
146
146
|
const params = new URLSearchParams({
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import { UUID } from "@opendaw/lib-std";
|
2
2
|
import { ProjectSchema } from "@opendaw/lib-dawproject";
|
3
|
-
import {
|
3
|
+
import { ProjectSkeleton } from "@opendaw/studio-adapters";
|
4
4
|
import { DawProject } from "./DawProject";
|
5
5
|
export declare namespace DawProjectImport {
|
6
6
|
type Result = {
|
7
7
|
audioIds: ReadonlyArray<UUID.Bytes>;
|
8
|
-
skeleton:
|
8
|
+
skeleton: ProjectSkeleton;
|
9
9
|
};
|
10
10
|
const read: (schema: ProjectSchema, resources: DawProject.ResourceProvider) => Promise<Result>;
|
11
11
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"DawProjectImport.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectImport.ts"],"names":[],"mappings":"AAAA,OAAO,EAiBH,IAAI,EAEP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAcH,aAAa,EAOhB,MAAM,yBAAyB,CAAA;AAuBhC,OAAO,EAAyC,
|
1
|
+
{"version":3,"file":"DawProjectImport.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectImport.ts"],"names":[],"mappings":"AAAA,OAAO,EAiBH,IAAI,EAEP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAcH,aAAa,EAOhB,MAAM,yBAAyB,CAAA;AAuBhC,OAAO,EAAyC,eAAe,EAAY,MAAM,0BAA0B,CAAA;AAC3G,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAQvC,yBAAiB,gBAAgB,CAAC;IAW9B,KAAY,MAAM,GAAG;QACjB,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,QAAQ,EAAE,eAAe,CAAA;KAC5B,CAAA;IAOM,MAAM,IAAI,GAAU,QAAQ,aAAa,EAAE,WAAW,UAAU,CAAC,gBAAgB,KAAG,OAAO,CAAC,MAAM,CAgXxG,CAAA;CAaJ"}
|
@@ -317,7 +317,10 @@ export var DawProjectImport;
|
|
317
317
|
assert(external !== true, "File cannot be external");
|
318
318
|
const { uuid, name } = resources.fromPath(path);
|
319
319
|
const audioFileBox = boxGraph.findBox(uuid)
|
320
|
-
.unwrapOrElse(() => AudioFileBox.create(boxGraph, uuid, box =>
|
320
|
+
.unwrapOrElse(() => AudioFileBox.create(boxGraph, uuid, box => {
|
321
|
+
box.fileName.setValue(name);
|
322
|
+
box.endInSeconds.setValue(asDefined(audio.duration, "Duration not defined"));
|
323
|
+
}));
|
321
324
|
audioIdSet.add(uuid, true);
|
322
325
|
AudioRegionBox.create(boxGraph, UUID.generate(), box => {
|
323
326
|
const position = asDefined(clip.time, "Time not defined");
|
package/dist/index.d.ts
CHANGED
@@ -26,6 +26,10 @@ export * from "./clouds/CloudAuthManager";
|
|
26
26
|
export * from "./clouds/CloudHandler";
|
27
27
|
export * from "./clouds/CloudBackup";
|
28
28
|
export * from "./ui/TimelineRange";
|
29
|
+
export * from "./utils/AutofitUtils";
|
30
|
+
export * from "./yjs/YService";
|
31
|
+
export * from "./yjs/YSync";
|
32
|
+
export * from "./yjs/YMapper";
|
29
33
|
export * from "./AudioDevices";
|
30
34
|
export * from "./AudioOfflineRenderer";
|
31
35
|
export * from "./AudioUnitOrdering";
|
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,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"}
|
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,sBAAsB,CAAA;AAEpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAE7B,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
@@ -26,6 +26,10 @@ export * from "./clouds/CloudAuthManager";
|
|
26
26
|
export * from "./clouds/CloudHandler";
|
27
27
|
export * from "./clouds/CloudBackup";
|
28
28
|
export * from "./ui/TimelineRange";
|
29
|
+
export * from "./utils/AutofitUtils";
|
30
|
+
export * from "./yjs/YService";
|
31
|
+
export * from "./yjs/YSync";
|
32
|
+
export * from "./yjs/YMapper";
|
29
33
|
export * from "./AudioDevices";
|
30
34
|
export * from "./AudioOfflineRenderer";
|
31
35
|
export * from "./AudioUnitOrdering";
|
@@ -7,7 +7,7 @@ export declare class MidiDevices {
|
|
7
7
|
static requestPermission(): Promise<undefined>;
|
8
8
|
static get(): ObservableOption<MIDIAccess>;
|
9
9
|
static subscribeMessageEvents(observer: Observer<MIDIMessageEvent>, channel?: byte): Subscription;
|
10
|
-
static inputDevices():
|
10
|
+
static inputDevices(): ReadonlyArray<MIDIInput>;
|
11
11
|
static findInputDeviceById(id: string): Option<MIDIInput>;
|
12
12
|
static externalInputDevices(): Option<ReadonlyArray<MIDIInput>>;
|
13
13
|
static externalOutputDevices(): Option<ReadonlyArray<MIDIOutput>>;
|
@@ -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;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,
|
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,aAAa,CAAC,SAAS,CAAC;IAK/C,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
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
9
9
|
};
|
10
|
-
import { Errors, Lazy, MutableObservableOption, MutableObservableValue, Notifier, Terminator } from "@opendaw/lib-std";
|
10
|
+
import { Errors, Lazy, MutableObservableOption, MutableObservableValue, Notifier, Option, Terminator } from "@opendaw/lib-std";
|
11
11
|
import { MidiData } from "@opendaw/lib-midi";
|
12
12
|
import { Promises } from "@opendaw/lib-runtime";
|
13
13
|
import { MIDIMessageSubscriber } from "./MIDIMessageSubscriber";
|
@@ -45,10 +45,10 @@ export class MidiDevices {
|
|
45
45
|
}
|
46
46
|
static inputDevices() {
|
47
47
|
return this.externalInputDevices()
|
48
|
-
.
|
48
|
+
.mapOr((inputs) => Array.from(inputs.values()).concat(this.softwareMIDIInput), [this.softwareMIDIInput]);
|
49
49
|
}
|
50
50
|
static findInputDeviceById(id) {
|
51
|
-
return this.inputDevices().
|
51
|
+
return Option.wrap(this.inputDevices().find(input => input.id === id));
|
52
52
|
}
|
53
53
|
static externalInputDevices() {
|
54
54
|
return this.get().map(({ inputs }) => Array.from(inputs.values()));
|
@@ -1,5 +1,7 @@
|
|
1
|
-
import { byte,
|
2
|
-
|
1
|
+
import { byte, int, Nullable, ObservableValue, unitValue } from "@opendaw/lib-std";
|
2
|
+
type OnMidiMessage = Nullable<(this: MIDIInput, ev: MIDIMessageEvent) => any>;
|
3
|
+
type OnStateChange = Nullable<(this: MIDIPort, ev: MIDIConnectionEvent) => any>;
|
4
|
+
export declare class SoftwareMIDIInput implements MIDIInput {
|
3
5
|
#private;
|
4
6
|
readonly manufacturer: string | null;
|
5
7
|
readonly connection: MIDIPortConnectionState;
|
@@ -8,13 +10,18 @@ export declare class SoftwareMIDIInput implements MIDIInput, Terminable {
|
|
8
10
|
readonly state: MIDIPortDeviceState;
|
9
11
|
readonly type: MIDIPortType;
|
10
12
|
readonly version: string | null;
|
11
|
-
|
12
|
-
onstatechange: ((this: MIDIPort, ev: MIDIConnectionEvent) => any) | null;
|
13
|
-
channel: byte;
|
13
|
+
onstatechange: OnStateChange;
|
14
14
|
constructor();
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
get onmidimessage(): OnMidiMessage;
|
16
|
+
set onmidimessage(value: OnMidiMessage);
|
17
|
+
get countListeners(): ObservableValue<int>;
|
18
|
+
sendNoteOn(note: byte, velocity?: unitValue): void;
|
19
|
+
sendNoteOff(note: byte): void;
|
20
|
+
releaseAllNotes(): void;
|
21
|
+
hasActiveNote(note: byte): boolean;
|
22
|
+
hasActiveNotes(): boolean;
|
23
|
+
get channel(): byte;
|
24
|
+
set channel(value: byte);
|
18
25
|
open(): Promise<MIDIPort>;
|
19
26
|
close(): Promise<MIDIPort>;
|
20
27
|
addEventListener<K extends keyof MIDIInputEventMap>(type: K, listener: (this: MIDIInput, ev: MIDIInputEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
@@ -22,6 +29,6 @@ export declare class SoftwareMIDIInput implements MIDIInput, Terminable {
|
|
22
29
|
dispatchEvent(event: MIDIMessageEvent): boolean;
|
23
30
|
removeEventListener<K extends keyof MIDIInputEventMap>(type: K, listener: (this: MIDIInput, ev: MIDIInputEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
24
31
|
removeEventListener<K extends keyof MIDIPortEventMap>(type: K, listener: (this: MIDIPort, ev: MIDIPortEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
25
|
-
terminate(): void;
|
26
32
|
}
|
33
|
+
export {};
|
27
34
|
//# sourceMappingURL=SoftwareMIDIInput.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"SoftwareMIDIInput.d.ts","sourceRoot":"","sources":["../../src/midi/SoftwareMIDIInput.ts"],"names":[],"mappings":"AAAA,OAAO,
|
1
|
+
{"version":3,"file":"SoftwareMIDIInput.d.ts","sourceRoot":"","sources":["../../src/midi/SoftwareMIDIInput.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,IAAI,EAGJ,GAAG,EAEH,QAAQ,EACR,eAAe,EAEf,SAAS,EACZ,MAAM,kBAAkB,CAAA;AAGzB,KAAK,aAAa,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,gBAAgB,KAAK,GAAG,CAAC,CAAA;AAE7E,KAAK,aAAa,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,mBAAmB,KAAK,GAAG,CAAC,CAAA;AAE/E,qBAAa,iBAAkB,YAAW,SAAS;;IAC/C,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;IAMzC,aAAa,EAAE,aAAa,CAAO;;IAWnC,IAAI,aAAa,IAAI,aAAa,CAA6B;IAC/D,IAAI,aAAa,CAAC,KAAK,EAAE,aAAa,EAGrC;IAED,IAAI,cAAc,IAAI,eAAe,CAAC,GAAG,CAAC,CAA8B;IAExE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAE,SAAe,GAAG,IAAI;IAOvD,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAO7B,eAAe,IAAI,IAAI;IASvB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;IAClC,cAAc,IAAI,OAAO;IAEzB,IAAI,OAAO,IAAI,IAAI,CAAuB;IAC1C,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,EAItB;IAED,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;IAK1K,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;CAc7K"}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { clamp, safeExecute } from "@opendaw/lib-std";
|
1
|
+
import { assert, clamp, DefaultObservableValue, isNull, safeExecute } from "@opendaw/lib-std";
|
2
2
|
import { MidiData } from "@opendaw/lib-midi";
|
3
3
|
export class SoftwareMIDIInput {
|
4
4
|
manufacturer = "openDAW";
|
@@ -9,34 +9,76 @@ export class SoftwareMIDIInput {
|
|
9
9
|
type = "input";
|
10
10
|
version = "1.0.0";
|
11
11
|
#dispatcher;
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
this
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
}
|
23
|
-
|
24
|
-
|
25
|
-
|
12
|
+
#countListeners;
|
13
|
+
#activeNotes;
|
14
|
+
onstatechange = null; // has no effect. this device is always connected.
|
15
|
+
#onmidimessage = null;
|
16
|
+
#channel = 0; // 0...15
|
17
|
+
constructor() {
|
18
|
+
this.#dispatcher = new EventTarget();
|
19
|
+
this.#countListeners = new DefaultObservableValue(0);
|
20
|
+
this.#activeNotes = new Uint8Array(128);
|
21
|
+
}
|
22
|
+
get onmidimessage() { return this.#onmidimessage; }
|
23
|
+
set onmidimessage(value) {
|
24
|
+
this.#onmidimessage = value;
|
25
|
+
if (isNull(value)) {
|
26
|
+
this.#changeListenerCount(-1);
|
27
|
+
}
|
28
|
+
else {
|
29
|
+
this.#changeListenerCount(1);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
get countListeners() { return this.#countListeners; }
|
33
|
+
sendNoteOn(note, velocity = 1.0) {
|
34
|
+
assert(note >= 0 && note <= 127, `Note must be between 0 and 127, but was ${note}`);
|
35
|
+
this.#activeNotes[note]++;
|
36
|
+
const velocityByte = Math.round(clamp(velocity, 0.0, 1.0) * 127.0);
|
37
|
+
this.#sendMIDIMessageData(MidiData.noteOn(this.#channel, note, velocityByte));
|
38
|
+
}
|
39
|
+
sendNoteOff(note) {
|
40
|
+
assert(note >= 0 && note <= 127, `Note must be between 0 and 127, but was ${note}`);
|
41
|
+
this.#activeNotes[note]--;
|
42
|
+
this.#sendMIDIMessageData(MidiData.noteOff(this.#channel, note));
|
43
|
+
assert(this.#activeNotes[note] >= 0, "Negative count of active notes");
|
44
|
+
}
|
45
|
+
releaseAllNotes() {
|
46
|
+
this.#activeNotes.forEach((count, note) => {
|
47
|
+
for (let i = 0; i < count; i++) {
|
48
|
+
this.#sendMIDIMessageData(MidiData.noteOff(this.#channel, note));
|
49
|
+
}
|
50
|
+
});
|
51
|
+
this.#activeNotes.fill(0);
|
52
|
+
}
|
53
|
+
hasActiveNote(note) { return this.#activeNotes[note] > 0; }
|
54
|
+
hasActiveNotes() { return this.#activeNotes.some(count => count > 0); }
|
55
|
+
get channel() { return this.#channel; }
|
56
|
+
set channel(value) {
|
57
|
+
if (this.#channel === value) {
|
58
|
+
return;
|
59
|
+
}
|
60
|
+
this.releaseAllNotes();
|
61
|
+
this.#channel = value;
|
26
62
|
}
|
27
63
|
open() { return Promise.resolve(this); }
|
28
64
|
close() { return Promise.resolve(this); }
|
29
65
|
addEventListener(type, listener, options) {
|
30
66
|
this.#dispatcher.addEventListener(type, listener, options);
|
67
|
+
this.#changeListenerCount(1);
|
31
68
|
}
|
32
69
|
dispatchEvent(event) {
|
33
|
-
safeExecute(this
|
70
|
+
safeExecute(this.#onmidimessage, event);
|
34
71
|
return this.#dispatcher.dispatchEvent(event);
|
35
72
|
}
|
36
73
|
removeEventListener(type, listener, options) {
|
37
74
|
this.#dispatcher.removeEventListener(type, listener, options);
|
75
|
+
this.#changeListenerCount(-1);
|
76
|
+
}
|
77
|
+
#sendMIDIMessageData(data) {
|
78
|
+
const eventInit = { data };
|
79
|
+
this.dispatchEvent(new MessageEvent("midimessage", eventInit));
|
38
80
|
}
|
39
|
-
|
40
|
-
this.#
|
81
|
+
#changeListenerCount(delta) {
|
82
|
+
this.#countListeners.setValue(this.#countListeners.getValue() + delta);
|
41
83
|
}
|
42
84
|
}
|