@opendaw/studio-core 0.0.83 → 0.0.85

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.
Files changed (70) hide show
  1. package/dist/EffectFactories.d.ts +0 -2
  2. package/dist/EffectFactories.d.ts.map +1 -1
  3. package/dist/EffectFactories.js +1 -1
  4. package/dist/Engine.d.ts +2 -1
  5. package/dist/Engine.d.ts.map +1 -1
  6. package/dist/EngineFacade.d.ts +2 -1
  7. package/dist/EngineFacade.d.ts.map +1 -1
  8. package/dist/EngineFacade.js +3 -1
  9. package/dist/EngineWorklet.d.ts +2 -1
  10. package/dist/EngineWorklet.d.ts.map +1 -1
  11. package/dist/EngineWorklet.js +5 -2
  12. package/dist/ExternalLib.d.ts +3 -2
  13. package/dist/ExternalLib.d.ts.map +1 -1
  14. package/dist/ExternalLib.js +2 -2
  15. package/dist/Preferences.d.ts +6 -0
  16. package/dist/Preferences.d.ts.map +1 -1
  17. package/dist/Preferences.js +5 -2
  18. package/dist/Storage.d.ts.map +1 -1
  19. package/dist/Storage.js +14 -5
  20. package/dist/capture/Capture.d.ts +4 -1
  21. package/dist/capture/Capture.d.ts.map +1 -1
  22. package/dist/capture/Capture.js +4 -0
  23. package/dist/capture/CaptureDevices.js +1 -1
  24. package/dist/capture/RecordAudio.d.ts.map +1 -1
  25. package/dist/capture/RecordAudio.js +20 -10
  26. package/dist/capture/RecordMidi.d.ts.map +1 -1
  27. package/dist/capture/RecordMidi.js +1 -0
  28. package/dist/capture/Recording.d.ts.map +1 -1
  29. package/dist/capture/Recording.js +1 -0
  30. package/dist/dawproject/BuiltinDevices.d.ts +1 -1
  31. package/dist/dawproject/DawProject.d.ts.map +1 -1
  32. package/dist/dawproject/DawProject.js +17 -3
  33. package/dist/midi/MIDILearning.d.ts +4 -16
  34. package/dist/midi/MIDILearning.d.ts.map +1 -1
  35. package/dist/midi/MIDILearning.js +94 -62
  36. package/dist/processors.js +17 -17
  37. package/dist/processors.js.map +4 -4
  38. package/dist/project/Project.d.ts +2 -2
  39. package/dist/project/Project.d.ts.map +1 -1
  40. package/dist/project/Project.js +16 -9
  41. package/dist/project/ProjectApi.js +2 -2
  42. package/dist/project/ProjectBundle.d.ts.map +1 -1
  43. package/dist/project/ProjectBundle.js +21 -6
  44. package/dist/project/ProjectMigration.d.ts.map +1 -1
  45. package/dist/project/ProjectMigration.js +20 -4
  46. package/dist/project/ProjectValidation.d.ts.map +1 -1
  47. package/dist/project/ProjectValidation.js +15 -13
  48. package/dist/project/audio/AudioContentFactory.d.ts.map +1 -1
  49. package/dist/project/audio/AudioContentFactory.js +3 -3
  50. package/dist/project/audio/AudioContentModifier.d.ts.map +1 -1
  51. package/dist/project/audio/AudioContentModifier.js +15 -3
  52. package/dist/project/audio/AudioFileBoxFactory.d.ts.map +1 -1
  53. package/dist/project/audio/AudioFileBoxFactory.js +5 -0
  54. package/dist/samples/DefaultSampleLoader.d.ts.map +1 -1
  55. package/dist/samples/DefaultSampleLoader.js +8 -4
  56. package/dist/samples/DefaultSampleLoaderManager.d.ts.map +1 -1
  57. package/dist/samples/DefaultSampleLoaderManager.js +5 -2
  58. package/dist/soundfont/DefaultSoundfontLoader.d.ts.map +1 -1
  59. package/dist/soundfont/DefaultSoundfontLoader.js +16 -11
  60. package/dist/soundfont/SoundfontService.d.ts.map +1 -1
  61. package/dist/soundfont/SoundfontService.js +3 -6
  62. package/dist/ui/RegionClipResolver.d.ts.map +1 -1
  63. package/dist/ui/RegionClipResolver.js +15 -6
  64. package/dist/ui/RegionModifyStrategies.js +3 -3
  65. package/dist/ui/TimeGrid.d.ts +2 -1
  66. package/dist/ui/TimeGrid.d.ts.map +1 -1
  67. package/dist/ui/TimeGrid.js +28 -14
  68. package/dist/workers-main.js +1 -1
  69. package/dist/workers-main.js.map +3 -3
  70. package/package.json +16 -16
@@ -10,7 +10,7 @@ import { CaptureDevices } from "../capture";
10
10
  import { EngineFacade } from "../EngineFacade";
11
11
  import { EngineWorklet } from "../EngineWorklet";
12
12
  import { MIDILearning } from "../midi";
13
- import { ppqn, TempoMap } from "@opendaw/lib-dsp";
13
+ import { TempoMap } from "@opendaw/lib-dsp";
14
14
  export type RestartWorklet = {
15
15
  unload: Func<unknown, Promise<unknown>>;
16
16
  load: Procedure<EngineWorklet>;
@@ -58,10 +58,10 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
58
58
  get isAudioContext(): boolean;
59
59
  get isMainThread(): boolean;
60
60
  get liveStreamBroadcaster(): LiveStreamBroadcaster;
61
- get signatureDuration(): ppqn;
62
61
  get skeleton(): ProjectSkeleton;
63
62
  receivedMIDIFromEngine(midiDeviceId: string, data: Uint8Array, relativeTimeInMs: number): void;
64
63
  collectSampleUUIDs(): ReadonlyArray<UUID.Bytes>;
64
+ restartRecording(): void;
65
65
  toArrayBuffer(): ArrayBufferLike;
66
66
  copy(env?: Partial<ProjectEnv>): Project;
67
67
  invalid(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { Arrays, panic, safeExecute, Terminator } from "@opendaw/lib-std";
2
2
  import { BoxEditing } from "@opendaw/lib-box";
3
3
  import { AudioRegionBox } from "@opendaw/studio-boxes";
4
- import { BoxAdapters, ParameterFieldAdapters, ProjectSkeleton, RootBoxAdapter, TimelineBoxAdapter, UnionBoxTypes, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
4
+ import { BoxAdapters, 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";
@@ -11,7 +11,7 @@ import { EngineFacade } from "../EngineFacade";
11
11
  import { MidiDevices, MIDILearning } from "../midi";
12
12
  import { ProjectValidation } from "./ProjectValidation";
13
13
  import { Preferences } from "../Preferences";
14
- import { ConstantTempoMap, PPQN, TimeBase } from "@opendaw/lib-dsp";
14
+ import { TimeBase } from "@opendaw/lib-dsp";
15
15
  import { MidiData } from "@opendaw/lib-midi";
16
16
  // Main Entry Point for a Project
17
17
  export class Project {
@@ -77,8 +77,8 @@ export class Project {
77
77
  this.editing = new BoxEditing(this.boxGraph);
78
78
  this.selection = new VertexSelection(this.editing, this.boxGraph);
79
79
  this.parameterFieldAdapters = new ParameterFieldAdapters();
80
- this.tempoMap = new ConstantTempoMap(this.timelineBox.bpm);
81
80
  this.boxAdapters = this.#terminator.own(new BoxAdapters(this));
81
+ this.tempoMap = new VaryingTempoMap(this.timelineBoxAdapter);
82
82
  this.userEditingManager = new UserEditingManager(this.editing);
83
83
  this.liveStreamReceiver = this.#terminator.own(new LiveStreamReceiver());
84
84
  this.midiLearning = this.#terminator.own(new MIDILearning(this));
@@ -118,6 +118,7 @@ export class Project {
118
118
  }
119
119
  follow(box) {
120
120
  this.userEditingManager.follow(box);
121
+ this.midiLearning.followUser(box.midiControllers);
121
122
  this.selection.switch(box.selection);
122
123
  }
123
124
  own(terminable) { return this.#terminator.own(terminable); }
@@ -132,10 +133,6 @@ export class Project {
132
133
  get isAudioContext() { return false; }
133
134
  get isMainThread() { return true; }
134
135
  get liveStreamBroadcaster() { return panic("Only available in audio context"); }
135
- get signatureDuration() {
136
- const { nominator, denominator } = this.timelineBox.signature;
137
- return PPQN.fromSignature(nominator.getValue(), denominator.getValue());
138
- }
139
136
  get skeleton() {
140
137
  return {
141
138
  boxGraph: this.boxGraph,
@@ -168,9 +165,19 @@ export class Project {
168
165
  .filter(box => box.accept({ visitAudioFileBox: (_box) => true }))
169
166
  .map(box => box.address.uuid);
170
167
  }
171
- toArrayBuffer() {
172
- return ProjectSkeleton.encode(this.boxGraph);
168
+ restartRecording() {
169
+ if (this.engine.isRecording.getValue()) {
170
+ this.engine.stopRecording();
171
+ this.editing.modify(() => this.captureDevices.filterArmed()
172
+ .forEach(capture => {
173
+ capture.recordedRegions().forEach(region => region.box.delete());
174
+ capture.clearRecordedRegions();
175
+ }), false);
176
+ this.engine.stop(true);
177
+ setTimeout(() => this.startRecording(true), 100);
178
+ }
173
179
  }
180
+ toArrayBuffer() { return ProjectSkeleton.encode(this.boxGraph); }
174
181
  copy(env) {
175
182
  return Project.load({ ...this.#env, ...env }, this.toArrayBuffer());
176
183
  }
@@ -176,7 +176,7 @@ export class ProjectApi {
176
176
  box.hue.setValue(hue ?? ColorCodes.forTrackType(type));
177
177
  box.mute.setValue(false);
178
178
  box.duration.setValue(duration);
179
- box.loopDuration.setValue(this.#project.signatureDuration);
179
+ box.loopDuration.setValue(duration);
180
180
  box.events.refer(events.owners);
181
181
  box.regions.refer(trackBox.regions);
182
182
  }));
@@ -189,7 +189,7 @@ export class ProjectApi {
189
189
  box.hue.setValue(hue ?? ColorCodes.forTrackType(type));
190
190
  box.mute.setValue(false);
191
191
  box.duration.setValue(duration);
192
- box.loopDuration.setValue(PPQN.Bar);
192
+ box.loopDuration.setValue(duration);
193
193
  box.events.refer(events.owners);
194
194
  box.regions.refer(trackBox.regions);
195
195
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectBundle.d.ts","sourceRoot":"","sources":["../../src/project/ProjectBundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,QAAQ,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAI1F,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAEvC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAO/C,yBAAiB,aAAa,CAAC;IACpB,MAAM,MAAM,GAAU,gCAA8B,cAAc,EAC5C,UAAU,QAAQ,CAAC,OAAO,KAAG,OAAO,CAAC,WAAW,CAoC5E,CAAA;IAEM,MAAM,MAAM,GAAU,KAAK,UAAU,EACf,aAAa,WAAW,EACxB,kBAAkB,IAAI,CAAC,KAAK,KAAG,OAAO,CAAC,cAAc,CAqCjF,CAAA;CAgDJ"}
1
+ {"version":3,"file":"ProjectBundle.d.ts","sourceRoot":"","sources":["../../src/project/ProjectBundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,QAAQ,EAAmB,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAI3G,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAEvC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAO/C,yBAAiB,aAAa,CAAC;IACpB,MAAM,MAAM,GAAU,gCAA8B,cAAc,EAC5C,UAAU,QAAQ,CAAC,OAAO,KAAG,OAAO,CAAC,WAAW,CA2C5E,CAAA;IAEM,MAAM,MAAM,GAAU,KAAK,UAAU,EACf,aAAa,WAAW,EACxB,kBAAkB,IAAI,CAAC,KAAK,KAAG,OAAO,CAAC,cAAc,CA6CjF,CAAA;CAgDJ"}
@@ -1,4 +1,4 @@
1
- import { asDefined, isDefined, Option, panic, UUID } from "@opendaw/lib-std";
1
+ import { asDefined, isDefined, Option, panic, RuntimeNotifier, UUID } from "@opendaw/lib-std";
2
2
  import { AudioFileBox, SoundfontFileBox } from "@opendaw/studio-boxes";
3
3
  import { Project } from "./Project";
4
4
  import { ProjectPaths } from "./ProjectPaths";
@@ -10,7 +10,14 @@ import { ExternalLib } from "../ExternalLib";
10
10
  export var ProjectBundle;
11
11
  (function (ProjectBundle) {
12
12
  ProjectBundle.encode = async ({ uuid, project, meta, cover }, progress) => {
13
- const JSZip = await ExternalLib.JSZip();
13
+ const { status, value: JSZip, error } = await ExternalLib.JSZip();
14
+ if (status === "rejected") {
15
+ await RuntimeNotifier.info({
16
+ headline: "Error",
17
+ message: `Could not load JSZip: ${String(error)}`
18
+ });
19
+ return Promise.reject(error);
20
+ }
14
21
  const zip = new JSZip();
15
22
  zip.file("version", "1");
16
23
  zip.file("uuid", uuid, { binary: true });
@@ -45,7 +52,14 @@ export var ProjectBundle;
45
52
  return blob.arrayBuffer();
46
53
  };
47
54
  ProjectBundle.decode = async (env, arrayBuffer, openProfileUUID) => {
48
- const JSZip = await ExternalLib.JSZip();
55
+ const { status, value: JSZip, error } = await ExternalLib.JSZip();
56
+ if (status === "rejected") {
57
+ await RuntimeNotifier.info({
58
+ headline: "Error",
59
+ message: `Could not load JSZip: ${String(error)}`
60
+ });
61
+ return Promise.reject(error);
62
+ }
49
63
  const zip = await JSZip.loadAsync(arrayBuffer);
50
64
  if (await asDefined(zip.file("version")).async("text") !== "1") {
51
65
  return panic("Unknown bundle version");
@@ -80,7 +94,8 @@ export var ProjectBundle;
80
94
  });
81
95
  }
82
96
  await Promise.all(promises);
83
- const project = Project.load(env, await asDefined(zip.file(ProjectPaths.ProjectFile)).async("arraybuffer"));
97
+ const projectData = await asDefined(zip.file(ProjectPaths.ProjectFile)).async("arraybuffer");
98
+ const project = await Project.loadAnyVersion(env, projectData);
84
99
  const meta = JSON.parse(await asDefined(zip.file(ProjectPaths.ProjectMetaFile)).async("text"));
85
100
  const coverFile = zip.file(ProjectPaths.ProjectCoverFile);
86
101
  const cover = Option.wrap(await coverFile?.async("arraybuffer"));
@@ -104,7 +119,7 @@ export var ProjectBundle;
104
119
  subscription.terminate();
105
120
  }
106
121
  else if (state.type === "error") {
107
- reject(state.reason);
122
+ reject(new Error(state.reason));
108
123
  subscription.terminate();
109
124
  }
110
125
  });
@@ -128,7 +143,7 @@ export var ProjectBundle;
128
143
  subscription.terminate();
129
144
  }
130
145
  else if (state.type === "error") {
131
- reject(state.reason);
146
+ reject(new Error(state.reason));
132
147
  subscription.terminate();
133
148
  }
134
149
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectMigration.d.ts","sourceRoot":"","sources":["../../src/project/ProjectMigration.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAC,eAAe,EAAC,MAAM,0BAA0B,CAAA;AAIxD,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AASvC,qBAAa,gBAAgB;WACZ,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,EAAC,QAAQ,EAAE,cAAc,EAAC,EAAE,eAAe;CAyOpF"}
1
+ {"version":3,"file":"ProjectMigration.d.ts","sourceRoot":"","sources":["../../src/project/ProjectMigration.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAC,eAAe,EAAC,MAAM,0BAA0B,CAAA;AAIxD,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AASvC,qBAAa,gBAAgB;WACZ,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,EAAC,QAAQ,EAAE,cAAc,EAAC,EAAE,eAAe;CAuPpF"}
@@ -26,18 +26,26 @@ export class ProjectMigration {
26
26
  const loadAudioData = (uuid) => {
27
27
  const { promise, resolve, reject } = Promise.withResolvers();
28
28
  const loader = env.sampleManager.getOrCreate(uuid);
29
- const subscription = loader.subscribe(state => {
29
+ let subscription;
30
+ subscription = loader.subscribe(state => {
30
31
  if (state.type === "loaded") {
31
- subscription.terminate();
32
+ queueMicrotask(() => subscription.terminate());
32
33
  resolve(loader.data.unwrap("State mismatch"));
33
34
  }
34
35
  else if (state.type === "error") {
35
- subscription.terminate();
36
- reject(state.reason);
36
+ queueMicrotask(() => subscription.terminate());
37
+ reject(new Error(state.reason));
37
38
  }
38
39
  });
39
40
  return promise;
40
41
  };
42
+ const orphans = boxGraph.findOrphans(rootBox);
43
+ if (orphans.length > 0) {
44
+ console.debug("Migrate remove orphaned boxes: ", orphans.length);
45
+ boxGraph.beginTransaction();
46
+ orphans.forEach(orphan => orphan.delete());
47
+ boxGraph.endTransaction();
48
+ }
41
49
  // 1st pass (2nd pass might rely on those changes)
42
50
  for (const box of boxGraph.boxes()) {
43
51
  await box.accept({
@@ -130,6 +138,14 @@ export class ProjectMigration {
130
138
  boxGraph.endTransaction();
131
139
  }
132
140
  },
141
+ visitTimelineBox: (timelineBox) => {
142
+ if (timelineBox.tempoTrack.events.isEmpty()) {
143
+ console.debug("Migrate 'TimelineBox' to have a ValueEventCollectionBox for tempo events");
144
+ boxGraph.beginTransaction();
145
+ ValueEventCollectionBox.create(boxGraph, UUID.generate(), box => timelineBox.tempoTrack.events.refer(box.owners));
146
+ boxGraph.endTransaction();
147
+ }
148
+ },
133
149
  visitMIDIOutputDeviceBox: (deviceBox) => {
134
150
  const id = deviceBox.deprecatedDevice.id.getValue();
135
151
  const label = deviceBox.deprecatedDevice.label.getValue();
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectValidation.d.ts","sourceRoot":"","sources":["../../src/project/ProjectValidation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,eAAe,EAAC,MAAM,0BAA0B,CAAA;AAGxD,yBAAiB,iBAAiB,CAAC;IACxB,MAAM,QAAQ,GAAI,UAAU,eAAe,KAAG,IA2CpD,CAAA;CACJ"}
1
+ {"version":3,"file":"ProjectValidation.d.ts","sourceRoot":"","sources":["../../src/project/ProjectValidation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,eAAe,EAAC,MAAM,0BAA0B,CAAA;AAGxD,yBAAiB,iBAAiB,CAAC;IACxB,MAAM,QAAQ,GAAI,UAAU,eAAe,KAAG,IA6CpD,CAAA;CACJ"}
@@ -18,20 +18,22 @@ export var ProjectValidation;
18
18
  visitNoteRegionBox: (box) => validateRegion(box),
19
19
  visitValueRegionBox: (box) => validateRegion(box),
20
20
  visitAudioRegionBox: (box) => validateRegion(box),
21
- visitTrackBox: (box) => Arrays.iterateAdjacent(box.regions.pointerHub.incoming()
22
- .map(({ box }) => asDefined(box.accept({
23
- visitNoteRegionBox: (box) => box,
24
- visitValueRegionBox: (box) => box,
25
- visitAudioRegionBox: (box) => box
26
- }), "Box must be a NoteRegionBox, ValueRegionBox or AudioRegionBox"))
27
- .sort((a, b) => a.position.getValue() - b.position.getValue()))
28
- .forEach(([left, right]) => {
29
- if (right.position.getValue() < left.position.getValue() + left.duration.getValue()) {
30
- console.warn(left, right, "Overlapping regions");
31
- invalidBoxes.add(left);
32
- invalidBoxes.add(right);
21
+ visitTrackBox: (box) => {
22
+ const regions = box.regions.pointerHub.incoming()
23
+ .map(({ box }) => asDefined(box.accept({
24
+ visitNoteRegionBox: (box) => box,
25
+ visitValueRegionBox: (box) => box,
26
+ visitAudioRegionBox: (box) => box
27
+ }), "Box must be a NoteRegionBox, ValueRegionBox or AudioRegionBox"))
28
+ .sort((a, b) => a.position.getValue() - b.position.getValue());
29
+ for (const [left, right] of Arrays.iterateAdjacent(regions)) {
30
+ if (right.position.getValue() < left.position.getValue() + left.duration.getValue()) {
31
+ console.warn(left, right, "Overlapping regions");
32
+ invalidBoxes.add(left);
33
+ invalidBoxes.add(right);
34
+ }
33
35
  }
34
- })
36
+ }
35
37
  }));
36
38
  if (invalidBoxes.size === 0) {
37
39
  return;
@@ -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,EAAwC,MAAM,kBAAkB,CAAA;AAC3E,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;IAI3E,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"}
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;IAI3E,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"}
@@ -1,6 +1,6 @@
1
1
  import { PPQN, TimeBase } from "@opendaw/lib-dsp";
2
2
  import { ColorCodes, TrackType } from "@opendaw/studio-adapters";
3
- import { isDefined, panic, quantizeRound, UUID } from "@opendaw/lib-std";
3
+ import { isDefined, panic, quantizeCeil, UUID } from "@opendaw/lib-std";
4
4
  import { AudioClipBox, AudioPitchStretchBox, AudioRegionBox, AudioTimeStretchBox, ValueEventCollectionBox } from "@opendaw/studio-boxes";
5
5
  import { TransientPlayMode } from "@opendaw/studio-enums";
6
6
  import { AudioContentHelpers } from "./AudioContentHelpers";
@@ -68,7 +68,7 @@ export var AudioContentFactory;
68
68
  return panic("Cannot create audio-region on non-audio track");
69
69
  }
70
70
  const { name, duration: durationInSeconds, bpm } = sample;
71
- const durationInPPQN = props.duration ?? quantizeRound(PPQN.secondsToPulses(durationInSeconds, bpm), PPQN.SemiQuaver);
71
+ const durationInPPQN = props.duration ?? quantizeCeil(PPQN.secondsToPulses(durationInSeconds, bpm), PPQN.SemiQuaver);
72
72
  if (isDefined(props.warpMarkers)) {
73
73
  AudioContentHelpers.addWarpMarkers(boxGraph, playMode, props.warpMarkers);
74
74
  }
@@ -97,7 +97,7 @@ export var AudioContentFactory;
97
97
  return panic("Cannot create audio-region on non-audio track");
98
98
  }
99
99
  const { name, duration: durationInSeconds, bpm } = sample;
100
- const durationInPPQN = props.duration ?? quantizeRound(PPQN.secondsToPulses(durationInSeconds, bpm), PPQN.SemiQuaver);
100
+ const durationInPPQN = props.duration ?? quantizeCeil(PPQN.secondsToPulses(durationInSeconds, bpm), PPQN.SemiQuaver);
101
101
  if (isDefined(props.warpMarkers)) {
102
102
  AudioContentHelpers.addWarpMarkers(boxGraph, playMode, props.warpMarkers);
103
103
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AudioContentModifier.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentModifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,IAAI,EAAgC,MAAM,kBAAkB,CAAA;AAS/E,OAAO,EAAC,sBAAsB,EAAwB,MAAM,0BAA0B,CAAA;AAItF,yBAAiB,oBAAoB,CAAC;IAC3B,MAAM,cAAc,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CAOlG,CAAA;IAEM,MAAM,cAAc,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CA2BlG,CAAA;IAEM,MAAM,aAAa,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CA2CjG,CAAA;CA4BJ"}
1
+ {"version":3,"file":"AudioContentModifier.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentModifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,IAAI,EAAgC,MAAM,kBAAkB,CAAA;AAS/E,OAAO,EAAC,sBAAsB,EAAwB,MAAM,0BAA0B,CAAA;AAKtF,yBAAiB,oBAAoB,CAAC;IAC3B,MAAM,cAAc,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CAalG,CAAA;IAEM,MAAM,cAAc,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CA4BlG,CAAA;IAEM,MAAM,aAAa,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CA4CjG,CAAA;CA2BJ"}
@@ -4,6 +4,7 @@ import { AudioPitchStretchBox, AudioTimeStretchBox, TransientMarkerBox, WarpMark
4
4
  import { AudioRegionBoxAdapter } from "@opendaw/studio-adapters";
5
5
  import { AudioContentHelpers } from "./AudioContentHelpers";
6
6
  import { Workers } from "../../Workers";
7
+ import { Pointers } from "@opendaw/studio-enums";
7
8
  export var AudioContentModifier;
8
9
  (function (AudioContentModifier) {
9
10
  AudioContentModifier.toNotStretched = async (adapters) => {
@@ -13,6 +14,16 @@ export var AudioContentModifier;
13
14
  }
14
15
  return () => audioAdapters.forEach((adapter) => {
15
16
  adapter.box.playMode.defer();
17
+ adapter.asPlayModeTimeStretch.ifSome(({ box }) => {
18
+ if (box.pointerHub.filter(Pointers.AudioPlayMode).length === 0) {
19
+ box.delete();
20
+ }
21
+ });
22
+ adapter.asPlayModePitchStretch.ifSome(({ box }) => {
23
+ if (box.pointerHub.filter(Pointers.AudioPlayMode).length === 0) {
24
+ box.delete();
25
+ }
26
+ });
16
27
  switchTimeBaseToSeconds(adapter);
17
28
  });
18
29
  };
@@ -28,7 +39,8 @@ export var AudioContentModifier;
28
39
  adapter.box.playMode.refer(pitchStretch);
29
40
  if (optTimeStretch.nonEmpty()) {
30
41
  const timeStretch = optTimeStretch.unwrap();
31
- if (timeStretch.box.pointerHub.isEmpty()) {
42
+ const numPointers = timeStretch.box.pointerHub.filter(Pointers.AudioPlayMode).length;
43
+ if (numPointers === 0) {
32
44
  timeStretch.warpMarkers.asArray()
33
45
  .forEach(({ box: { owner } }) => owner.refer(pitchStretch.warpMarkers));
34
46
  timeStretch.box.delete();
@@ -69,7 +81,8 @@ export var AudioContentModifier;
69
81
  adapter.box.playMode.refer(timeStretch);
70
82
  if (optPitchStretch.nonEmpty()) {
71
83
  const pitchStretch = optPitchStretch.unwrap();
72
- if (pitchStretch.box.pointerHub.isEmpty()) {
84
+ const numPointers = pitchStretch.box.pointerHub.filter(Pointers.AudioPlayMode).length;
85
+ if (numPointers === 0) {
73
86
  pitchStretch.warpMarkers.asArray()
74
87
  .forEach(({ box: { owner } }) => owner.refer(timeStretch.warpMarkers));
75
88
  pitchStretch.box.delete();
@@ -105,7 +118,6 @@ export var AudioContentModifier;
105
118
  box.duration.setValue(file.endInSeconds);
106
119
  box.accept({
107
120
  visitAudioRegionBox: (box) => {
108
- console.debug("RESET");
109
121
  box.loopOffset.setValue(0);
110
122
  box.loopDuration.setValue(file.endInSeconds);
111
123
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AudioFileBoxFactory.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioFileBoxFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAqB,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAAS,QAAQ,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAC,SAAS,EAAE,iBAAiB,EAAC,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAEzC,yBAAiB,mBAAmB,CAAC;IAO1B,MAAM,cAAc,GAAU,mBAAmB,iBAAiB,EACpC,UAAU,QAAQ,EAClB,WAAW,SAAS,EACpB,MAAM,IAAI,CAAC,KAAK,EAChB,MAAM,MAAM,KAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAyBjF,CAAA;CACJ"}
1
+ {"version":3,"file":"AudioFileBoxFactory.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioFileBoxFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAqB,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAAS,QAAQ,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAC,SAAS,EAAE,iBAAiB,EAAC,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAEzC,yBAAiB,mBAAmB,CAAC;IAO1B,MAAM,cAAc,GAAU,mBAAmB,iBAAiB,EACpC,UAAU,QAAQ,EAClB,WAAW,SAAS,EACpB,MAAM,IAAI,CAAC,KAAK,EAChB,MAAM,MAAM,KAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CA8BjF,CAAA;CACJ"}
@@ -23,6 +23,11 @@ export var AudioFileBoxFactory;
23
23
  const transients = await transientProtocol.detect(audioData);
24
24
  const durationInSeconds = audioData.numberOfFrames / audioData.sampleRate;
25
25
  return () => {
26
+ // Re-check in case another drop created it between createModifier and now
27
+ const existingBox = boxGraph.findBox(uuid);
28
+ if (existingBox.nonEmpty()) {
29
+ return existingBox.unwrap();
30
+ }
26
31
  const audioFileBox = AudioFileBox.create(boxGraph, uuid, box => {
27
32
  box.fileName.setValue(name);
28
33
  box.startInSeconds.setValue(0);
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultSampleLoader.d.ts","sourceRoot":"","sources":["../../src/samples/DefaultSampleLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,QAAQ,EACR,MAAM,EAEN,YAAY,EAEZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAC,KAAK,EAAc,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAC,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAExF,OAAO,EAAC,0BAA0B,EAAC,MAAM,8BAA8B,CAAA;AAEvE,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,qBAAa,mBAAoB,YAAW,YAAY;;gBAYxC,OAAO,EAAE,0BAA0B,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK;IAQjE,UAAU,IAAI,IAAI;IASlB,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,YAAY;IAQ9D,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,CAAoB;IAC1C,IAAI,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAoB;IACjD,IAAI,IAAI,IAAI,MAAM,CAAC,cAAc,CAAC,CAAoB;IACtD,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAqB;IAC/C,IAAI,KAAK,IAAI,iBAAiB,CAAqB;IAEnD,QAAQ,IAAI,MAAM;CAmErB"}
1
+ {"version":3,"file":"DefaultSampleLoader.d.ts","sourceRoot":"","sources":["../../src/samples/DefaultSampleLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,QAAQ,EACR,MAAM,EAEN,YAAY,EAEZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAC,KAAK,EAAc,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAC,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAExF,OAAO,EAAC,0BAA0B,EAAC,MAAM,8BAA8B,CAAA;AAEvE,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,qBAAa,mBAAoB,YAAW,YAAY;;gBAYxC,OAAO,EAAE,0BAA0B,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK;IAQjE,UAAU,IAAI,IAAI;IASlB,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,YAAY;IAQ9D,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,CAAoB;IAC1C,IAAI,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAoB;IACjD,IAAI,IAAI,IAAI,MAAM,CAAC,cAAc,CAAC,CAAoB;IACtD,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAqB;IAC/C,IAAI,KAAK,IAAI,iBAAiB,CAAqB;IAEnD,QAAQ,IAAI,MAAM;CAuErB"}
@@ -75,8 +75,10 @@ export class DefaultSampleLoader {
75
75
  return;
76
76
  }
77
77
  if (fetchResult.status === "rejected") {
78
- console.warn(fetchResult.error);
79
- this.#setState({ type: "error", reason: "Error: N/A" });
78
+ const error = fetchResult.error;
79
+ console.warn(error);
80
+ const reason = error instanceof Error ? error.message : String(error);
81
+ this.#setState({ type: "error", reason });
80
82
  return;
81
83
  }
82
84
  const [audio, meta] = fetchResult.value;
@@ -98,8 +100,10 @@ export class DefaultSampleLoader {
98
100
  this.#setState({ type: "loaded" });
99
101
  }
100
102
  else {
101
- console.warn(storeResult.error);
102
- this.#setState({ type: "error", reason: "N/A" });
103
+ const error = storeResult.error;
104
+ console.warn(error);
105
+ const reason = error instanceof Error ? error.message : String(error);
106
+ this.#setState({ type: "error", reason });
103
107
  }
104
108
  }
105
109
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultSampleLoaderManager.d.ts","sourceRoot":"","sources":["../../src/samples/DefaultSampleLoaderManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAa,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAE1D,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAC1F,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,qBAAa,0BAA2B,YAAW,mBAAmB,EAAE,cAAc;;gBAItE,QAAQ,EAAE,cAAc;IAKpC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAIzF,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK;IACvB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK;IAE3B,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAElC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,YAAY;IAIrC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC;CAY3D"}
1
+ {"version":3,"file":"DefaultSampleLoaderManager.d.ts","sourceRoot":"","sources":["../../src/samples/DefaultSampleLoaderManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAA2B,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAExE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAC1F,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,qBAAa,0BAA2B,YAAW,mBAAmB,EAAE,cAAc;;gBAItE,QAAQ,EAAE,cAAc;IAKpC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAIzF,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK;IACvB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK;IAE3B,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAElC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,YAAY;IAIrC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC;CAe3D"}
@@ -19,11 +19,14 @@ export class DefaultSampleLoaderManager {
19
19
  async getAudioData(uuid) {
20
20
  const { promise, resolve, reject } = Promise.withResolvers();
21
21
  const loader = this.getOrCreate(uuid);
22
- loader.subscribe(state => {
22
+ let subscription;
23
+ subscription = loader.subscribe(state => {
23
24
  if (state.type === "error") {
24
- reject(state.reason);
25
+ queueMicrotask(() => subscription.terminate());
26
+ reject(new Error(state.reason));
25
27
  }
26
28
  else if (loader.data.nonEmpty()) {
29
+ queueMicrotask(() => subscription.terminate());
27
30
  resolve(loader.data.unwrap());
28
31
  }
29
32
  });
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultSoundfontLoader.d.ts","sourceRoot":"","sources":["../../src/soundfont/DefaultSoundfontLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,QAAQ,EAAE,MAAM,EAAY,YAAY,EAAc,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAErG,OAAO,EAAC,eAAe,EAAE,oBAAoB,EAAE,iBAAiB,EAAC,MAAM,0BAA0B,CAAA;AACjG,OAAO,EAAC,6BAA6B,EAAC,MAAM,iCAAiC,CAAA;AAE7E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,YAAY,CAAA;AAG1C,qBAAa,sBAAuB,YAAW,eAAe;;gBAY9C,OAAO,EAAE,6BAA6B,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK;IAQpE,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,YAAY;IAQjE,UAAU,IAAI,IAAI;IAOlB,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,CAAoB;IAC1C,IAAI,SAAS,IAAI,MAAM,CAAC,UAAU,CAAC,CAAyB;IAC5D,IAAI,IAAI,IAAI,MAAM,CAAC,iBAAiB,CAAC,CAAoB;IACzD,IAAI,KAAK,IAAI,oBAAoB,CAAqB;IAEtD,QAAQ,IAAI,MAAM;CA+CrB"}
1
+ {"version":3,"file":"DefaultSoundfontLoader.d.ts","sourceRoot":"","sources":["../../src/soundfont/DefaultSoundfontLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,QAAQ,EAAE,MAAM,EAAY,YAAY,EAAc,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAErG,OAAO,EAAC,eAAe,EAAE,oBAAoB,EAAE,iBAAiB,EAAC,MAAM,0BAA0B,CAAA;AACjG,OAAO,EAAC,6BAA6B,EAAC,MAAM,iCAAiC,CAAA;AAE7E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,YAAY,CAAA;AAG1C,qBAAa,sBAAuB,YAAW,eAAe;;gBAU9C,OAAO,EAAE,6BAA6B,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK;IAQpE,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,YAAY;IAQjE,UAAU,IAAI,IAAI;IAOlB,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,CAAoB;IAC1C,IAAI,SAAS,IAAI,MAAM,CAAC,UAAU,CAAC,CAAyB;IAC5D,IAAI,IAAI,IAAI,MAAM,CAAC,iBAAiB,CAAC,CAAoB;IACzD,IAAI,KAAK,IAAI,oBAAoB,CAAqB;IAEtD,QAAQ,IAAI,MAAM;CAkDrB"}
@@ -6,7 +6,6 @@ export class DefaultSoundfontLoader {
6
6
  #manager;
7
7
  #uuid;
8
8
  #notifier;
9
- #soundFont2 = Promises.memoizeAsync(() => ExternalLib.SoundFont2());
10
9
  #meta = Option.None;
11
10
  #soundfont = Option.None;
12
11
  #state = { type: "progress", progress: 0.0 };
@@ -40,7 +39,10 @@ export class DefaultSoundfontLoader {
40
39
  }
41
40
  #get() {
42
41
  SoundfontStorage.get().load(this.#uuid).then(async ([file, meta]) => {
43
- this.#soundfont = Option.wrap(await this.#createSoundFont2(file));
42
+ const { status, value: SoundFont2, error } = await ExternalLib.SoundFont2();
43
+ if (status === "rejected")
44
+ return console.warn(error);
45
+ this.#soundfont = Option.wrap(new SoundFont2(new Uint8Array(file)));
44
46
  this.#meta = Option.wrap(meta);
45
47
  this.#setState({ type: "loaded" });
46
48
  }, (error) => {
@@ -57,24 +59,27 @@ export class DefaultSoundfontLoader {
57
59
  const fetchProgress = progress => this.#setState({ type: "progress", progress });
58
60
  const fetchResult = await Promises.tryCatch(this.#manager.fetch(this.#uuid, fetchProgress));
59
61
  if (fetchResult.status === "rejected") {
60
- console.warn(fetchResult.error);
61
- this.#setState({ type: "error", reason: "Error: N/A" });
62
+ const error = fetchResult.error;
63
+ console.warn(error);
64
+ const reason = error instanceof Error ? error.message : String(error);
65
+ this.#setState({ type: "error", reason });
62
66
  return;
63
67
  }
64
68
  const [file, meta] = fetchResult.value;
65
69
  const storeResult = await Promises.tryCatch(SoundfontStorage.get().save({ uuid: this.#uuid, file, meta }));
66
70
  if (storeResult.status === "resolved") {
67
- this.#soundfont = Option.wrap(await this.#createSoundFont2(file));
71
+ const { status, value: SoundFont2, error } = await ExternalLib.SoundFont2();
72
+ if (status === "rejected")
73
+ return console.warn(error);
74
+ this.#soundfont = Option.wrap(new SoundFont2(new Uint8Array(file)));
68
75
  this.#meta = Option.wrap(meta);
69
76
  this.#setState({ type: "loaded" });
70
77
  }
71
78
  else {
72
- console.warn(storeResult.error);
73
- this.#setState({ type: "error", reason: "N/A" });
79
+ const error = storeResult.error;
80
+ console.warn(error);
81
+ const reason = error instanceof Error ? error.message : String(error);
82
+ this.#setState({ type: "error", reason });
74
83
  }
75
84
  }
76
- async #createSoundFont2(buffer) {
77
- const SoundFont2 = await this.#soundFont2();
78
- return new SoundFont2(new Uint8Array(buffer));
79
- }
80
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SoundfontService.d.ts","sourceRoot":"","sources":["../../src/soundfont/SoundfontService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAE,MAAM,EAAS,SAAS,EAAwB,MAAM,kBAAkB,CAAA;AAC/F,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAGpC,OAAO,EAAC,SAAS,EAAoB,MAAM,0BAA0B,CAAA;AAIrE,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAI5C,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,SAAS,CAAC;;IACzD,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAe;IACpD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAc;IACrD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAmB;IACzD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAuC;gBAKlF,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC;IAY1C,IAAI,KAAK,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAqB;IAClE,IAAI,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAsB;IAE9D,UAAU,CAAC,EAAC,IAAI,EAAE,WAAW,EAAC,EAAE,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;cA2ClE,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;CAUvE"}
1
+ {"version":3,"file":"SoundfontService.d.ts","sourceRoot":"","sources":["../../src/soundfont/SoundfontService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAE,MAAM,EAAS,SAAS,EAAwB,MAAM,kBAAkB,CAAA;AAC/F,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAGpC,OAAO,EAAC,SAAS,EAAoB,MAAM,0BAA0B,CAAA;AAIrE,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAG5C,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,SAAS,CAAC;;IACzD,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAe;IACpD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAc;IACrD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAmB;IACzD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAuC;gBAKlF,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC;IAY1C,IAAI,KAAK,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAqB;IAClE,IAAI,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAsB;IAE9D,UAAU,CAAC,EAAC,IAAI,EAAE,WAAW,EAAC,EAAE,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;cA4ClE,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;CAKvE"}
@@ -1,5 +1,5 @@
1
1
  import { Arrays, Option, panic, RuntimeNotifier, UUID } from "@opendaw/lib-std";
2
- import { Promises, Wait } from "@opendaw/lib-runtime";
2
+ import { Wait } from "@opendaw/lib-runtime";
3
3
  import { SoundfontFileBox } from "@opendaw/studio-boxes";
4
4
  import { SoundfontStorage } from "./SoundfontStorage";
5
5
  import { FilePickerAcceptTypes } from "../FilePickerAcceptTypes";
@@ -44,12 +44,13 @@ export class SoundfontService extends AssetService {
44
44
  uuid ??= await UUID.sha256(arrayBuffer);
45
45
  console.timeEnd("UUID.sha256");
46
46
  console.time("SoundFont2");
47
- const { status, value: soundFont2, error } = await Promises.tryCatch(this.#createSoundFont2(arrayBuffer));
47
+ const { status, value: SoundFont2, error } = await ExternalLib.SoundFont2();
48
48
  console.timeEnd("SoundFont2");
49
49
  if (status === "rejected") {
50
50
  updater.terminate();
51
51
  return panic(error);
52
52
  }
53
+ const soundFont2 = new SoundFont2(new Uint8Array(arrayBuffer));
53
54
  const meta = {
54
55
  name: soundFont2.metaData.name,
55
56
  size: arrayBuffer.byteLength,
@@ -72,8 +73,4 @@ export class SoundfontService extends AssetService {
72
73
  const local = await SoundfontStorage.get().list();
73
74
  return Arrays.merge(stock, local, (a, b) => a.uuid === b.uuid);
74
75
  }
75
- async #createSoundFont2(buffer) {
76
- const SoundFont2 = await ExternalLib.SoundFont2();
77
- return new SoundFont2(new Uint8Array(buffer));
78
- }
79
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RegionClipResolver.d.ts","sourceRoot":"","sources":["../../src/ui/RegionClipResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,IAAI,EAAE,GAAG,EAAa,MAAM,kBAAkB,CAAA;AACzE,OAAO,EAAC,KAAK,EAAmB,IAAI,EAAW,MAAM,kBAAkB,CAAA;AACvE,OAAO,EACH,mBAAmB,EAGnB,eAAe,EAGlB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,sBAAsB,EAAC,MAAM,0BAA0B,CAAA;AAE/D,MAAM,MAAM,QAAQ,GAAG;IACnB,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,mBAAmB,CAAA;CAC9B,GAAG;IACA,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,KAAK,EAAE,IAAI,CAAA;IACX,GAAG,EAAE,IAAI,CAAA;CACZ,GAAG;IACA,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,mBAAmB,CAAA;IAC3B,QAAQ,EAAE,IAAI,CAAA;CACjB,GAAG;IACA,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,QAAQ,EAAE,IAAI,CAAA;CACjB,CAAA;AAED,UAAU,IAAK,SAAQ,KAAK;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAC;AAO7C,qBAAa,kBAAkB;;IAC3B,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,EACtC,QAAQ,EAAE,aAAa,CAAC,mBAAmB,CAAC,EAC5C,QAAQ,EAAE,sBAAsB,EAChC,UAAU,GAAE,GAAO,GAAG,IAAI;IAY/C,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI;IAO9E,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,IAAI;IAInE,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAuBlD,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC;gBAuC5D,QAAQ,EAAE,sBAAsB,EAAE,MAAM,EAAE,eAAe;IAMrE,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI;IAK1C,YAAY,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI;CAyErD"}
1
+ {"version":3,"file":"RegionClipResolver.d.ts","sourceRoot":"","sources":["../../src/ui/RegionClipResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,IAAI,EAAE,GAAG,EAAa,MAAM,kBAAkB,CAAA;AACzE,OAAO,EAAC,KAAK,EAAmB,IAAI,EAAW,MAAM,kBAAkB,CAAA;AACvE,OAAO,EACH,mBAAmB,EAGnB,eAAe,EAGlB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,sBAAsB,EAAC,MAAM,0BAA0B,CAAA;AAE/D,MAAM,MAAM,QAAQ,GAAG;IACnB,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,mBAAmB,CAAA;CAC9B,GAAG;IACA,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,KAAK,EAAE,IAAI,CAAA;IACX,GAAG,EAAE,IAAI,CAAA;CACZ,GAAG;IACA,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,mBAAmB,CAAA;IAC3B,QAAQ,EAAE,IAAI,CAAA;CACjB,GAAG;IACA,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,QAAQ,EAAE,IAAI,CAAA;CACjB,CAAA;AAED,UAAU,IAAK,SAAQ,KAAK;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAC;AAO7C,qBAAa,kBAAkB;;IAC3B,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,EACtC,QAAQ,EAAE,aAAa,CAAC,mBAAmB,CAAC,EAC5C,QAAQ,EAAE,sBAAsB,EAChC,UAAU,GAAE,GAAO,GAAG,IAAI;IAY/C,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI;IAO9E,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,IAAI;IAInE,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAuBlD,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC;gBAuC5D,QAAQ,EAAE,sBAAsB,EAAE,MAAM,EAAE,eAAe;IAMrE,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI;IAK1C,YAAY,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI;CA+ErD"}
@@ -106,16 +106,21 @@ export class RegionClipResolver {
106
106
  #createTasksFromMasks(masks) {
107
107
  const tasks = [];
108
108
  masks.forEach(({ position, complete }) => {
109
- for (const region of this.#ground.regions.collection.iterateRange(position, complete)) {
109
+ // Iterate from 0 to find all regions that OVERLAP with [position, complete],
110
+ // not just regions that START within that range
111
+ for (const region of this.#ground.regions.collection.iterateRange(0, complete)) {
112
+ if (region.position >= complete) {
113
+ break;
114
+ } // past the mask, done
115
+ if (region.complete <= position) {
116
+ continue;
117
+ } // ends before mask, skip
110
118
  if (region.isSelected && !this.#strategy.showOrigin()) {
111
119
  continue;
112
120
  }
113
121
  else if (region.duration <= 0) {
114
122
  return panic(`Invalid duration(${region.duration})`);
115
123
  }
116
- else if (region.complete <= position || region.position >= complete) {
117
- return panic("Not overlapping");
118
- }
119
124
  const positionIn = region.position >= position;
120
125
  const completeIn = region.complete <= complete;
121
126
  if (positionIn && completeIn) {
@@ -154,9 +159,13 @@ export class RegionClipResolver {
154
159
  case "start":
155
160
  if (UnionAdapterTypes.isLoopableRegion(region)) {
156
161
  const delta = task.position - region.position;
162
+ // Capture old values BEFORE changing position (they depend on position for TimeBase.Seconds)
163
+ const oldDuration = region.duration;
164
+ const oldLoopOffset = region.loopOffset;
165
+ const oldLoopDuration = region.loopDuration;
157
166
  region.position = region.position + delta;
158
- region.duration = region.duration - delta;
159
- region.loopOffset = mod(region.loopOffset + delta, region.loopDuration);
167
+ region.duration = oldDuration - delta;
168
+ region.loopOffset = mod(oldLoopOffset + delta, oldLoopDuration);
160
169
  }
161
170
  else {
162
171
  return panic("Not yet implemented");