@opendaw/studio-core 0.0.126 → 0.0.128

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 (82) hide show
  1. package/dist/AssetService.d.ts.map +1 -1
  2. package/dist/AssetService.js +7 -7
  3. package/dist/AudioConsolidation.d.ts.map +1 -1
  4. package/dist/AudioConsolidation.js +2 -2
  5. package/dist/EffectBox.d.ts +2 -2
  6. package/dist/EffectBox.d.ts.map +1 -1
  7. package/dist/EffectFactories.d.ts +20 -14
  8. package/dist/EffectFactories.d.ts.map +1 -1
  9. package/dist/EffectFactories.js +88 -20
  10. package/dist/EffectFactory.d.ts +1 -0
  11. package/dist/EffectFactory.d.ts.map +1 -1
  12. package/dist/Engine.d.ts +2 -1
  13. package/dist/Engine.d.ts.map +1 -1
  14. package/dist/EngineFacade.d.ts +2 -1
  15. package/dist/EngineFacade.d.ts.map +1 -1
  16. package/dist/EngineFacade.js +3 -0
  17. package/dist/EngineWorklet.d.ts +2 -1
  18. package/dist/EngineWorklet.d.ts.map +1 -1
  19. package/dist/EngineWorklet.js +11 -1
  20. package/dist/Mixer.d.ts.map +1 -1
  21. package/dist/Mixer.js +3 -2
  22. package/dist/OfflineEngineRenderer.d.ts.map +1 -1
  23. package/dist/OfflineEngineRenderer.js +41 -3
  24. package/dist/StudioPreferences.d.ts +1 -1
  25. package/dist/StudioSettings.d.ts +1 -1
  26. package/dist/StudioSettings.js +2 -2
  27. package/dist/capture/RecordAudio.d.ts.map +1 -1
  28. package/dist/capture/RecordAudio.js +48 -18
  29. package/dist/capture/RecordAutomation.d.ts.map +1 -1
  30. package/dist/capture/RecordAutomation.js +219 -198
  31. package/dist/capture/RecordMidi.d.ts.map +1 -1
  32. package/dist/capture/RecordMidi.js +1 -1
  33. package/dist/cloud/CloudBackupSamples.js +1 -1
  34. package/dist/dawproject/DawProjectExporter.js +1 -1
  35. package/dist/dawproject/DawProjectService.d.ts.map +1 -1
  36. package/dist/dawproject/DawProjectService.js +3 -16
  37. package/dist/index.d.ts +0 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +0 -1
  40. package/dist/midi/MidiDevices.d.ts.map +1 -1
  41. package/dist/midi/MidiDevices.js +8 -2
  42. package/dist/offline-engine.js +1 -1
  43. package/dist/offline-engine.js.map +3 -3
  44. package/dist/processors.js +37 -25
  45. package/dist/processors.js.map +4 -4
  46. package/dist/project/Project.d.ts.map +1 -1
  47. package/dist/project/Project.js +30 -5
  48. package/dist/project/Recovery.js +1 -1
  49. package/dist/project/migration/MigrateAudioClipBox.d.ts.map +1 -1
  50. package/dist/project/migration/MigrateAudioClipBox.js +7 -0
  51. package/dist/project/migration/MigrateAudioRegionBox.d.ts.map +1 -1
  52. package/dist/project/migration/MigrateAudioRegionBox.js +7 -0
  53. package/dist/samples/OpenSampleAPI.d.ts.map +1 -1
  54. package/dist/samples/OpenSampleAPI.js +1 -1
  55. package/dist/samples/SampleService.js +1 -1
  56. package/dist/samples/SampleStorage.d.ts.map +1 -1
  57. package/dist/samples/SampleStorage.js +1 -1
  58. package/dist/ui/clipboard/ClipboardManager.d.ts.map +1 -1
  59. package/dist/ui/clipboard/ClipboardManager.js +18 -4
  60. package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.d.ts.map +1 -1
  61. package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.js +8 -2
  62. package/dist/ui/clipboard/types/DevicesClipboardHandler.d.ts.map +1 -1
  63. package/dist/ui/clipboard/types/DevicesClipboardHandler.js +77 -10
  64. package/dist/ui/clipboard/types/DevicesClipboardHandler.test.d.ts +2 -0
  65. package/dist/ui/clipboard/types/DevicesClipboardHandler.test.d.ts.map +1 -0
  66. package/dist/ui/clipboard/types/DevicesClipboardHandler.test.js +1154 -0
  67. package/dist/ui/timeline/RegionClipResolver.d.ts.map +1 -1
  68. package/dist/ui/timeline/RegionClipResolver.js +21 -29
  69. package/dist/ui/timeline/TimeGrid.d.ts +2 -0
  70. package/dist/ui/timeline/TimeGrid.d.ts.map +1 -1
  71. package/dist/ui/timeline/TimeGrid.js +13 -1
  72. package/dist/workers-main.js +1 -1
  73. package/dist/workers-main.js.map +3 -3
  74. package/dist/ysync/YService.d.ts +6 -1
  75. package/dist/ysync/YService.d.ts.map +1 -1
  76. package/dist/ysync/YService.js +2 -2
  77. package/dist/ysync/YSync.d.ts.map +1 -1
  78. package/dist/ysync/YSync.js +1 -0
  79. package/package.json +15 -15
  80. package/dist/WavFile.d.ts +0 -7
  81. package/dist/WavFile.d.ts.map +0 -1
  82. package/dist/WavFile.js +0 -120
@@ -1 +1 @@
1
- {"version":3,"file":"OfflineEngineRenderer.d.ts","sourceRoot":"","sources":["../src/OfflineEngineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAU,GAAG,EAAuB,MAAM,EAA4D,MAAM,kBAAkB,CAAA;AAC5J,OAAO,EAAC,SAAS,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAGhD,OAAO,EAKH,wBAAwB,EAKxB,yBAAyB,EAC5B,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAOjC,qBAAa,qBAAqB;;IAC9B,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKjC,MAAM,CAAC,YAAY,IAAI,MAAM;WAIhB,MAAM,CAAC,MAAM,EAAE,OAAO,EACf,sBAAsB,EAAE,MAAM,CAAC,wBAAwB,CAAC,EACxD,UAAU,GAAE,GAAY,GACzC,OAAO,CAAC,qBAAqB,CAAC;WAqHpB,KAAK,CAAC,MAAM,EAAE,OAAO,EACf,sBAAsB,EAAE,MAAM,CAAC,wBAAwB,CAAC,EACxD,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,EACxC,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,GAAE,GAAY,GACxC,OAAO,CAAC,SAAS,CAAC;IA0BrB,OAAO;IAoBP,IAAI,UAAU,IAAI,GAAG,CAA0B;IAC/C,IAAI,gBAAgB,IAAI,GAAG,CAAgC;IAC3D,IAAI,WAAW,IAAI,GAAG,CAA2B;IAEjD,IAAI,IAAI,IAAI;IAIZ,IAAI,IAAI,IAAI;IAKZ,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IAI3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrC,SAAS,IAAI,IAAI;IAKX,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM3C,MAAM,CACR,MAAM,EAAE,yBAAyB,EACjC,WAAW,EAAE,IAAI,EACjB,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,EACxC,WAAW,CAAC,EAAE,WAAW,GAC1B,OAAO,CAAC,SAAS,CAAC;CA0CxB"}
1
+ {"version":3,"file":"OfflineEngineRenderer.d.ts","sourceRoot":"","sources":["../src/OfflineEngineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,sBAAsB,EAEtB,GAAG,EAGH,MAAM,EAOT,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,SAAS,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAIhD,OAAO,EAKH,wBAAwB,EAKxB,yBAAyB,EAC5B,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAOjC,qBAAa,qBAAqB;;IAC9B,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKjC,MAAM,CAAC,YAAY,IAAI,MAAM;WAIhB,MAAM,CAAC,MAAM,EAAE,OAAO,EACf,sBAAsB,EAAE,MAAM,CAAC,wBAAwB,CAAC,EACxD,UAAU,GAAE,GAAY,GACzC,OAAO,CAAC,qBAAqB,CAAC;WAgKpB,KAAK,CAAC,MAAM,EAAE,OAAO,EACf,sBAAsB,EAAE,MAAM,CAAC,wBAAwB,CAAC,EACxD,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,EACxC,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,GAAE,GAAY,GACxC,OAAO,CAAC,SAAS,CAAC;IA2BrB,OAAO;IAoBP,IAAI,UAAU,IAAI,GAAG,CAA0B;IAC/C,IAAI,gBAAgB,IAAI,GAAG,CAAgC;IAC3D,IAAI,WAAW,IAAI,GAAG,CAA2B;IAEjD,IAAI,IAAI,IAAI;IAIZ,IAAI,IAAI,IAAI;IAKZ,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IAI3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrC,SAAS,IAAI,IAAI;IAKX,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM3C,MAAM,CACR,MAAM,EAAE,yBAAyB,EACjC,WAAW,EAAE,IAAI,EACjB,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,EACxC,WAAW,CAAC,EAAE,WAAW,GAC1B,OAAO,CAAC,SAAS,CAAC;CA0CxB"}
@@ -1,5 +1,6 @@
1
- import { Errors, isDefined, Option, panic, SyncStream, Terminable, Terminator, TimeSpan } from "@opendaw/lib-std";
1
+ import { Errors, isDefined, Option, panic, SyncStream, Terminable, Terminator, TimeSpan, UUID } from "@opendaw/lib-std";
2
2
  import { AudioData } from "@opendaw/lib-dsp";
3
+ import { ApparatDeviceBox, SpielwerkDeviceBox, WerkstattDeviceBox } from "@opendaw/studio-boxes";
3
4
  import { Communicator, Messenger, Wait } from "@opendaw/lib-runtime";
4
5
  import { AnimationFrame } from "@opendaw/lib-dom";
5
6
  import { EngineStateSchema, ExportStemsConfiguration } from "@opendaw/studio-adapters";
@@ -26,6 +27,9 @@ export class OfflineEngineRenderer {
26
27
  initialize(enginePort, config) {
27
28
  return dispatcher.dispatchAndReturn(this.initialize, enginePort, config);
28
29
  }
30
+ addModule(code) {
31
+ return dispatcher.dispatchAndReturn(this.addModule, code);
32
+ }
29
33
  render(config) {
30
34
  return dispatcher.dispatchAndReturn(this.render, config);
31
35
  }
@@ -76,7 +80,10 @@ export class OfflineEngineRenderer {
76
80
  return response.arrayBuffer();
77
81
  },
78
82
  notifyClipSequenceChanges: () => { },
79
- switchMarkerState: () => { }
83
+ switchMarkerState: () => { },
84
+ deviceMessage: (uuid, message) => {
85
+ console.warn(`OFFLINE-ENGINE device(${uuid}): ${message}`);
86
+ }
80
87
  });
81
88
  const engineCommands = Communicator.sender(engineMessenger.channel("engine-commands"), dispatcher => new class {
82
89
  play() { dispatcher.dispatchAndForget(this.play); }
@@ -99,6 +106,36 @@ export class OfflineEngineRenderer {
99
106
  channel.port2.start();
100
107
  terminator.own(source.liveStreamReceiver.connect(engineMessenger.channel("engine-live-data")));
101
108
  const { port, sab } = terminator.own(MIDIReceiver.create(() => 0, (deviceId, data, relativeTimeInMs) => source.receivedMIDIFromEngine(deviceId, data, relativeTimeInMs)));
109
+ const loadScriptDevice = async (code, headerPattern, registryName, functionName, uuid) => {
110
+ const match = code.match(headerPattern);
111
+ if (match === null) {
112
+ return;
113
+ }
114
+ const userCode = code.slice(match[0].length);
115
+ const update = parseInt(match[3]);
116
+ await protocol.addModule(`
117
+ if (typeof globalThis.openDAW === "undefined") { globalThis.openDAW = {} }
118
+ if (typeof globalThis.openDAW.${registryName} === "undefined") { globalThis.openDAW.${registryName} = {} }
119
+ globalThis.openDAW.${registryName}["${uuid}"] = {
120
+ update: ${update},
121
+ create: (function ${functionName}() {
122
+ ${userCode}
123
+ return Processor
124
+ })()
125
+ }
126
+ `);
127
+ };
128
+ for (const box of source.boxGraph.boxes()) {
129
+ if (box instanceof WerkstattDeviceBox) {
130
+ await loadScriptDevice(box.code.getValue(), /^\/\/ @werkstatt (\w+) (\d+) (\d+)\n/, "werkstattProcessors", "werkstatt", UUID.toString(box.address.uuid));
131
+ }
132
+ else if (box instanceof SpielwerkDeviceBox) {
133
+ await loadScriptDevice(box.code.getValue(), /^\/\/ @spielwerk (\w+) (\d+) (\d+)\n/, "spielwerkProcessors", "spielwerk", UUID.toString(box.address.uuid));
134
+ }
135
+ else if (box instanceof ApparatDeviceBox) {
136
+ await loadScriptDevice(box.code.getValue(), /^\/\/ @apparat (\w+) (\d+) (\d+)\n/, "apparatProcessors", "apparat", UUID.toString(box.address.uuid));
137
+ }
138
+ }
102
139
  await protocol.initialize(channel.port1, {
103
140
  sampleRate,
104
141
  numberOfChannels,
@@ -118,8 +155,9 @@ export class OfflineEngineRenderer {
118
155
  enabled.setValue(false);
119
156
  boxGraph.endTransaction();
120
157
  const endPosition = source.lastRegionAction();
158
+ const maxDurationSeconds = source.tempoMap.ppqnToSeconds(endPosition) + 30;
121
159
  const renderer = await this.create(source, optExportConfiguration, sampleRate);
122
- const result = await renderer.render({}, endPosition, progress, abortSignal);
160
+ const result = await renderer.render({ maxDurationSeconds }, endPosition, progress, abortSignal);
123
161
  boxGraph.beginTransaction();
124
162
  enabled.setValue(wasEnabled);
125
163
  boxGraph.endTransaction();
@@ -14,7 +14,7 @@ export declare const StudioPreferences: import("@opendaw/lib-fusion").Preference
14
14
  };
15
15
  engine: {
16
16
  "note-audition-while-editing": boolean;
17
- "auto-create-output-compressor": boolean;
17
+ "auto-create-output-maximizer": boolean;
18
18
  "stop-playback-when-overloading": boolean;
19
19
  };
20
20
  pointer: {
@@ -17,7 +17,7 @@ export declare const StudioSettingsSchema: z.ZodObject<{
17
17
  }, z.core.$strip>>;
18
18
  engine: z.ZodDefault<z.ZodObject<{
19
19
  "note-audition-while-editing": z.ZodBoolean;
20
- "auto-create-output-compressor": z.ZodBoolean;
20
+ "auto-create-output-maximizer": z.ZodBoolean;
21
21
  "stop-playback-when-overloading": z.ZodBoolean;
22
22
  }, z.core.$strip>>;
23
23
  pointer: z.ZodDefault<z.ZodObject<{
@@ -24,11 +24,11 @@ export const StudioSettingsSchema = z.object({
24
24
  }).default({ musical: true, absolute: false, details: false, fps: 25 }),
25
25
  "engine": z.object({
26
26
  "note-audition-while-editing": z.boolean(),
27
- "auto-create-output-compressor": z.boolean(),
27
+ "auto-create-output-maximizer": z.boolean(),
28
28
  "stop-playback-when-overloading": z.boolean()
29
29
  }).default({
30
30
  "note-audition-while-editing": true,
31
- "auto-create-output-compressor": true,
31
+ "auto-create-output-maximizer": true,
32
32
  "stop-playback-when-overloading": true
33
33
  }),
34
34
  "pointer": z.object({
@@ -1 +1 @@
1
- {"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAMH,UAAU,EAIb,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAa,mBAAmB,EAA2B,MAAM,0BAA0B,CAAA;AAClG,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAIjC,yBAAiB,WAAW,CAAC;IACzB,KAAK,kBAAkB,GAAG;QACtB,gBAAgB,EAAE,gBAAgB,CAAA;QAClC,UAAU,EAAE,SAAS,CAAA;QACrB,aAAa,EAAE,mBAAmB,CAAA;QAClC,OAAO,EAAE,OAAO,CAAA;QAChB,OAAO,EAAE,OAAO,CAAA;QAChB,aAAa,EAAE,MAAM,CAAA;KACxB,CAAA;IAOD,MAAM,CAAC,MAAM,KAAK,GACd,kFAAgF,kBAAkB,KAChG,UAmLL,CAAA;;CACJ"}
1
+ {"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAMH,UAAU,EAIb,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAa,mBAAmB,EAA2B,MAAM,0BAA0B,CAAA;AAClG,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAIjC,yBAAiB,WAAW,CAAC;IACzB,KAAK,kBAAkB,GAAG;QACtB,gBAAgB,EAAE,gBAAgB,CAAA;QAClC,UAAU,EAAE,SAAS,CAAA;QACrB,aAAa,EAAE,mBAAmB,CAAA;QAClC,OAAO,EAAE,OAAO,CAAA;QAChB,OAAO,EAAE,OAAO,CAAA;QAChB,aAAa,EAAE,MAAM,CAAA;KACxB,CAAA;IAOD,MAAM,CAAC,MAAM,KAAK,GACd,kFAAgF,kBAAkB,KAChG,UA8ML,CAAA;;CACJ"}
@@ -7,6 +7,7 @@ import { RecordTrack } from "./RecordTrack";
7
7
  export var RecordAudio;
8
8
  (function (RecordAudio) {
9
9
  RecordAudio.start = ({ recordingWorklet, sourceNode, sampleManager, project, capture, outputLatency }) => {
10
+ console.debug("[RecordAudio] start", { outputLatency });
10
11
  const terminator = new Terminator();
11
12
  const beats = PPQN.fromSignature(1, project.timelineBox.signature.denominator.getValue());
12
13
  const { editing, engine, boxGraph, timelineBox } = project;
@@ -31,6 +32,7 @@ export var RecordAudio;
31
32
  };
32
33
  const createTakeRegion = (position, waveformOffset, excludeTrack) => {
33
34
  takeNumber++;
35
+ console.debug("[RecordAudio] createTakeRegion", { takeNumber, position, waveformOffset });
34
36
  const trackBox = RecordTrack.findOrCreate(editing, capture.audioUnitBox, TrackType.Audio, excludeTrack);
35
37
  const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
36
38
  const regionBox = AudioRegionBox.create(boxGraph, UUID.generate(), box => {
@@ -48,6 +50,7 @@ export var RecordAudio;
48
50
  return { trackBox, regionBox };
49
51
  };
50
52
  const finalizeTake = (take, durationInSeconds) => {
53
+ console.debug("[RecordAudio] finalizeTake", { durationInSeconds });
51
54
  const { trackBox, regionBox } = take;
52
55
  if (regionBox.isAttached()) {
53
56
  regionBox.duration.setValue(durationInSeconds);
@@ -98,37 +101,64 @@ export var RecordAudio;
98
101
  };
99
102
  recordingWorklet.onSaved = uuid => {
100
103
  project.trackUserCreatedSample(uuid);
101
- editing.modify(() => {
102
- fileBox.ifSome(oldFileBox => {
103
- editing.modify(() => {
104
- const newFileBox = AudioFileBox.create(boxGraph, uuid, box => {
105
- box.fileName.setValue(oldFileBox.fileName.getValue());
106
- box.startInSeconds.setValue(oldFileBox.startInSeconds.getValue());
107
- box.endInSeconds.setValue(oldFileBox.endInSeconds.getValue());
108
- });
109
- for (const pointer of [...oldFileBox.pointerHub.incoming()]) {
110
- pointer.refer(newFileBox);
111
- }
112
- for (const pointer of [...oldFileBox.transientMarkers.pointerHub.incoming()]) {
113
- pointer.refer(newFileBox.transientMarkers);
114
- }
104
+ fileBox.ifSome(oldFileBox => {
105
+ if (!oldFileBox.isAttached() || oldFileBox.pointerHub.isEmpty()) {
106
+ return;
107
+ }
108
+ editing.modify(() => {
109
+ const incomingPointers = [...oldFileBox.pointerHub.incoming()];
110
+ const incomingTransientPointers = [...oldFileBox.transientMarkers.pointerHub.incoming()];
111
+ if (incomingPointers.length === 0) {
115
112
  oldFileBox.delete();
113
+ return;
114
+ }
115
+ const newFileBox = AudioFileBox.create(boxGraph, uuid, box => {
116
+ box.fileName.setValue(oldFileBox.fileName.getValue());
117
+ box.startInSeconds.setValue(oldFileBox.startInSeconds.getValue());
118
+ box.endInSeconds.setValue(oldFileBox.endInSeconds.getValue());
116
119
  });
120
+ for (const pointer of incomingPointers) {
121
+ pointer.refer(newFileBox);
122
+ }
123
+ for (const pointer of incomingTransientPointers) {
124
+ pointer.refer(newFileBox.transientMarkers);
125
+ }
126
+ oldFileBox.delete();
117
127
  });
118
128
  });
119
129
  };
120
130
  terminator.ownAll(Terminable.create(() => {
121
131
  tryCatch(() => sourceNode.disconnect(recordingWorklet));
122
132
  if (recordingWorklet.numberOfFrames === 0 || fileBox.isEmpty()) {
123
- console.debug("Abort recording audio.");
133
+ console.debug("[RecordAudio] abort", {
134
+ numberOfFrames: recordingWorklet.numberOfFrames,
135
+ hasFile: fileBox.nonEmpty()
136
+ });
124
137
  sampleManager.remove(originalUuid);
125
138
  recordingWorklet.terminate();
126
139
  }
127
140
  else {
128
- currentTake.ifSome(({ regionBox: { duration } }) => {
129
- recordingWorklet.limit(Math.ceil((currentWaveformOffset + duration.getValue()) * sampleRate));
141
+ // fixes #840: short recordings (e.g. count-in) can leave zero-duration regions
142
+ currentTake.ifSome(({ regionBox }) => {
143
+ const duration = regionBox.duration.getValue();
144
+ if (duration <= 0) {
145
+ console.debug("[RecordAudio] stop: deleting zero-duration region", { takeNumber });
146
+ editing.modify(() => regionBox.delete(), false);
147
+ }
148
+ else {
149
+ console.debug("[RecordAudio] stop", {
150
+ takeNumber,
151
+ duration,
152
+ numberOfFrames: recordingWorklet.numberOfFrames
153
+ });
154
+ recordingWorklet.limit(Math.ceil((currentWaveformOffset + duration) * sampleRate));
155
+ }
156
+ });
157
+ fileBox.ifSome(box => {
158
+ if (box.isAttached()) {
159
+ box.endInSeconds.setValue(recordingWorklet.numberOfFrames / sampleRate);
160
+ }
130
161
  });
131
- fileBox.ifSome(({ endInSeconds }) => endInSeconds.setValue(recordingWorklet.numberOfFrames / sampleRate));
132
162
  }
133
163
  }), engine.position.catchupAndSubscribe(owner => {
134
164
  const isCountingIn = engine.isCountingIn.getValue();
@@ -1 +1 @@
1
- {"version":3,"file":"RecordAutomation.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAutomation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,UAAU,EAAkB,MAAM,kBAAkB,CAAA;AAc5G,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAGlC,yBAAiB,gBAAgB,CAAC;IAevB,MAAM,KAAK,GAAI,SAAS,OAAO,KAAG,UAwPxC,CAAA;CACJ"}
1
+ {"version":3,"file":"RecordAutomation.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAutomation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,UAAU,EAAkB,MAAM,kBAAkB,CAAA;AAc5G,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAGlC,yBAAiB,gBAAgB,CAAC;IAsPvB,MAAM,KAAK,GAAI,SAAS,OAAO,KAAG,UA6DxC,CAAA;CAEJ"}