@opendaw/studio-core 0.0.127 → 0.0.129
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/StudioPreferences.d.ts +1 -1
- package/dist/StudioSettings.d.ts +1 -1
- package/dist/StudioSettings.js +2 -2
- package/dist/processors.js +11 -11
- package/dist/processors.js.map +4 -4
- package/dist/project/Project.js +3 -3
- package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.d.ts.map +1 -1
- package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.js +6 -0
- package/dist/ui/clipboard/types/DevicesClipboardHandler.d.ts.map +1 -1
- package/dist/ui/clipboard/types/DevicesClipboardHandler.js +18 -3
- package/dist/ui/clipboard/types/DevicesClipboardHandler.test.js +182 -4
- package/dist/ysync/YSync.d.ts.map +1 -1
- package/dist/ysync/YSync.js +2 -1
- package/package.json +15 -15
package/dist/project/Project.js
CHANGED
|
@@ -20,9 +20,9 @@ import { AudioUnitFreeze } from "../AudioUnitFreeze";
|
|
|
20
20
|
export class Project {
|
|
21
21
|
static new(env, options) {
|
|
22
22
|
const createDefaultUser = options?.noDefaultUser !== true;
|
|
23
|
-
const
|
|
23
|
+
const createOutputMaximizer = StudioPreferences.settings.engine["auto-create-output-maximizer"];
|
|
24
24
|
const { boxGraph, mandatoryBoxes } = ProjectSkeleton.empty({
|
|
25
|
-
|
|
25
|
+
createOutputMaximizer,
|
|
26
26
|
createDefaultUser
|
|
27
27
|
});
|
|
28
28
|
const project = new Project(env, boxGraph, mandatoryBoxes);
|
|
@@ -123,7 +123,7 @@ export class Project {
|
|
|
123
123
|
}
|
|
124
124
|
else if (update instanceof DeleteUpdate && update.name === AudioFileBox.ClassName) {
|
|
125
125
|
this.#unregisterSample(update.uuid);
|
|
126
|
-
this.#deleteUserCreatedSample(update.uuid);
|
|
126
|
+
this.#deleteUserCreatedSample(update.uuid).finally();
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioUnitsClipboardHandler.d.ts","sourceRoot":"","sources":["../../../../src/ui/clipboard/types/AudioUnitsClipboardHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,OAAO,EAAO,MAAM,EAAY,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAC1G,OAAO,EAAM,QAAQ,EAAa,MAAM,kBAAkB,CAAA;AAW1D,OAAO,EAAC,mBAAmB,EAAqB,cAAc,EAAE,WAAW,EAAC,MAAM,0BAA0B,CAAA;AAC5G,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AAGpE,KAAK,mBAAmB,GAAG,cAAc,CAAC,aAAa,CAAC,CAAA;AAMxD,yBAAiB,mBAAmB,CAAC;IACjC,KAAY,OAAO,GAAG;QAClB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;QACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;QACzB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;QAC3B,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAA;QACvC,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAA;QACtC,QAAQ,CAAC,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAA;KACrE,CAAA;IAaM,MAAM,aAAa,GAAI,yFAOG,OAAO,KAAG,gBAAgB,CAAC,mBAAmB,CAsE9E,CAAA;
|
|
1
|
+
{"version":3,"file":"AudioUnitsClipboardHandler.d.ts","sourceRoot":"","sources":["../../../../src/ui/clipboard/types/AudioUnitsClipboardHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,OAAO,EAAO,MAAM,EAAY,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAC1G,OAAO,EAAM,QAAQ,EAAa,MAAM,kBAAkB,CAAA;AAW1D,OAAO,EAAC,mBAAmB,EAAqB,cAAc,EAAE,WAAW,EAAC,MAAM,0BAA0B,CAAA;AAC5G,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AAGpE,KAAK,mBAAmB,GAAG,cAAc,CAAC,aAAa,CAAC,CAAA;AAMxD,yBAAiB,mBAAmB,CAAC;IACjC,KAAY,OAAO,GAAG;QAClB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;QACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;QACzB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;QAC3B,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAA;QACvC,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAA;QACtC,QAAQ,CAAC,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAA;KACrE,CAAA;IAaM,MAAM,aAAa,GAAI,yFAOG,OAAO,KAAG,gBAAgB,CAAC,mBAAmB,CAsE9E,CAAA;CA+GJ"}
|
|
@@ -138,6 +138,9 @@ export var AudioUnitsClipboard;
|
|
|
138
138
|
}
|
|
139
139
|
ClipboardUtils.deserializeBoxes(data, boxGraph, {
|
|
140
140
|
mapPointer: (pointer, address) => {
|
|
141
|
+
if (address.isEmpty()) {
|
|
142
|
+
return Option.None;
|
|
143
|
+
}
|
|
141
144
|
if (pointer.pointerType === Pointers.TrackCollection) {
|
|
142
145
|
return Option.wrap(outputBox.tracks.address);
|
|
143
146
|
}
|
|
@@ -169,6 +172,9 @@ export var AudioUnitsClipboard;
|
|
|
169
172
|
}
|
|
170
173
|
const boxes = ClipboardUtils.deserializeBoxes(data, boxGraph, {
|
|
171
174
|
mapPointer: (pointer, address) => {
|
|
175
|
+
if (address.isEmpty()) {
|
|
176
|
+
return Option.None;
|
|
177
|
+
}
|
|
172
178
|
if (pointer.pointerType === Pointers.AudioUnits) {
|
|
173
179
|
return Option.wrap(rootBox.audioUnits.address);
|
|
174
180
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevicesClipboardHandler.d.ts","sourceRoot":"","sources":["../../../../src/ui/clipboard/types/DevicesClipboardHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,OAAO,EAKP,MAAM,EAEN,QAAQ,EAGX,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAM,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAG9C,OAAO,EAEH,WAAW,EACX,gBAAgB,EAEhB,UAAU,EAGV,iBAAiB,EAGpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AAGpE,KAAK,gBAAgB,GAAG,cAAc,CAAC,SAAS,CAAC,CAAA;AAajD,yBAAiB,gBAAgB,CAAC;IAC9B,KAAY,OAAO,GAAG;QAClB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;QACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;QACzB,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,CAAA;QACvD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;QAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;QACjC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAA;KACjD,CAAA;IAyBM,MAAM,aAAa,GAAI,oEAOG,OAAO,KAAG,gBAAgB,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"DevicesClipboardHandler.d.ts","sourceRoot":"","sources":["../../../../src/ui/clipboard/types/DevicesClipboardHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,OAAO,EAKP,MAAM,EAEN,QAAQ,EAGX,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAM,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAG9C,OAAO,EAEH,WAAW,EACX,gBAAgB,EAEhB,UAAU,EAGV,iBAAiB,EAGpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AAGpE,KAAK,gBAAgB,GAAG,cAAc,CAAC,SAAS,CAAC,CAAA;AAajD,yBAAiB,gBAAgB,CAAC;IAC9B,KAAY,OAAO,GAAG;QAClB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;QACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;QACzB,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,CAAA;QACvD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;QAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;QACjC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAA;KACjD,CAAA;IAyBM,MAAM,aAAa,GAAI,oEAOG,OAAO,KAAG,gBAAgB,CAAC,gBAAgB,CAwN3E,CAAA;CACJ"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ByteArrayInput, ByteArrayOutput, isDefined, isInstanceOf, isNotNull, Option, RuntimeNotifier } from "@opendaw/lib-std";
|
|
2
2
|
import { Pointers } from "@opendaw/studio-enums";
|
|
3
|
-
import { TrackBox } from "@opendaw/studio-boxes";
|
|
3
|
+
import { RootBox, TrackBox } from "@opendaw/studio-boxes";
|
|
4
4
|
import { DeviceBoxUtils, Devices } from "@opendaw/studio-adapters";
|
|
5
5
|
import { ClipboardUtils } from "../ClipboardUtils";
|
|
6
6
|
export var DevicesClipboard;
|
|
@@ -69,11 +69,16 @@ export var DevicesClipboard;
|
|
|
69
69
|
.filter(pointer => pointer.mandatory && !pointer.box.ephemeral
|
|
70
70
|
&& !isDefined(pointer.box.resource))
|
|
71
71
|
.map(pointer => pointer.box);
|
|
72
|
+
const mandatoryDeps = Array.from(boxGraph.dependenciesOf(box, {
|
|
73
|
+
alwaysFollowMandatory: true,
|
|
74
|
+
excludeBox: (dep) => dep.ephemeral || DeviceBoxUtils.isDeviceBox(dep)
|
|
75
|
+
|| dep.name === RootBox.ClassName
|
|
76
|
+
}).boxes).filter(dep => !isDefined(dep.resource));
|
|
72
77
|
const preserved = [box, ...ownedChildren].flatMap(root => Array.from(boxGraph.dependenciesOf(root, {
|
|
73
78
|
alwaysFollowMandatory: true,
|
|
74
79
|
excludeBox: (dep) => dep.ephemeral || DeviceBoxUtils.isDeviceBox(dep)
|
|
75
80
|
}).boxes).filter(dep => dep.resource === "preserved"));
|
|
76
|
-
return [...ownedChildren, ...preserved];
|
|
81
|
+
return [...ownedChildren, ...mandatoryDeps, ...preserved];
|
|
77
82
|
});
|
|
78
83
|
const trackContent = [];
|
|
79
84
|
if (isNotNull(instrument)) {
|
|
@@ -194,7 +199,10 @@ export var DevicesClipboard;
|
|
|
194
199
|
}
|
|
195
200
|
}
|
|
196
201
|
const boxes = ClipboardUtils.deserializeBoxes(entry.data, boxGraph, {
|
|
197
|
-
mapPointer: pointer => {
|
|
202
|
+
mapPointer: (pointer, address) => {
|
|
203
|
+
if (address.isEmpty()) {
|
|
204
|
+
return Option.None;
|
|
205
|
+
}
|
|
198
206
|
if (pointer.pointerType === Pointers.InstrumentHost && replaceInstrument) {
|
|
199
207
|
return Option.wrap(host.inputField.address);
|
|
200
208
|
}
|
|
@@ -210,6 +218,13 @@ export var DevicesClipboard;
|
|
|
210
218
|
if (pointer.pointerType === Pointers.Automation && replaceInstrument) {
|
|
211
219
|
return Option.wrap(host.audioUnitBoxAdapter().address);
|
|
212
220
|
}
|
|
221
|
+
if (pointer.pointerType === Pointers.MIDIDevice) {
|
|
222
|
+
const rootBox = boxGraph.boxes()
|
|
223
|
+
.find(box => isInstanceOf(box, RootBox));
|
|
224
|
+
if (isDefined(rootBox)) {
|
|
225
|
+
return Option.wrap(rootBox.outputMidiDevices.address);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
213
228
|
return Option.None;
|
|
214
229
|
},
|
|
215
230
|
excludeBox: box => !replaceInstrument
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it, beforeEach } from "vitest";
|
|
2
2
|
import { isDefined, isInstanceOf, Option, UUID } from "@opendaw/lib-std";
|
|
3
3
|
import { BoxEditing } from "@opendaw/lib-box";
|
|
4
|
-
import { ApparatDeviceBox, AudioFileBox, AudioUnitBox, CompressorDeviceBox, NoteEventCollectionBox, NoteRegionBox, PlayfieldDeviceBox, PlayfieldSampleBox, TapeDeviceBox, TrackBox, VaporisateurDeviceBox, ValueEventCollectionBox, ValueRegionBox, WerkstattParameterBox, WerkstattSampleBox } from "@opendaw/studio-boxes";
|
|
4
|
+
import { ApparatDeviceBox, AudioFileBox, AudioUnitBox, CompressorDeviceBox, MIDIOutputBox, MIDIOutputDeviceBox, NoteEventCollectionBox, NoteRegionBox, PlayfieldDeviceBox, PlayfieldSampleBox, RootBox, TapeDeviceBox, TrackBox, VaporisateurDeviceBox, ValueEventCollectionBox, ValueRegionBox, WerkstattParameterBox, WerkstattSampleBox } from "@opendaw/studio-boxes";
|
|
5
5
|
import { AudioUnitType, Pointers } from "@opendaw/studio-enums";
|
|
6
6
|
import { DeviceBoxUtils, ProjectSkeleton, TrackType } from "@opendaw/studio-adapters";
|
|
7
7
|
import { ClipboardUtils } from "../ClipboardUtils";
|
|
@@ -9,8 +9,8 @@ describe("DevicesClipboardHandler", () => {
|
|
|
9
9
|
let source;
|
|
10
10
|
let target;
|
|
11
11
|
beforeEach(() => {
|
|
12
|
-
source = ProjectSkeleton.empty({ createDefaultUser: true,
|
|
13
|
-
target = ProjectSkeleton.empty({ createDefaultUser: true,
|
|
12
|
+
source = ProjectSkeleton.empty({ createDefaultUser: true, createOutputMaximizer: false });
|
|
13
|
+
target = ProjectSkeleton.empty({ createDefaultUser: true, createOutputMaximizer: false });
|
|
14
14
|
});
|
|
15
15
|
const createAudioUnit = (skeleton, index = 1) => {
|
|
16
16
|
const { boxGraph, mandatoryBoxes: { rootBox, primaryAudioBusBox } } = skeleton;
|
|
@@ -193,6 +193,11 @@ describe("DevicesClipboardHandler", () => {
|
|
|
193
193
|
.filter(pointer => pointer.mandatory && !pointer.box.ephemeral
|
|
194
194
|
&& !isDefined(pointer.box.resource))
|
|
195
195
|
.map(pointer => pointer.box);
|
|
196
|
+
const mandatoryDeps = Array.from(boxGraph.dependenciesOf(deviceBox, {
|
|
197
|
+
alwaysFollowMandatory: true,
|
|
198
|
+
excludeBox: (dep) => dep.ephemeral || DeviceBoxUtils.isDeviceBox(dep)
|
|
199
|
+
|| dep.name === RootBox.ClassName
|
|
200
|
+
}).boxes).filter(dep => !isDefined(dep.resource));
|
|
196
201
|
const preserved = [deviceBox, ...ownedChildren].flatMap(root => Array.from(boxGraph.dependenciesOf(root, {
|
|
197
202
|
alwaysFollowMandatory: true,
|
|
198
203
|
excludeBox: (dep) => dep.ephemeral || DeviceBoxUtils.isDeviceBox(dep)
|
|
@@ -219,7 +224,7 @@ describe("DevicesClipboardHandler", () => {
|
|
|
219
224
|
}
|
|
220
225
|
}
|
|
221
226
|
const seen = new Set();
|
|
222
|
-
return [...ownedChildren, ...preserved, ...trackContent].filter(box => {
|
|
227
|
+
return [...ownedChildren, ...mandatoryDeps, ...preserved, ...trackContent].filter(box => {
|
|
223
228
|
const uuid = UUID.toString(box.address.uuid);
|
|
224
229
|
if (seen.has(uuid))
|
|
225
230
|
return false;
|
|
@@ -958,6 +963,179 @@ describe("DevicesClipboardHandler", () => {
|
|
|
958
963
|
// ─────────────────────────────────────────────────────────
|
|
959
964
|
// isInstanceOf type narrowing
|
|
960
965
|
// ─────────────────────────────────────────────────────────
|
|
966
|
+
// ─────────────────────────────────────────────────────────
|
|
967
|
+
// MIDIOutputDeviceBox copy & paste
|
|
968
|
+
// ─────────────────────────────────────────────────────────
|
|
969
|
+
const addMIDIOutputInstrument = (skeleton, audioUnit, label) => {
|
|
970
|
+
const { boxGraph } = skeleton;
|
|
971
|
+
let device;
|
|
972
|
+
boxGraph.beginTransaction();
|
|
973
|
+
device = MIDIOutputDeviceBox.create(boxGraph, UUID.generate(), box => {
|
|
974
|
+
box.label.setValue(label);
|
|
975
|
+
box.host.refer(audioUnit.input);
|
|
976
|
+
});
|
|
977
|
+
boxGraph.endTransaction();
|
|
978
|
+
return device;
|
|
979
|
+
};
|
|
980
|
+
const connectMIDIOutput = (skeleton, deviceBox, outputId, outputLabel) => {
|
|
981
|
+
const { boxGraph, mandatoryBoxes: { rootBox } } = skeleton;
|
|
982
|
+
let midiOutputBox;
|
|
983
|
+
boxGraph.beginTransaction();
|
|
984
|
+
midiOutputBox = MIDIOutputBox.create(boxGraph, UUID.generate(), box => {
|
|
985
|
+
box.id.setValue(outputId);
|
|
986
|
+
box.label.setValue(outputLabel);
|
|
987
|
+
box.root.refer(rootBox.outputMidiDevices);
|
|
988
|
+
});
|
|
989
|
+
deviceBox.device.refer(midiOutputBox.device);
|
|
990
|
+
boxGraph.endTransaction();
|
|
991
|
+
return midiOutputBox;
|
|
992
|
+
};
|
|
993
|
+
describe("MIDIOutputDeviceBox copy & paste", () => {
|
|
994
|
+
it("collects MIDIOutputBox as dependency when device pointer is set", () => {
|
|
995
|
+
const audioUnit = createAudioUnit(source);
|
|
996
|
+
const midiDevice = addMIDIOutputInstrument(source, audioUnit, "MIDIOut");
|
|
997
|
+
connectMIDIOutput(source, midiDevice, "output-1", "MIDI Port 1");
|
|
998
|
+
const deps = collectDeviceDependencies(midiDevice, source.boxGraph);
|
|
999
|
+
expect(deps.filter(box => isInstanceOf(box, MIDIOutputBox)).length).toBe(1);
|
|
1000
|
+
});
|
|
1001
|
+
it("does not collect RootBox as dependency", () => {
|
|
1002
|
+
const audioUnit = createAudioUnit(source);
|
|
1003
|
+
const midiDevice = addMIDIOutputInstrument(source, audioUnit, "MIDIOut");
|
|
1004
|
+
connectMIDIOutput(source, midiDevice, "output-1", "MIDI Port 1");
|
|
1005
|
+
const deps = collectDeviceDependencies(midiDevice, source.boxGraph);
|
|
1006
|
+
expect(deps.filter(box => isInstanceOf(box, RootBox)).length).toBe(0);
|
|
1007
|
+
});
|
|
1008
|
+
it("does not collect MIDIOutputBox when device pointer is empty", () => {
|
|
1009
|
+
const audioUnit = createAudioUnit(source);
|
|
1010
|
+
const midiDevice = addMIDIOutputInstrument(source, audioUnit, "MIDIOut");
|
|
1011
|
+
const deps = collectDeviceDependencies(midiDevice, source.boxGraph);
|
|
1012
|
+
expect(deps.filter(box => isInstanceOf(box, MIDIOutputBox)).length).toBe(0);
|
|
1013
|
+
});
|
|
1014
|
+
it("paste MIDIOutput with empty device pointer does not fill it", () => {
|
|
1015
|
+
const sourceAU = createAudioUnit(source);
|
|
1016
|
+
const sourceMidi = addMIDIOutputInstrument(source, sourceAU, "Source MIDI");
|
|
1017
|
+
const deps = collectDeviceDependencies(sourceMidi, source.boxGraph, sourceAU);
|
|
1018
|
+
const data = ClipboardUtils.serializeBoxes([sourceMidi, ...deps]);
|
|
1019
|
+
const targetAU = createAudioUnit(target);
|
|
1020
|
+
target.boxGraph.beginTransaction();
|
|
1021
|
+
const boxes = ClipboardUtils.deserializeBoxes(data, target.boxGraph, {
|
|
1022
|
+
mapPointer: (pointer, address) => {
|
|
1023
|
+
if (address.isEmpty()) {
|
|
1024
|
+
return Option.None;
|
|
1025
|
+
}
|
|
1026
|
+
if (pointer.pointerType === Pointers.InstrumentHost) {
|
|
1027
|
+
return Option.wrap(targetAU.input.address);
|
|
1028
|
+
}
|
|
1029
|
+
if (pointer.pointerType === Pointers.MIDIDevice) {
|
|
1030
|
+
return Option.wrap(target.mandatoryBoxes.rootBox.outputMidiDevices.address);
|
|
1031
|
+
}
|
|
1032
|
+
if (pointer.pointerType === Pointers.TrackCollection) {
|
|
1033
|
+
return Option.wrap(targetAU.tracks.address);
|
|
1034
|
+
}
|
|
1035
|
+
if (pointer.pointerType === Pointers.Automation) {
|
|
1036
|
+
return Option.wrap(targetAU.address);
|
|
1037
|
+
}
|
|
1038
|
+
return Option.None;
|
|
1039
|
+
},
|
|
1040
|
+
excludeBox: () => false
|
|
1041
|
+
});
|
|
1042
|
+
target.boxGraph.endTransaction();
|
|
1043
|
+
const pastedDevice = boxes.find(box => isInstanceOf(box, MIDIOutputDeviceBox));
|
|
1044
|
+
expect(pastedDevice).toBeDefined();
|
|
1045
|
+
expect(pastedDevice.device.isEmpty()).toBe(true);
|
|
1046
|
+
});
|
|
1047
|
+
it("paste-replace MIDIOutput with connected device does not throw", () => {
|
|
1048
|
+
const sourceAU = createAudioUnit(source);
|
|
1049
|
+
const sourceMidi = addMIDIOutputInstrument(source, sourceAU, "Source MIDI");
|
|
1050
|
+
connectMIDIOutput(source, sourceMidi, "output-1", "MIDI Port 1");
|
|
1051
|
+
const deps = collectDeviceDependencies(sourceMidi, source.boxGraph, sourceAU);
|
|
1052
|
+
const data = ClipboardUtils.serializeBoxes([sourceMidi, ...deps]);
|
|
1053
|
+
const targetAU = createAudioUnit(target);
|
|
1054
|
+
const targetVapo = addVaporisateur(target, targetAU, "Target Vapo");
|
|
1055
|
+
expect(() => {
|
|
1056
|
+
target.boxGraph.beginTransaction();
|
|
1057
|
+
targetVapo.delete();
|
|
1058
|
+
ClipboardUtils.deserializeBoxes(data, target.boxGraph, {
|
|
1059
|
+
...makePasteMapper(targetAU, true),
|
|
1060
|
+
mapPointer: (pointer, address) => {
|
|
1061
|
+
const base = makePasteMapper(targetAU, true).mapPointer(pointer);
|
|
1062
|
+
if (base.nonEmpty()) {
|
|
1063
|
+
return base;
|
|
1064
|
+
}
|
|
1065
|
+
if (pointer.pointerType === Pointers.MIDIDevice) {
|
|
1066
|
+
return Option.wrap(target.mandatoryBoxes.rootBox.outputMidiDevices.address);
|
|
1067
|
+
}
|
|
1068
|
+
return Option.None;
|
|
1069
|
+
}
|
|
1070
|
+
});
|
|
1071
|
+
target.boxGraph.endTransaction();
|
|
1072
|
+
}).not.toThrow();
|
|
1073
|
+
});
|
|
1074
|
+
it("pasted MIDIOutputBox.root points to target RootBox.outputMidiDevices", () => {
|
|
1075
|
+
const sourceAU = createAudioUnit(source);
|
|
1076
|
+
const sourceMidi = addMIDIOutputInstrument(source, sourceAU, "Source MIDI");
|
|
1077
|
+
connectMIDIOutput(source, sourceMidi, "output-1", "MIDI Port 1");
|
|
1078
|
+
const deps = collectDeviceDependencies(sourceMidi, source.boxGraph, sourceAU);
|
|
1079
|
+
const data = ClipboardUtils.serializeBoxes([sourceMidi, ...deps]);
|
|
1080
|
+
const targetAU = createAudioUnit(target);
|
|
1081
|
+
target.boxGraph.beginTransaction();
|
|
1082
|
+
const boxes = ClipboardUtils.deserializeBoxes(data, target.boxGraph, {
|
|
1083
|
+
mapPointer: (pointer, address) => {
|
|
1084
|
+
if (pointer.pointerType === Pointers.InstrumentHost) {
|
|
1085
|
+
return Option.wrap(targetAU.input.address);
|
|
1086
|
+
}
|
|
1087
|
+
if (pointer.pointerType === Pointers.MIDIDevice) {
|
|
1088
|
+
return Option.wrap(target.mandatoryBoxes.rootBox.outputMidiDevices.address);
|
|
1089
|
+
}
|
|
1090
|
+
if (pointer.pointerType === Pointers.TrackCollection) {
|
|
1091
|
+
return Option.wrap(targetAU.tracks.address);
|
|
1092
|
+
}
|
|
1093
|
+
if (pointer.pointerType === Pointers.Automation) {
|
|
1094
|
+
return Option.wrap(targetAU.address);
|
|
1095
|
+
}
|
|
1096
|
+
return Option.None;
|
|
1097
|
+
},
|
|
1098
|
+
excludeBox: () => false
|
|
1099
|
+
});
|
|
1100
|
+
target.boxGraph.endTransaction();
|
|
1101
|
+
const pastedMidiOutputBox = boxes.find(box => isInstanceOf(box, MIDIOutputBox));
|
|
1102
|
+
expect(pastedMidiOutputBox).toBeDefined();
|
|
1103
|
+
expect(pastedMidiOutputBox.root.targetVertex.unwrap().box).toBe(target.mandatoryBoxes.rootBox);
|
|
1104
|
+
});
|
|
1105
|
+
it("pasted MIDIOutputDeviceBox.device points to pasted MIDIOutputBox", () => {
|
|
1106
|
+
const sourceAU = createAudioUnit(source);
|
|
1107
|
+
const sourceMidi = addMIDIOutputInstrument(source, sourceAU, "Source MIDI");
|
|
1108
|
+
connectMIDIOutput(source, sourceMidi, "output-1", "MIDI Port 1");
|
|
1109
|
+
const deps = collectDeviceDependencies(sourceMidi, source.boxGraph, sourceAU);
|
|
1110
|
+
const data = ClipboardUtils.serializeBoxes([sourceMidi, ...deps]);
|
|
1111
|
+
const targetAU = createAudioUnit(target);
|
|
1112
|
+
target.boxGraph.beginTransaction();
|
|
1113
|
+
const boxes = ClipboardUtils.deserializeBoxes(data, target.boxGraph, {
|
|
1114
|
+
mapPointer: (pointer, address) => {
|
|
1115
|
+
if (pointer.pointerType === Pointers.InstrumentHost) {
|
|
1116
|
+
return Option.wrap(targetAU.input.address);
|
|
1117
|
+
}
|
|
1118
|
+
if (pointer.pointerType === Pointers.MIDIDevice) {
|
|
1119
|
+
return Option.wrap(target.mandatoryBoxes.rootBox.outputMidiDevices.address);
|
|
1120
|
+
}
|
|
1121
|
+
if (pointer.pointerType === Pointers.TrackCollection) {
|
|
1122
|
+
return Option.wrap(targetAU.tracks.address);
|
|
1123
|
+
}
|
|
1124
|
+
if (pointer.pointerType === Pointers.Automation) {
|
|
1125
|
+
return Option.wrap(targetAU.address);
|
|
1126
|
+
}
|
|
1127
|
+
return Option.None;
|
|
1128
|
+
},
|
|
1129
|
+
excludeBox: () => false
|
|
1130
|
+
});
|
|
1131
|
+
target.boxGraph.endTransaction();
|
|
1132
|
+
const pastedDevice = boxes.find(box => isInstanceOf(box, MIDIOutputDeviceBox));
|
|
1133
|
+
const pastedMidiOutput = boxes.find(box => isInstanceOf(box, MIDIOutputBox));
|
|
1134
|
+
expect(pastedDevice).toBeDefined();
|
|
1135
|
+
expect(pastedMidiOutput).toBeDefined();
|
|
1136
|
+
expect(pastedDevice.device.targetVertex.unwrap().box).toBe(pastedMidiOutput);
|
|
1137
|
+
});
|
|
1138
|
+
});
|
|
961
1139
|
describe("isInstanceOf type narrowing", () => {
|
|
962
1140
|
it("narrows TrackBox type directly without intermediate null variable", () => {
|
|
963
1141
|
const audioUnit = createAudioUnit(source);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"YSync.d.ts","sourceRoot":"","sources":["../../src/ysync/YSync.ts"],"names":[],"mappings":"AAAA,OAAO,EASH,QAAQ,EAER,UAAU,EAGb,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAa,QAAQ,EAA2D,MAAM,kBAAkB,CAAA;AAE/G,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAIxB,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACvB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtB,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;CAC/B,CAAA;AAED,qBAAa,KAAK,CAAC,CAAC,CAAE,YAAW,UAAU;;IACvC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,OAAO;WAItB,YAAY,CAAC,CAAC,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAC,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;WAcnE,QAAQ,CAAC,CAAC,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAC,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAyBhE,EAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAC,EAAE,SAAS,CAAC,CAAC,CAAC;IAQrD,SAAS,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"YSync.d.ts","sourceRoot":"","sources":["../../src/ysync/YSync.ts"],"names":[],"mappings":"AAAA,OAAO,EASH,QAAQ,EAER,UAAU,EAGb,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAa,QAAQ,EAA2D,MAAM,kBAAkB,CAAA;AAE/G,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAIxB,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACvB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtB,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;CAC/B,CAAA;AAED,qBAAa,KAAK,CAAC,CAAC,CAAE,YAAW,UAAU;;IACvC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,OAAO;WAItB,YAAY,CAAC,CAAC,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAC,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;WAcnE,QAAQ,CAAC,CAAC,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAC,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAyBhE,EAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAC,EAAE,SAAS,CAAC,CAAC,CAAC;IAQrD,SAAS,IAAI,IAAI;CAkLpB"}
|
package/dist/ysync/YSync.js
CHANGED
|
@@ -50,8 +50,8 @@ export class YSync {
|
|
|
50
50
|
#setupYjs() {
|
|
51
51
|
const eventHandler = (events, { origin, local }) => {
|
|
52
52
|
const originLabel = typeof origin === "string" ? origin : "WebsocketProvider";
|
|
53
|
-
console.debug(`got ${events.length} ${local ? "local" : "external"} updates from '${originLabel}'`);
|
|
54
53
|
const isHistoryReplay = typeof origin === "string" && origin.startsWith("[history]");
|
|
54
|
+
console.debug(`got ${events.length} ${local ? "local" : "external"} updates from '${originLabel}, isHistoryReplay: ${isHistoryReplay}'`);
|
|
55
55
|
if (local && !isHistoryReplay) {
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
@@ -111,6 +111,7 @@ export class YSync {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
#updateValue(path, key) {
|
|
114
|
+
console.debug(`#updateValue`, path, key);
|
|
114
115
|
const vertexOption = this.#boxGraph.findVertex(YMapper.pathToAddress(path, key));
|
|
115
116
|
if (vertexOption.isEmpty()) {
|
|
116
117
|
console.debug(`Vertex at '${path}' does not exist. Ignoring.`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opendaw/studio-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.129",
|
|
4
4
|
"license": "LGPL-3.0-or-later",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -33,17 +33,17 @@
|
|
|
33
33
|
"test": "vitest run --config vitest.config.ts"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@opendaw/lib-box": "^0.0.
|
|
37
|
-
"@opendaw/lib-dawproject": "^0.0.
|
|
38
|
-
"@opendaw/lib-dom": "^0.0.
|
|
39
|
-
"@opendaw/lib-dsp": "^0.0.
|
|
40
|
-
"@opendaw/lib-fusion": "^0.0.
|
|
41
|
-
"@opendaw/lib-runtime": "^0.0.
|
|
42
|
-
"@opendaw/lib-std": "^0.0.
|
|
36
|
+
"@opendaw/lib-box": "^0.0.80",
|
|
37
|
+
"@opendaw/lib-dawproject": "^0.0.65",
|
|
38
|
+
"@opendaw/lib-dom": "^0.0.79",
|
|
39
|
+
"@opendaw/lib-dsp": "^0.0.79",
|
|
40
|
+
"@opendaw/lib-fusion": "^0.0.87",
|
|
41
|
+
"@opendaw/lib-runtime": "^0.0.75",
|
|
42
|
+
"@opendaw/lib-std": "^0.0.74",
|
|
43
43
|
"@opendaw/nam-wasm": "^1.0.3",
|
|
44
|
-
"@opendaw/studio-adapters": "^0.0.
|
|
45
|
-
"@opendaw/studio-boxes": "^0.0.
|
|
46
|
-
"@opendaw/studio-enums": "^0.0.
|
|
44
|
+
"@opendaw/studio-adapters": "^0.0.101",
|
|
45
|
+
"@opendaw/studio-boxes": "^0.0.85",
|
|
46
|
+
"@opendaw/studio-enums": "^0.0.70",
|
|
47
47
|
"dropbox": "^10.34.0",
|
|
48
48
|
"y-websocket": "^1.4.5",
|
|
49
49
|
"yjs": "^13.6.27",
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
"@ffmpeg/ffmpeg": "^0.12.15",
|
|
58
58
|
"@ffmpeg/util": "^0.12.2",
|
|
59
59
|
"@opendaw/eslint-config": "^0.0.27",
|
|
60
|
-
"@opendaw/studio-core-processors": "^0.0.
|
|
61
|
-
"@opendaw/studio-core-workers": "^0.0.
|
|
62
|
-
"@opendaw/studio-forge-boxes": "^0.0.
|
|
60
|
+
"@opendaw/studio-core-processors": "^0.0.105",
|
|
61
|
+
"@opendaw/studio-core-workers": "^0.0.96",
|
|
62
|
+
"@opendaw/studio-forge-boxes": "^0.0.85",
|
|
63
63
|
"@opendaw/typescript-config": "^0.0.29"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "ee79696d07f80c597f2a9dcbb2e2a4b61a50c7df"
|
|
66
66
|
}
|