@opendaw/studio-core 0.0.84 → 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 (53) 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/Preferences.d.ts +2 -0
  13. package/dist/Preferences.d.ts.map +1 -1
  14. package/dist/Preferences.js +1 -0
  15. package/dist/Storage.d.ts.map +1 -1
  16. package/dist/Storage.js +14 -5
  17. package/dist/capture/Capture.d.ts +4 -1
  18. package/dist/capture/Capture.d.ts.map +1 -1
  19. package/dist/capture/Capture.js +4 -0
  20. package/dist/capture/RecordAudio.d.ts.map +1 -1
  21. package/dist/capture/RecordAudio.js +4 -2
  22. package/dist/capture/RecordMidi.d.ts.map +1 -1
  23. package/dist/capture/RecordMidi.js +1 -0
  24. package/dist/capture/Recording.d.ts.map +1 -1
  25. package/dist/capture/Recording.js +1 -0
  26. package/dist/midi/MIDILearning.d.ts.map +1 -1
  27. package/dist/midi/MIDILearning.js +0 -1
  28. package/dist/processors.js +14 -14
  29. package/dist/processors.js.map +4 -4
  30. package/dist/project/Project.d.ts +2 -2
  31. package/dist/project/Project.d.ts.map +1 -1
  32. package/dist/project/Project.js +15 -9
  33. package/dist/project/ProjectApi.js +2 -2
  34. package/dist/project/ProjectBundle.d.ts.map +1 -1
  35. package/dist/project/ProjectBundle.js +4 -3
  36. package/dist/project/ProjectMigration.d.ts.map +1 -1
  37. package/dist/project/ProjectMigration.js +16 -1
  38. package/dist/project/audio/AudioContentModifier.d.ts.map +1 -1
  39. package/dist/project/audio/AudioContentModifier.js +15 -2
  40. package/dist/samples/DefaultSampleLoader.d.ts.map +1 -1
  41. package/dist/samples/DefaultSampleLoader.js +8 -4
  42. package/dist/samples/DefaultSampleLoaderManager.js +1 -1
  43. package/dist/soundfont/DefaultSoundfontLoader.d.ts.map +1 -1
  44. package/dist/soundfont/DefaultSoundfontLoader.js +8 -4
  45. package/dist/ui/RegionClipResolver.d.ts.map +1 -1
  46. package/dist/ui/RegionClipResolver.js +15 -6
  47. package/dist/ui/RegionModifyStrategies.js +3 -3
  48. package/dist/ui/TimeGrid.d.ts +2 -1
  49. package/dist/ui/TimeGrid.d.ts.map +1 -1
  50. package/dist/ui/TimeGrid.js +28 -14
  51. package/dist/workers-main.js +1 -1
  52. package/dist/workers-main.js.map +3 -3
  53. 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));
@@ -133,10 +133,6 @@ export class Project {
133
133
  get isAudioContext() { return false; }
134
134
  get isMainThread() { return true; }
135
135
  get liveStreamBroadcaster() { return panic("Only available in audio context"); }
136
- get signatureDuration() {
137
- const { nominator, denominator } = this.timelineBox.signature;
138
- return PPQN.fromSignature(nominator.getValue(), denominator.getValue());
139
- }
140
136
  get skeleton() {
141
137
  return {
142
138
  boxGraph: this.boxGraph,
@@ -169,9 +165,19 @@ export class Project {
169
165
  .filter(box => box.accept({ visitAudioFileBox: (_box) => true }))
170
166
  .map(box => box.address.uuid);
171
167
  }
172
- toArrayBuffer() {
173
- 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
+ }
174
179
  }
180
+ toArrayBuffer() { return ProjectSkeleton.encode(this.boxGraph); }
175
181
  copy(env) {
176
182
  return Project.load({ ...this.#env, ...env }, this.toArrayBuffer());
177
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,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,CA4CjF,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"}
@@ -94,7 +94,8 @@ export var ProjectBundle;
94
94
  });
95
95
  }
96
96
  await Promise.all(promises);
97
- 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);
98
99
  const meta = JSON.parse(await asDefined(zip.file(ProjectPaths.ProjectMetaFile)).async("text"));
99
100
  const coverFile = zip.file(ProjectPaths.ProjectCoverFile);
100
101
  const cover = Option.wrap(await coverFile?.async("arraybuffer"));
@@ -118,7 +119,7 @@ export var ProjectBundle;
118
119
  subscription.terminate();
119
120
  }
120
121
  else if (state.type === "error") {
121
- reject(state.reason);
122
+ reject(new Error(state.reason));
122
123
  subscription.terminate();
123
124
  }
124
125
  });
@@ -142,7 +143,7 @@ export var ProjectBundle;
142
143
  subscription.terminate();
143
144
  }
144
145
  else if (state.type === "error") {
145
- reject(state.reason);
146
+ reject(new Error(state.reason));
146
147
  subscription.terminate();
147
148
  }
148
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;CA0OpF"}
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"}
@@ -34,11 +34,18 @@ export class ProjectMigration {
34
34
  }
35
35
  else if (state.type === "error") {
36
36
  queueMicrotask(() => subscription.terminate());
37
- reject(state.reason);
37
+ reject(new Error(state.reason));
38
38
  }
39
39
  });
40
40
  return promise;
41
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
+ }
42
49
  // 1st pass (2nd pass might rely on those changes)
43
50
  for (const box of boxGraph.boxes()) {
44
51
  await box.accept({
@@ -131,6 +138,14 @@ export class ProjectMigration {
131
138
  boxGraph.endTransaction();
132
139
  }
133
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
+ },
134
149
  visitMIDIOutputDeviceBox: (deviceBox) => {
135
150
  const id = deviceBox.deprecatedDevice.id.getValue();
136
151
  const label = deviceBox.deprecatedDevice.label.getValue();
@@ -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;CA2BJ"}
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();
@@ -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
  }
@@ -23,7 +23,7 @@ export class DefaultSampleLoaderManager {
23
23
  subscription = loader.subscribe(state => {
24
24
  if (state.type === "error") {
25
25
  queueMicrotask(() => subscription.terminate());
26
- reject(state.reason);
26
+ reject(new Error(state.reason));
27
27
  }
28
28
  else if (loader.data.nonEmpty()) {
29
29
  queueMicrotask(() => subscription.terminate());
@@ -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;;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;CA8CrB"}
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"}
@@ -59,8 +59,10 @@ export class DefaultSoundfontLoader {
59
59
  const fetchProgress = progress => this.#setState({ type: "progress", progress });
60
60
  const fetchResult = await Promises.tryCatch(this.#manager.fetch(this.#uuid, fetchProgress));
61
61
  if (fetchResult.status === "rejected") {
62
- console.warn(fetchResult.error);
63
- 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 });
64
66
  return;
65
67
  }
66
68
  const [file, meta] = fetchResult.value;
@@ -74,8 +76,10 @@ export class DefaultSoundfontLoader {
74
76
  this.#setState({ type: "loaded" });
75
77
  }
76
78
  else {
77
- console.warn(storeResult.error);
78
- 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 });
79
83
  }
80
84
  }
81
85
  }
@@ -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");
@@ -15,9 +15,9 @@ export var RegionModifyStrategy;
15
15
  (function (RegionModifyStrategy) {
16
16
  RegionModifyStrategy.Identity = Object.freeze({
17
17
  readPosition: (region) => region.position,
18
- readComplete: (region) => region.complete,
19
- readLoopOffset: (region) => region.loopOffset,
20
- readLoopDuration: (region) => region.loopDuration,
18
+ readComplete: (region) => region.resolveComplete(region.position),
19
+ readLoopOffset: (region) => region.resolveLoopOffset(region.position),
20
+ readLoopDuration: (region) => region.resolveLoopDuration(region.position),
21
21
  readMirror: (region) => region.isMirrowed,
22
22
  translateTrackIndex: (value) => value,
23
23
  iterateRange: (regions, from, to) => regions.iterateRange(from, to)
@@ -1,5 +1,6 @@
1
1
  import { int } from "@opendaw/lib-std";
2
2
  import { TimelineRange } from "./TimelineRange";
3
+ import { SignatureTrackAdapter } from "@opendaw/studio-adapters";
3
4
  export declare namespace TimeGrid {
4
5
  type Signature = [int, int];
5
6
  type Options = {
@@ -14,6 +15,6 @@ export declare namespace TimeGrid {
14
15
  pulse: number;
15
16
  };
16
17
  type Designer = (fragment: Fragment) => void;
17
- const fragment: ([nominator, denominator]: Signature, range: TimelineRange, designer: Designer, options?: Options) => void;
18
+ const fragment: (signatureTrack: SignatureTrackAdapter, range: TimelineRange, designer: Designer, options?: Options) => void;
18
19
  }
19
20
  //# sourceMappingURL=TimeGrid.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TimeGrid.d.ts","sourceRoot":"","sources":["../../src/ui/TimeGrid.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAgB,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAE7C,yBAAiB,QAAQ,CAAC;IACtB,KAAY,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IAClC,KAAY,OAAO,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C,KAAY,QAAQ,GAAG;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5G,KAAY,QAAQ,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;IAE5C,MAAM,QAAQ,GAAI,0BAA0B,SAAS,EACnC,OAAO,aAAa,EAAE,UAAU,QAAQ,EAAE,UAAU,OAAO,KAAG,IA4DtF,CAAA;CACJ"}
1
+ {"version":3,"file":"TimeGrid.d.ts","sourceRoot":"","sources":["../../src/ui/TimeGrid.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAuB,MAAM,kBAAkB,CAAA;AAC1D,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAC,qBAAqB,EAAC,MAAM,0BAA0B,CAAA;AAE9D,yBAAiB,QAAQ,CAAC;IACtB,KAAY,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IAClC,KAAY,OAAO,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C,KAAY,QAAQ,GAAG;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5G,KAAY,QAAQ,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;IA8C5C,MAAM,QAAQ,GAAI,gBAAgB,qBAAqB,EACrC,OAAO,aAAa,EAAE,UAAU,QAAQ,EAAE,UAAU,OAAO,KAAG,IAmBtF,CAAA;CACJ"}
@@ -1,15 +1,10 @@
1
1
  import { PPQN } from "@opendaw/lib-dsp";
2
- import { quantizeFloor } from "@opendaw/lib-std";
2
+ import { isDefined, Iterables } from "@opendaw/lib-std";
3
3
  export var TimeGrid;
4
4
  (function (TimeGrid) {
5
- TimeGrid.fragment = ([nominator, denominator], range, designer, options) => {
6
- const unitsPerPixel = range.unitsPerPixel;
7
- if (unitsPerPixel <= 0) {
8
- return;
9
- }
5
+ const computeInterval = (nominator, denominator, unitsPerPixel, minLength) => {
10
6
  const barPulses = PPQN.fromSignature(nominator, denominator);
11
7
  const beatPulses = PPQN.fromSignature(1, denominator);
12
- const minLength = options?.minLength ?? 48;
13
8
  let interval = barPulses;
14
9
  let pixel = interval / unitsPerPixel;
15
10
  if (pixel > minLength) {
@@ -62,13 +57,32 @@ export var TimeGrid;
62
57
  pixel = interval / unitsPerPixel;
63
58
  }
64
59
  }
65
- const p0 = quantizeFloor(range.unitMin, interval);
66
- const p1 = range.unitMax;
67
- for (let pulse = p0; pulse < p1; pulse += interval) {
68
- const { bars, beats, semiquavers, ticks } = PPQN.toParts(pulse, nominator, denominator);
69
- const isBeat = ticks === 0 && semiquavers === 0;
70
- const isBar = isBeat && beats === 0;
71
- designer({ bars, beats, ticks, isBar, isBeat, pulse });
60
+ return interval;
61
+ };
62
+ TimeGrid.fragment = (signatureTrack, range, designer, options) => {
63
+ const unitsPerPixel = range.unitsPerPixel;
64
+ if (unitsPerPixel <= 0) {
65
+ return;
66
+ }
67
+ const minLength = options?.minLength ?? 48;
68
+ for (const [prev, next] of Iterables.pairWise(signatureTrack.iterateAll())) {
69
+ const { accumulatedPpqn, accumulatedBars, nominator, denominator } = prev;
70
+ const interval = computeInterval(prev.nominator, prev.denominator, unitsPerPixel, minLength);
71
+ const barDuration = PPQN.fromSignature(nominator, denominator);
72
+ const p0 = accumulatedPpqn;
73
+ const p1 = isDefined(next) ? next.accumulatedPpqn : range.unitMax;
74
+ for (let pulse = p0; pulse < p1; pulse += interval) {
75
+ if (pulse < range.unitMin - barDuration) {
76
+ continue;
77
+ }
78
+ if (pulse >= range.unitMax) {
79
+ break;
80
+ }
81
+ const { bars, beats, semiquavers, ticks } = PPQN.toParts(pulse - accumulatedPpqn, nominator, denominator);
82
+ const isBeat = ticks === 0 && semiquavers === 0;
83
+ const isBar = isBeat && beats === 0;
84
+ designer({ bars: bars + accumulatedBars, beats, ticks, isBar, isBeat, pulse });
85
+ }
72
86
  }
73
87
  };
74
88
  })(TimeGrid || (TimeGrid = {}));