@opendaw/studio-core 0.0.99 → 0.0.101
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/EffectFactories.d.ts.map +1 -1
- package/dist/EffectFactories.js +39 -24
- package/dist/Engine.d.ts +2 -0
- package/dist/Engine.d.ts.map +1 -1
- package/dist/EngineFacade.d.ts +2 -0
- package/dist/EngineFacade.d.ts.map +1 -1
- package/dist/EngineFacade.js +3 -0
- package/dist/EngineWorklet.d.ts +2 -0
- package/dist/EngineWorklet.d.ts.map +1 -1
- package/dist/EngineWorklet.js +10 -2
- package/dist/HRClockWorker.d.ts +7 -0
- package/dist/HRClockWorker.d.ts.map +1 -0
- package/dist/HRClockWorker.js +54 -0
- package/dist/OfflineEngineRenderer.d.ts.map +1 -1
- package/dist/OfflineEngineRenderer.js +5 -2
- package/dist/RecordingWorklet.d.ts +2 -1
- package/dist/RecordingWorklet.d.ts.map +1 -1
- package/dist/RecordingWorklet.js +9 -1
- package/dist/Storage.d.ts.map +1 -1
- package/dist/Storage.js +1 -0
- package/dist/StudioPreferences.d.ts +8 -0
- package/dist/StudioPreferences.d.ts.map +1 -1
- package/dist/StudioSettings.d.ts +13 -0
- package/dist/StudioSettings.d.ts.map +1 -1
- package/dist/StudioSettings.js +15 -0
- package/dist/capture/CaptureAudio.d.ts.map +1 -1
- package/dist/capture/CaptureAudio.js +8 -11
- package/dist/capture/RecordAudio.d.ts.map +1 -1
- package/dist/capture/RecordAudio.js +1 -0
- package/dist/processors.js +24 -24
- package/dist/processors.js.map +4 -4
- package/dist/project/Project.d.ts +6 -1
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +34 -2
- package/dist/project/ProjectApi.d.ts.map +1 -1
- package/dist/project/ProjectApi.js +14 -3
- package/dist/project/audio/AudioContentFactory.d.ts +5 -0
- package/dist/project/audio/AudioContentFactory.d.ts.map +1 -1
- package/dist/project/audio/AudioContentFactory.js +13 -0
- package/dist/ui/{generic → clipboard}/ClipboardManager.d.ts +3 -3
- package/dist/ui/clipboard/ClipboardManager.d.ts.map +1 -0
- package/dist/ui/{generic → clipboard}/ClipboardManager.js +70 -14
- package/dist/ui/clipboard/ClipboardUtils.d.ts +12 -0
- package/dist/ui/clipboard/ClipboardUtils.d.ts.map +1 -0
- package/dist/ui/clipboard/ClipboardUtils.js +94 -0
- package/dist/ui/{generic → clipboard}/ContextMenu.d.ts +1 -1
- package/dist/ui/clipboard/ContextMenu.d.ts.map +1 -0
- package/dist/ui/{generic → clipboard}/ContextMenu.js +1 -1
- package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.d.ts +18 -0
- package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.d.ts.map +1 -0
- package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.js +215 -0
- package/dist/ui/clipboard/types/DevicesClipboardHandler.d.ts +18 -0
- package/dist/ui/clipboard/types/DevicesClipboardHandler.d.ts.map +1 -0
- package/dist/ui/clipboard/types/DevicesClipboardHandler.js +188 -0
- package/dist/ui/clipboard/types/NotesClipboardHandler.d.ts +21 -0
- package/dist/ui/clipboard/types/NotesClipboardHandler.d.ts.map +1 -0
- package/dist/ui/clipboard/types/NotesClipboardHandler.js +72 -0
- package/dist/ui/clipboard/types/RegionsClipboardHandler.d.ts +24 -0
- package/dist/ui/clipboard/types/RegionsClipboardHandler.d.ts.map +1 -0
- package/dist/ui/clipboard/types/RegionsClipboardHandler.js +137 -0
- package/dist/ui/clipboard/types/ValuesClipboardHandler.d.ts +22 -0
- package/dist/ui/clipboard/types/ValuesClipboardHandler.d.ts.map +1 -0
- package/dist/ui/clipboard/types/ValuesClipboardHandler.js +135 -0
- package/dist/ui/index.d.ts +14 -3
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +14 -3
- package/dist/ui/menu/MenuItems.d.ts.map +1 -0
- package/dist/ui/timeline/RegionClipResolver.d.ts +5 -1
- package/dist/ui/timeline/RegionClipResolver.d.ts.map +1 -1
- package/dist/ui/timeline/RegionClipResolver.js +5 -1
- package/dist/ui/timeline/RegionKeepExistingResolver.d.ts +34 -0
- package/dist/ui/timeline/RegionKeepExistingResolver.d.ts.map +1 -0
- package/dist/ui/timeline/RegionKeepExistingResolver.js +171 -0
- package/dist/ui/timeline/RegionOverlapResolver.d.ts +33 -0
- package/dist/ui/timeline/RegionOverlapResolver.d.ts.map +1 -0
- package/dist/ui/timeline/RegionOverlapResolver.js +79 -0
- package/dist/ui/timeline/RegionPushExistingResolver.d.ts +31 -0
- package/dist/ui/timeline/RegionPushExistingResolver.d.ts.map +1 -0
- package/dist/ui/timeline/RegionPushExistingResolver.js +159 -0
- package/dist/ui/timeline/TimelineFocus.d.ts +14 -0
- package/dist/ui/timeline/TimelineFocus.d.ts.map +1 -0
- package/dist/ui/timeline/TimelineFocus.js +45 -0
- package/dist/ui/timeline/TrackResolver.d.ts +11 -0
- package/dist/ui/timeline/TrackResolver.d.ts.map +1 -0
- package/dist/ui/timeline/TrackResolver.js +5 -0
- package/package.json +62 -61
- package/dist/ui/generic/ClipboardManager.d.ts.map +0 -1
- package/dist/ui/generic/ContextMenu.d.ts.map +0 -1
- package/dist/ui/generic/MenuItems.d.ts.map +0 -1
- /package/dist/ui/{generic → menu}/MenuItems.d.ts +0 -0
- /package/dist/ui/{generic → menu}/MenuItems.js +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Func, Procedure, Terminable, TerminableOwner, Terminator, UUID } from "@opendaw/lib-std";
|
|
2
2
|
import { BoxEditing, BoxGraph } from "@opendaw/lib-box";
|
|
3
3
|
import { AudioBusBox, AudioUnitBox, BoxIO, RootBox, TimelineBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
|
4
|
-
import { BoxAdapters, BoxAdaptersContext, ClipSequencing, ParameterFieldAdapters, ProcessorOptions, ProjectSkeleton, RootBoxAdapter, SampleLoaderManager, SoundfontLoaderManager, TimelineBoxAdapter, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
|
|
4
|
+
import { BoxAdapters, BoxAdaptersContext, ClipSequencing, DeviceBoxAdapter, FilteredSelection, ParameterFieldAdapters, ProcessorOptions, ProjectSkeleton, RootBoxAdapter, SampleLoaderManager, SoundfontLoaderManager, TimelineBoxAdapter, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
|
|
5
5
|
import { LiveStreamBroadcaster, LiveStreamReceiver } from "@opendaw/lib-fusion";
|
|
6
6
|
import { ProjectEnv } from "./ProjectEnv";
|
|
7
7
|
import { Mixer } from "../Mixer";
|
|
@@ -11,6 +11,7 @@ import { EngineFacade } from "../EngineFacade";
|
|
|
11
11
|
import { EngineWorklet } from "../EngineWorklet";
|
|
12
12
|
import { MIDILearning } from "../midi";
|
|
13
13
|
import { ppqn, TempoMap } from "@opendaw/lib-dsp";
|
|
14
|
+
import { RegionOverlapResolver, TimelineFocus } from "../ui";
|
|
14
15
|
export type RestartWorklet = {
|
|
15
16
|
unload: Func<unknown, Promise<unknown>>;
|
|
16
17
|
load: Procedure<EngineWorklet>;
|
|
@@ -34,6 +35,7 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
|
|
|
34
35
|
readonly captureDevices: CaptureDevices;
|
|
35
36
|
readonly editing: BoxEditing;
|
|
36
37
|
readonly selection: VertexSelection;
|
|
38
|
+
readonly deviceSelection: FilteredSelection<DeviceBoxAdapter>;
|
|
37
39
|
readonly boxAdapters: BoxAdapters;
|
|
38
40
|
readonly userEditingManager: UserEditingManager;
|
|
39
41
|
readonly parameterFieldAdapters: ParameterFieldAdapters;
|
|
@@ -41,6 +43,8 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
|
|
|
41
43
|
readonly midiLearning: MIDILearning;
|
|
42
44
|
readonly mixer: Mixer;
|
|
43
45
|
readonly tempoMap: TempoMap;
|
|
46
|
+
readonly overlapResolver: RegionOverlapResolver;
|
|
47
|
+
readonly timelineFocus: TimelineFocus;
|
|
44
48
|
readonly engine: EngineFacade;
|
|
45
49
|
private constructor();
|
|
46
50
|
startAudioWorklet(restart?: RestartWorklet, options?: ProcessorOptions): EngineWorklet;
|
|
@@ -66,6 +70,7 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
|
|
|
66
70
|
copy(env?: Partial<ProjectEnv>): Project;
|
|
67
71
|
invalid(): boolean;
|
|
68
72
|
lastRegionAction(): ppqn;
|
|
73
|
+
trackUserCreatedSample(uuid: UUID.Bytes): void;
|
|
69
74
|
terminate(): void;
|
|
70
75
|
}
|
|
71
76
|
//# sourceMappingURL=Project.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,IAAI,EAGJ,SAAS,
|
|
1
|
+
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"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"}
|
package/dist/project/Project.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Arrays, isDefined, panic, safeExecute, Terminator, UUID } from "@opendaw/lib-std";
|
|
1
|
+
import { Arrays, isDefined, panic, RuntimeNotifier, safeExecute, Terminator, UUID } from "@opendaw/lib-std";
|
|
2
2
|
import { BoxEditing, DeleteUpdate, NewUpdate } from "@opendaw/lib-box";
|
|
3
3
|
import { AudioFileBox, AudioRegionBox } from "@opendaw/studio-boxes";
|
|
4
|
-
import { BoxAdapters, ParameterFieldAdapters, ProjectSkeleton, RootBoxAdapter, TimelineBoxAdapter, UnionBoxTypes, UserEditingManager, VaryingTempoMap, VertexSelection } from "@opendaw/studio-adapters";
|
|
4
|
+
import { BoxAdapters, DeviceBoxUtils, Devices, isVertexOfBox, ParameterFieldAdapters, ProjectSkeleton, RootBoxAdapter, TimelineBoxAdapter, UnionBoxTypes, UserEditingManager, VaryingTempoMap, VertexSelection } from "@opendaw/studio-adapters";
|
|
5
5
|
import { LiveStreamReceiver } from "@opendaw/lib-fusion";
|
|
6
6
|
import { Mixer } from "../Mixer";
|
|
7
7
|
import { ProjectApi } from "./ProjectApi";
|
|
@@ -13,6 +13,8 @@ import { ProjectValidation } from "./ProjectValidation";
|
|
|
13
13
|
import { TimeBase } from "@opendaw/lib-dsp";
|
|
14
14
|
import { MidiData } from "@opendaw/lib-midi";
|
|
15
15
|
import { StudioPreferences } from "../StudioPreferences";
|
|
16
|
+
import { RegionOverlapResolver, TimelineFocus } from "../ui";
|
|
17
|
+
import { SampleStorage } from "../samples/SampleStorage";
|
|
16
18
|
// Main Entry Point for a Project
|
|
17
19
|
export class Project {
|
|
18
20
|
static new(env, options) {
|
|
@@ -47,6 +49,7 @@ export class Project {
|
|
|
47
49
|
}
|
|
48
50
|
#terminator = new Terminator();
|
|
49
51
|
#sampleRegistrations;
|
|
52
|
+
#userCreatedSamples = UUID.newSet(uuid => uuid);
|
|
50
53
|
#env;
|
|
51
54
|
boxGraph;
|
|
52
55
|
rootBox;
|
|
@@ -58,6 +61,7 @@ export class Project {
|
|
|
58
61
|
captureDevices;
|
|
59
62
|
editing;
|
|
60
63
|
selection;
|
|
64
|
+
deviceSelection;
|
|
61
65
|
boxAdapters;
|
|
62
66
|
userEditingManager;
|
|
63
67
|
parameterFieldAdapters;
|
|
@@ -65,6 +69,8 @@ export class Project {
|
|
|
65
69
|
midiLearning;
|
|
66
70
|
mixer;
|
|
67
71
|
tempoMap;
|
|
72
|
+
overlapResolver;
|
|
73
|
+
timelineFocus;
|
|
68
74
|
engine = new EngineFacade();
|
|
69
75
|
constructor(env, boxGraph, { rootBox, userInterfaceBoxes, primaryAudioBus, primaryAudioOutputUnit, timelineBox }) {
|
|
70
76
|
this.#env = env;
|
|
@@ -79,12 +85,18 @@ export class Project {
|
|
|
79
85
|
this.selection = new VertexSelection(this.editing, this.boxGraph);
|
|
80
86
|
this.parameterFieldAdapters = new ParameterFieldAdapters();
|
|
81
87
|
this.boxAdapters = this.#terminator.own(new BoxAdapters(this));
|
|
88
|
+
this.deviceSelection = this.#terminator.own(this.selection.createFilteredSelection(isVertexOfBox(DeviceBoxUtils.isDeviceBox), {
|
|
89
|
+
fx: (adapter) => adapter.box,
|
|
90
|
+
fy: vertex => this.boxAdapters.adapterFor(vertex.box, Devices.isAny)
|
|
91
|
+
}));
|
|
82
92
|
this.tempoMap = new VaryingTempoMap(this.timelineBoxAdapter);
|
|
83
93
|
this.userEditingManager = new UserEditingManager(this.editing);
|
|
84
94
|
this.liveStreamReceiver = this.#terminator.own(new LiveStreamReceiver());
|
|
85
95
|
this.midiLearning = this.#terminator.own(new MIDILearning(this));
|
|
86
96
|
this.captureDevices = this.#terminator.own(new CaptureDevices(this));
|
|
87
97
|
this.mixer = new Mixer(this.rootBoxAdapter.audioUnits);
|
|
98
|
+
this.overlapResolver = new RegionOverlapResolver(this.editing, this.api, this.boxAdapters);
|
|
99
|
+
this.timelineFocus = this.#terminator.own(new TimelineFocus());
|
|
88
100
|
console.debug(`Project was created on ${this.rootBoxAdapter.created.toString()}`);
|
|
89
101
|
this.#sampleRegistrations = UUID.newSet(({ uuid }) => uuid);
|
|
90
102
|
for (const box of this.boxGraph.boxes()) {
|
|
@@ -99,6 +111,7 @@ export class Project {
|
|
|
99
111
|
}
|
|
100
112
|
else if (update instanceof DeleteUpdate && update.name === AudioFileBox.ClassName) {
|
|
101
113
|
this.#unregisterSample(update.uuid);
|
|
114
|
+
this.#deleteUserCreatedSample(update.uuid);
|
|
102
115
|
}
|
|
103
116
|
}
|
|
104
117
|
}));
|
|
@@ -227,6 +240,9 @@ export class Project {
|
|
|
227
240
|
.map(trackAdapter => trackAdapter.regions.collection.asArray().at(-1)))
|
|
228
241
|
.filter(isDefined).reduce((position, region) => Math.max(position, region.complete), 0);
|
|
229
242
|
}
|
|
243
|
+
trackUserCreatedSample(uuid) {
|
|
244
|
+
this.#userCreatedSamples.add(uuid);
|
|
245
|
+
}
|
|
230
246
|
terminate() {
|
|
231
247
|
this.#sampleRegistrations.forEach(({ terminable }) => terminable.terminate());
|
|
232
248
|
this.#sampleRegistrations.clear();
|
|
@@ -239,4 +255,20 @@ export class Project {
|
|
|
239
255
|
#unregisterSample(uuid) {
|
|
240
256
|
this.#sampleRegistrations.removeByKey(uuid).terminable.terminate();
|
|
241
257
|
}
|
|
258
|
+
async #deleteUserCreatedSample(uuid) {
|
|
259
|
+
if (!this.#userCreatedSamples.hasKey(uuid)) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
this.#userCreatedSamples.removeByKey(uuid);
|
|
263
|
+
const autoDelete = StudioPreferences.settings.storage["auto-delete-orphaned-samples"];
|
|
264
|
+
if (!autoDelete && !await RuntimeNotifier.approve({
|
|
265
|
+
headline: "Delete Sample?",
|
|
266
|
+
message: "The sample is no longer used. Delete it from storage? This cannot be undone!",
|
|
267
|
+
approveText: "Delete",
|
|
268
|
+
cancelText: "Keep"
|
|
269
|
+
})) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
SampleStorage.get().deleteItem(uuid).catch((reason) => console.warn("Failed to delete sample from storage", reason));
|
|
273
|
+
}
|
|
242
274
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectApi.d.ts","sourceRoot":"","sources":["../../src/project/ProjectApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,OAAO,EAGP,KAAK,EACL,GAAG,EAIH,QAAQ,EACR,MAAM,EAIN,YAAY,EAEf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,IAAI,EAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAW,KAAK,EAAc,YAAY,EAAC,MAAM,kBAAkB,CAAA;AAC1E,OAAO,EAAgB,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EACH,YAAY,EACZ,cAAc,EACd,YAAY,EAGZ,WAAW,EACX,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,QAAQ,EACR,YAAY,EAEZ,cAAc,EACjB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACH,mBAAmB,EACnB,mBAAmB,EAInB,iBAAiB,EACjB,gCAAgC,EAChC,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EAGpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAC,SAAS,EAAC,MAAM,cAAc,CAAA;AACtC,OAAO,EAAC,mBAAmB,EAAC,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"ProjectApi.d.ts","sourceRoot":"","sources":["../../src/project/ProjectApi.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,6 @@ import { AudioUnitType } from "@opendaw/studio-enums";
|
|
|
5
5
|
import { AudioUnitBox, CaptureAudioBox, CaptureMidiBox, NoteClipBox, NoteEventBox, NoteEventCollectionBox, NoteRegionBox, TrackBox, ValueClipBox, ValueEventCollectionBox, ValueRegionBox } from "@opendaw/studio-boxes";
|
|
6
6
|
import { AudioUnitFactory, ColorCodes, ProjectQueries, TrackType } from "@opendaw/studio-adapters";
|
|
7
7
|
import { AudioContentFactory } from "./audio";
|
|
8
|
-
import { RegionClipResolver } from "../ui";
|
|
9
8
|
// noinspection JSUnusedGlobalSymbols
|
|
10
9
|
export class ProjectApi {
|
|
11
10
|
#project;
|
|
@@ -111,10 +110,22 @@ export class ProjectApi {
|
|
|
111
110
|
});
|
|
112
111
|
}
|
|
113
112
|
duplicateRegion(region) {
|
|
113
|
+
const track = region.trackBoxAdapter.unwrap("Region is invalid");
|
|
114
114
|
const clearFrom = region.position + region.duration;
|
|
115
115
|
const clearTo = region.complete + region.duration;
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
// Resolve target track (for keep-existing mode)
|
|
117
|
+
const targetTrack = this.#project.overlapResolver.resolveTargetTrack(track, clearFrom, clearTo);
|
|
118
|
+
// Capture overlap state before creating (for clip/push-existing modes)
|
|
119
|
+
const solver = this.#project.overlapResolver.fromRange(targetTrack, clearFrom, clearTo);
|
|
120
|
+
// Create the duplicate on target track
|
|
121
|
+
const duplicate = region.copyTo({
|
|
122
|
+
position: region.complete,
|
|
123
|
+
consolidate: true,
|
|
124
|
+
track: targetTrack !== track ? targetTrack.box.regions : undefined
|
|
125
|
+
});
|
|
126
|
+
// Apply overlap resolution
|
|
127
|
+
solver();
|
|
128
|
+
return duplicate;
|
|
118
129
|
}
|
|
119
130
|
quantiseNotes(collection, { positionQuantisation, durationQuantisation }) {
|
|
120
131
|
if (isAbsent(positionQuantisation) && isAbsent(durationQuantisation)) {
|
|
@@ -29,6 +29,11 @@ export declare namespace AudioContentFactory {
|
|
|
29
29
|
} & Props;
|
|
30
30
|
type PitchStretchedProps = {} & Props;
|
|
31
31
|
type NotStretchedProps = {} & Props;
|
|
32
|
+
/**
|
|
33
|
+
* Calculates the duration of an audio region based on sample properties.
|
|
34
|
+
* Returns duration in PPQN for stretched regions, or in seconds for non-stretched.
|
|
35
|
+
*/
|
|
36
|
+
const calculateDuration: (sample: Sample) => ppqn;
|
|
32
37
|
const createTimeStretchedRegion: (props: TimeStretchedProps & Region) => AudioRegionBox;
|
|
33
38
|
const createPitchStretchedRegion: (props: PitchStretchedProps & Region) => AudioRegionBox;
|
|
34
39
|
const createNotStretchedRegion: (props: NotStretchedProps & Region) => AudioRegionBox;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioContentFactory.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAiB,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAa,MAAM,EAAY,MAAM,0BAA0B,CAAA;AACtE,OAAO,EAAC,GAAG,EAAuC,MAAM,kBAAkB,CAAA;AAC1E,OAAO,EACH,YAAY,EACZ,YAAY,EAEZ,cAAc,EAEd,QAAQ,EAEX,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAEzC,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AAEvD,yBAAiB,mBAAmB,CAAC;IACjC,KAAY,KAAK,GAAG;QAChB,QAAQ,EAAE,QAAQ,CAAA;QAClB,WAAW,EAAE,QAAQ,CAAA;QACrB,YAAY,EAAE,YAAY,CAAA;QAC1B,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;QACxB,WAAW,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;QAC/C,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IAED,KAAY,IAAI,GAAG,KAAK,GAAG;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,CAAA;IACzC,KAAY,MAAM,GAAG,KAAK,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAE9D,KAAY,kBAAkB,GAAG;QAC7B,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;QACrC,YAAY,CAAC,EAAE,MAAM,CAAA;KACxB,GAAG,KAAK,CAAA;IAET,KAAY,mBAAmB,GAAG,EAA0C,GAAG,KAAK,CAAA;IAEpF,KAAY,iBAAiB,GAAG,EAA0C,GAAG,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"AudioContentFactory.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAiB,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAa,MAAM,EAAY,MAAM,0BAA0B,CAAA;AACtE,OAAO,EAAC,GAAG,EAAuC,MAAM,kBAAkB,CAAA;AAC1E,OAAO,EACH,YAAY,EACZ,YAAY,EAEZ,cAAc,EAEd,QAAQ,EAEX,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAEzC,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AAEvD,yBAAiB,mBAAmB,CAAC;IACjC,KAAY,KAAK,GAAG;QAChB,QAAQ,EAAE,QAAQ,CAAA;QAClB,WAAW,EAAE,QAAQ,CAAA;QACrB,YAAY,EAAE,YAAY,CAAA;QAC1B,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;QACxB,WAAW,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;QAC/C,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IAED,KAAY,IAAI,GAAG,KAAK,GAAG;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,CAAA;IACzC,KAAY,MAAM,GAAG,KAAK,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAE9D,KAAY,kBAAkB,GAAG;QAC7B,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;QACrC,YAAY,CAAC,EAAE,MAAM,CAAA;KACxB,GAAG,KAAK,CAAA;IAET,KAAY,mBAAmB,GAAG,EAA0C,GAAG,KAAK,CAAA;IAEpF,KAAY,iBAAiB,GAAG,EAA0C,GAAG,KAAK,CAAA;IAElF;;;OAGG;IACI,MAAM,iBAAiB,GAAI,QAAQ,MAAM,KAAG,IAQlD,CAAA;IAIM,MAAM,yBAAyB,GAAI,OAAO,kBAAkB,GAAG,MAAM,KAAG,cAM9E,CAAA;IAEM,MAAM,0BAA0B,GAAI,OAAO,mBAAmB,GAAG,MAAM,KAAG,cAEhF,CAAA;IAEM,MAAM,wBAAwB,GAAI,OAAO,iBAAiB,GAAG,MAAM,KAAG,cAgB5E,CAAA;IAIM,MAAM,uBAAuB,GAAI,OAAO,kBAAkB,GAAG,IAAI,KAAG,YAM1E,CAAA;IAEM,MAAM,wBAAwB,GAAI,OAAO,mBAAmB,GAAG,IAAI,KAAG,YAG5E,CAAA;IAEM,MAAM,sBAAsB,GAAI,OAAO,iBAAiB,GAAG,IAAI,KAAG,YAcxE,CAAA;CA6DJ"}
|
|
@@ -6,6 +6,19 @@ import { TransientPlayMode } from "@opendaw/studio-enums";
|
|
|
6
6
|
import { AudioContentHelpers } from "./AudioContentHelpers";
|
|
7
7
|
export var AudioContentFactory;
|
|
8
8
|
(function (AudioContentFactory) {
|
|
9
|
+
/**
|
|
10
|
+
* Calculates the duration of an audio region based on sample properties.
|
|
11
|
+
* Returns duration in PPQN for stretched regions, or in seconds for non-stretched.
|
|
12
|
+
*/
|
|
13
|
+
AudioContentFactory.calculateDuration = (sample) => {
|
|
14
|
+
const { duration: durationInSeconds, bpm } = sample;
|
|
15
|
+
if (bpm === 0) {
|
|
16
|
+
// Non-stretched: duration is in seconds
|
|
17
|
+
return durationInSeconds;
|
|
18
|
+
}
|
|
19
|
+
// Stretched: duration is in PPQN
|
|
20
|
+
return quantizeCeil(PPQN.secondsToPulses(durationInSeconds, bpm), PPQN.SemiQuaver);
|
|
21
|
+
};
|
|
9
22
|
// --- Region Creation --- //
|
|
10
23
|
AudioContentFactory.createTimeStretchedRegion = (props) => {
|
|
11
24
|
const { boxGraph, playbackRate, transientPlayMode } = props;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Client,
|
|
2
|
-
export type ClipboardEntry<T extends string = string
|
|
1
|
+
import { Client, Option, Subscription } from "@opendaw/lib-std";
|
|
2
|
+
export type ClipboardEntry<T extends string = string> = {
|
|
3
3
|
readonly type: T;
|
|
4
|
-
readonly data:
|
|
4
|
+
readonly data: ArrayBufferLike;
|
|
5
5
|
};
|
|
6
6
|
export interface ClipboardHandler<E extends ClipboardEntry> {
|
|
7
7
|
canCopy(client: Client): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClipboardManager.d.ts","sourceRoot":"","sources":["../../../src/ui/clipboard/ClipboardManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAa,MAAM,kBAAkB,CAAA;AASzE,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;IACpD,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CACjC,CAAA;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,cAAc;IACtD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;IAChC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;IACxD,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,CAAA;IACjB,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,CAAA;IAChB,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAA;CACrC;AAED,yBAAiB,gBAAgB,CAAC;IAC9B,KAAK,QAAQ,GAAG,cAAc,CAAA;IA0B9B,MAAM,CAAC,MAAM,OAAO,GAAI,CAAC,SAAS,QAAQ,EAAE,SAAS,WAAW,EAAE,SAAS,gBAAgB,CAAC,CAAC,CAAC,KAAG,YA0FhG,CAAA;;CACJ"}
|
|
@@ -1,15 +1,41 @@
|
|
|
1
1
|
import { Option, Terminable } from "@opendaw/lib-std";
|
|
2
2
|
import { Events, ReservedShortcuts } from "@opendaw/lib-dom";
|
|
3
3
|
import { ContextMenu } from "./ContextMenu";
|
|
4
|
-
import { MenuItem } from "
|
|
5
|
-
|
|
4
|
+
import { MenuItem } from "../menu/MenuItems";
|
|
5
|
+
import { StudioPreferences } from "../../StudioPreferences";
|
|
6
|
+
const CLIPBOARD_HEADER = "OPENDAW";
|
|
7
|
+
const CLIPBOARD_VERSION = 2;
|
|
6
8
|
export var ClipboardManager;
|
|
7
9
|
(function (ClipboardManager) {
|
|
8
10
|
let fallbackEntry = Option.None;
|
|
9
|
-
const encode = (entry) =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const encode = (entry) => {
|
|
12
|
+
const bytes = new Uint8Array(entry.data);
|
|
13
|
+
let binary = "";
|
|
14
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
15
|
+
binary += String.fromCharCode(bytes[i]);
|
|
16
|
+
}
|
|
17
|
+
return `${CLIPBOARD_HEADER}:${CLIPBOARD_VERSION}:${entry.type}:${btoa(binary)}`;
|
|
18
|
+
};
|
|
19
|
+
const decode = (text) => {
|
|
20
|
+
const parts = text.split(":");
|
|
21
|
+
if (parts.length < 4 || parts[0] !== CLIPBOARD_HEADER) {
|
|
22
|
+
return Option.None;
|
|
23
|
+
}
|
|
24
|
+
const version = parseInt(parts[1], 10);
|
|
25
|
+
if (version !== CLIPBOARD_VERSION) {
|
|
26
|
+
return Option.None;
|
|
27
|
+
}
|
|
28
|
+
return Option.tryCatch(() => {
|
|
29
|
+
const type = parts[2];
|
|
30
|
+
const base64 = parts.slice(3).join(":");
|
|
31
|
+
const binary = atob(base64);
|
|
32
|
+
const bytes = new Uint8Array(binary.length);
|
|
33
|
+
for (let i = 0; i < binary.length; i++) {
|
|
34
|
+
bytes[i] = binary.charCodeAt(i);
|
|
35
|
+
}
|
|
36
|
+
return { type, data: bytes.buffer };
|
|
37
|
+
});
|
|
38
|
+
};
|
|
13
39
|
ClipboardManager.install = (element, handler) => {
|
|
14
40
|
const writeEntry = (entry) => {
|
|
15
41
|
fallbackEntry = Option.wrap(entry);
|
|
@@ -18,28 +44,39 @@ export var ClipboardManager;
|
|
|
18
44
|
const performCopy = () => handler.copy().ifSome(writeEntry);
|
|
19
45
|
const performCut = () => handler.cut().ifSome(writeEntry);
|
|
20
46
|
const performPaste = async () => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
47
|
+
try {
|
|
48
|
+
const rawText = await navigator.clipboard.readText();
|
|
49
|
+
const text = Option.wrap(rawText);
|
|
50
|
+
const entry = text.flatMap(decode);
|
|
51
|
+
if (entry.nonEmpty()) {
|
|
52
|
+
handler.paste(entry.unwrap());
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
fallbackEntry.ifSome(entry => handler.paste(entry));
|
|
56
|
+
}
|
|
25
57
|
}
|
|
26
|
-
|
|
58
|
+
catch (_error) {
|
|
27
59
|
fallbackEntry.ifSome(entry => handler.paste(entry));
|
|
28
60
|
}
|
|
29
61
|
};
|
|
30
62
|
return Terminable.many(Events.subscribe(element, "copy", (event) => {
|
|
31
63
|
handler.copy().ifSome(entry => {
|
|
32
64
|
event.preventDefault();
|
|
65
|
+
const encoded = encode(entry);
|
|
33
66
|
fallbackEntry = Option.wrap(entry);
|
|
34
|
-
event.clipboardData?.setData("text/plain",
|
|
67
|
+
event.clipboardData?.setData("text/plain", encoded);
|
|
35
68
|
});
|
|
36
69
|
}), Events.subscribe(element, "cut", (event) => {
|
|
37
70
|
handler.cut().ifSome(entry => {
|
|
38
71
|
event.preventDefault();
|
|
72
|
+
const encoded = encode(entry);
|
|
39
73
|
fallbackEntry = Option.wrap(entry);
|
|
40
|
-
event.clipboardData?.setData("text/plain",
|
|
74
|
+
event.clipboardData?.setData("text/plain", encoded);
|
|
41
75
|
});
|
|
42
|
-
}), Events.subscribe(
|
|
76
|
+
}), Events.subscribe(document, "paste", (event) => {
|
|
77
|
+
if (!element.contains(document.activeElement) && document.activeElement !== document.body) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
43
80
|
const text = event.clipboardData?.getData("text/plain") ?? "";
|
|
44
81
|
const entry = decode(text);
|
|
45
82
|
if (entry.nonEmpty()) {
|
|
@@ -52,7 +89,26 @@ export var ClipboardManager;
|
|
|
52
89
|
handler.paste(entry);
|
|
53
90
|
});
|
|
54
91
|
}
|
|
92
|
+
}), Events.subscribe(document, "keydown", (event) => {
|
|
93
|
+
if (!element.contains(document.activeElement) && document.activeElement !== document.body) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const isMod = event.metaKey || event.ctrlKey;
|
|
97
|
+
if (!isMod || event.shiftKey || event.altKey) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (event.key === "c") {
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
performCopy();
|
|
103
|
+
}
|
|
104
|
+
else if (event.key === "x") {
|
|
105
|
+
event.preventDefault();
|
|
106
|
+
performCut();
|
|
107
|
+
}
|
|
55
108
|
}), ContextMenu.subscribe(element, async (collector) => {
|
|
109
|
+
if (!StudioPreferences.settings.editing["show-clipboard-menu"]) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
56
112
|
const { client } = collector;
|
|
57
113
|
const text = await Option.async(navigator.clipboard.readText());
|
|
58
114
|
const entry = text.flatMap(decode);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Predicate, Procedure } from "@opendaw/lib-std";
|
|
2
|
+
import { Box, BoxGraph, SpecialDecoder } from "@opendaw/lib-box";
|
|
3
|
+
export declare namespace ClipboardUtils {
|
|
4
|
+
const extractMetadata: (data: ArrayBufferLike) => ArrayBufferLike;
|
|
5
|
+
const serializeBoxes: (boxes: ReadonlyArray<Box>, metadata?: ArrayBufferLike) => ArrayBufferLike;
|
|
6
|
+
const deserializeBoxes: <T extends Box = Box>(data: ArrayBufferLike, targetGraph: BoxGraph, options: {
|
|
7
|
+
mapPointer: SpecialDecoder["map"];
|
|
8
|
+
modifyBox?: Procedure<T>;
|
|
9
|
+
excludeBox?: Predicate<Box>;
|
|
10
|
+
}) => ReadonlyArray<T>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=ClipboardUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClipboardUtils.d.ts","sourceRoot":"","sources":["../../../src/ui/clipboard/ClipboardUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,SAAS,EAAE,SAAS,EAAO,MAAM,kBAAkB,CAAA;AACpG,OAAO,EAAC,GAAG,EAAE,QAAQ,EAAgB,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAK5E,yBAAiB,cAAc,CAAC;IACrB,MAAM,eAAe,GAAI,MAAM,eAAe,KAAG,eAMvD,CAAA;IAEM,MAAM,cAAc,GAAI,OAAO,aAAa,CAAC,GAAG,CAAC,EACzB,WAAU,eAAoC,KAAG,eAsB/E,CAAA;IAEM,MAAM,gBAAgB,GAAI,CAAC,SAAS,GAAG,GAAG,GAAG,EAAE,MAAM,eAAe,EACrB,aAAa,QAAQ,EACrB,SAAS;QACL,UAAU,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;QACjC,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;QACxB,UAAU,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;KAC9B,KAAG,aAAa,CAAC,CAAC,CAkDxE,CAAA;CACJ"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ByteArrayInput, ByteArrayOutput, Option, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { BoxGraph, PointerField } from "@opendaw/lib-box";
|
|
3
|
+
import { BoxIO } from "@opendaw/studio-boxes";
|
|
4
|
+
export var ClipboardUtils;
|
|
5
|
+
(function (ClipboardUtils) {
|
|
6
|
+
ClipboardUtils.extractMetadata = (data) => {
|
|
7
|
+
const input = new ByteArrayInput(data);
|
|
8
|
+
const metadataLength = input.readInt();
|
|
9
|
+
const metadataBytes = new Int8Array(metadataLength);
|
|
10
|
+
input.readBytes(metadataBytes);
|
|
11
|
+
return metadataBytes.buffer;
|
|
12
|
+
};
|
|
13
|
+
ClipboardUtils.serializeBoxes = (boxes, metadata = new ArrayBuffer(0)) => {
|
|
14
|
+
const uniqueBoxes = UUID.newSet(box => box.address.uuid);
|
|
15
|
+
boxes.forEach(box => uniqueBoxes.add(box));
|
|
16
|
+
const typeCounts = new Map();
|
|
17
|
+
uniqueBoxes.forEach(box => typeCounts.set(box.name, (typeCounts.get(box.name) ?? 0) + 1));
|
|
18
|
+
const types = [...typeCounts.entries()].map(([type, count]) => `${type}: ${count}`).join(", ");
|
|
19
|
+
const clipboardGraph = new BoxGraph(Option.wrap(BoxIO.create));
|
|
20
|
+
clipboardGraph.beginTransaction();
|
|
21
|
+
uniqueBoxes.forEach(sourceBox => {
|
|
22
|
+
const input = new ByteArrayInput(sourceBox.toArrayBuffer());
|
|
23
|
+
clipboardGraph.createBox(sourceBox.name, sourceBox.address.uuid, box => box.read(input));
|
|
24
|
+
});
|
|
25
|
+
clipboardGraph.endTransaction();
|
|
26
|
+
const graphData = clipboardGraph.toArrayBuffer();
|
|
27
|
+
const output = ByteArrayOutput.create();
|
|
28
|
+
output.writeInt(metadata.byteLength);
|
|
29
|
+
output.writeBytes(new Int8Array(metadata));
|
|
30
|
+
output.writeInt(graphData.byteLength);
|
|
31
|
+
output.writeBytes(new Int8Array(graphData));
|
|
32
|
+
const arrayBuffer = output.toArrayBuffer();
|
|
33
|
+
console.debug(`Clipboard copy (${arrayBuffer.byteLength >> 10}kB): ${types}`);
|
|
34
|
+
return arrayBuffer;
|
|
35
|
+
};
|
|
36
|
+
ClipboardUtils.deserializeBoxes = (data, targetGraph, options) => {
|
|
37
|
+
const input = new ByteArrayInput(data);
|
|
38
|
+
input.skip(input.readInt());
|
|
39
|
+
const graphDataLength = input.readInt();
|
|
40
|
+
const graphData = new Int8Array(graphDataLength);
|
|
41
|
+
input.readBytes(graphData);
|
|
42
|
+
const clipboardGraph = new BoxGraph(Option.wrap(BoxIO.create));
|
|
43
|
+
clipboardGraph.fromArrayBuffer(graphData.buffer);
|
|
44
|
+
const skippedExternalUuids = UUID.newSet(uuid => uuid);
|
|
45
|
+
clipboardGraph.boxes().forEach(box => {
|
|
46
|
+
if (box.resource === "external" && targetGraph.findBox(box.address.uuid).nonEmpty()) {
|
|
47
|
+
skippedExternalUuids.add(box.address.uuid);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
const shouldSkipBox = (box) => {
|
|
51
|
+
if (options.excludeBox?.(box)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
if (box.resource === "external" && skippedExternalUuids.hasKey(box.address.uuid)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
for (const [, targetAddress] of box.outgoingEdges()) {
|
|
58
|
+
if (skippedExternalUuids.hasKey(targetAddress.uuid) && !targetAddress.isBox()) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
};
|
|
64
|
+
const sourceBoxes = clipboardGraph.boxes().filter(box => !shouldSkipBox(box));
|
|
65
|
+
const typeCounts = new Map();
|
|
66
|
+
sourceBoxes.forEach(box => typeCounts.set(box.name, (typeCounts.get(box.name) ?? 0) + 1));
|
|
67
|
+
console.debug("Clipboard paste:", [...typeCounts.entries()].map(([type, count]) => `${type}: ${count}`).join(", "));
|
|
68
|
+
const uuidMap = UUID.newSet(({ source }) => source);
|
|
69
|
+
sourceBoxes.forEach(box => {
|
|
70
|
+
const isExternal = box.resource === "external";
|
|
71
|
+
uuidMap.add({ source: box.address.uuid, target: isExternal ? box.address.uuid : UUID.generate() });
|
|
72
|
+
});
|
|
73
|
+
skippedExternalUuids.forEach(uuid => uuidMap.add({ source: uuid, target: uuid }));
|
|
74
|
+
const result = [];
|
|
75
|
+
PointerField.decodeWith({
|
|
76
|
+
map: (pointer, address) => {
|
|
77
|
+
const remappedInternal = address.flatMap(addr => uuidMap.opt(addr.uuid).map(({ target }) => addr.moveTo(target)));
|
|
78
|
+
if (remappedInternal.nonEmpty()) {
|
|
79
|
+
return remappedInternal;
|
|
80
|
+
}
|
|
81
|
+
return options.mapPointer(pointer, address);
|
|
82
|
+
}
|
|
83
|
+
}, () => sourceBoxes.forEach(sourceBox => {
|
|
84
|
+
const inputStream = new ByteArrayInput(sourceBox.toArrayBuffer());
|
|
85
|
+
const targetUuid = uuidMap.get(sourceBox.address.uuid).target;
|
|
86
|
+
targetGraph.createBox(sourceBox.name, targetUuid, box => {
|
|
87
|
+
box.read(inputStream);
|
|
88
|
+
options.modifyBox?.(box);
|
|
89
|
+
result.push(box);
|
|
90
|
+
});
|
|
91
|
+
}));
|
|
92
|
+
return result;
|
|
93
|
+
};
|
|
94
|
+
})(ClipboardUtils || (ClipboardUtils = {}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Client, Subscription } from "@opendaw/lib-std";
|
|
2
|
-
import { MenuItem } from "
|
|
2
|
+
import { MenuItem } from "../menu/MenuItems";
|
|
3
3
|
export declare namespace ContextMenu {
|
|
4
4
|
const CONTEXT_MENU_EVENT_TYPE: "--context-menu";
|
|
5
5
|
type MenuFactory = (menuItem: MenuItem, client: Client) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContextMenu.d.ts","sourceRoot":"","sources":["../../../src/ui/clipboard/ContextMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAU,YAAY,EAAC,MAAM,kBAAkB,CAAA;AAE7D,OAAO,EAAC,QAAQ,EAAe,MAAM,mBAAmB,CAAA;AAExD,yBAAiB,WAAW,CAAC;IAClB,MAAM,uBAAuB,EAAG,gBAAyB,CAAA;IAEhE,KAAY,WAAW,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAEtE,UAAiB,SAAS;QACtB,QAAQ,CAAC,GAAG,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAA;QAEpC,IAAI,MAAM,IAAI,MAAM,CAAA;KACvB;IAqCM,MAAM,OAAO,GAAI,OAAO,WAAW,EAAE,aAAa,WAAW,KAAG,YAkBhD,CAAA;IAEhB,MAAM,SAAS,GAAI,QAAQ,WAAW,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,KAAG,YAI/D,CAAA;CAChC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Option } from "@opendaw/lib-std";
|
|
2
2
|
import { Events } from "@opendaw/lib-dom";
|
|
3
|
-
import { MenuItem } from "
|
|
3
|
+
import { MenuItem } from "../menu/MenuItems";
|
|
4
4
|
export var ContextMenu;
|
|
5
5
|
(function (ContextMenu) {
|
|
6
6
|
ContextMenu.CONTEXT_MENU_EVENT_TYPE = "--context-menu";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Option, Provider } from "@opendaw/lib-std";
|
|
2
|
+
import { BoxEditing, BoxGraph } from "@opendaw/lib-box";
|
|
3
|
+
import { AudioUnitBoxAdapter, RootBoxAdapter, UserEditing } from "@opendaw/studio-adapters";
|
|
4
|
+
import { ClipboardEntry, ClipboardHandler } from "../ClipboardManager";
|
|
5
|
+
type ClipboardAudioUnits = ClipboardEntry<"audio-units">;
|
|
6
|
+
export declare namespace AudioUnitsClipboard {
|
|
7
|
+
type Context = {
|
|
8
|
+
readonly getEnabled: Provider<boolean>;
|
|
9
|
+
readonly editing: BoxEditing;
|
|
10
|
+
readonly boxGraph: BoxGraph;
|
|
11
|
+
readonly rootBoxAdapter: RootBoxAdapter;
|
|
12
|
+
readonly audioUnitEditing: UserEditing;
|
|
13
|
+
readonly getEditedAudioUnit: Provider<Option<AudioUnitBoxAdapter>>;
|
|
14
|
+
};
|
|
15
|
+
const createHandler: ({ getEnabled, editing, boxGraph, rootBoxAdapter, audioUnitEditing, getEditedAudioUnit }: Context) => ClipboardHandler<ClipboardAudioUnits>;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=AudioUnitsClipboardHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioUnitsClipboardHandler.d.ts","sourceRoot":"","sources":["../../../../src/ui/clipboard/types/AudioUnitsClipboardHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,MAAM,EAAE,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAClF,OAAO,EAAM,UAAU,EAAE,QAAQ,EAAa,MAAM,kBAAkB,CAAA;AAWtE,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,UAAU,CAAA;QAC5B,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;CA6GJ"}
|