@opendaw/studio-core 0.0.100 → 0.0.102

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 (114) hide show
  1. package/dist/AssetService.js +2 -2
  2. package/dist/EffectFactories.d.ts +2 -0
  3. package/dist/EffectFactories.d.ts.map +1 -1
  4. package/dist/EffectFactories.js +44 -24
  5. package/dist/Engine.d.ts +5 -0
  6. package/dist/Engine.d.ts.map +1 -1
  7. package/dist/EngineFacade.d.ts +5 -0
  8. package/dist/EngineFacade.d.ts.map +1 -1
  9. package/dist/EngineFacade.js +23 -2
  10. package/dist/EngineWorklet.d.ts +5 -0
  11. package/dist/EngineWorklet.d.ts.map +1 -1
  12. package/dist/EngineWorklet.js +107 -11
  13. package/dist/HRClockWorker.d.ts +7 -0
  14. package/dist/HRClockWorker.d.ts.map +1 -0
  15. package/dist/HRClockWorker.js +54 -0
  16. package/dist/OfflineEngineRenderer.d.ts.map +1 -1
  17. package/dist/OfflineEngineRenderer.js +6 -2
  18. package/dist/RecordingWorklet.d.ts +2 -1
  19. package/dist/RecordingWorklet.d.ts.map +1 -1
  20. package/dist/RecordingWorklet.js +9 -1
  21. package/dist/Storage.d.ts.map +1 -1
  22. package/dist/Storage.js +1 -0
  23. package/dist/StudioPreferences.d.ts +9 -0
  24. package/dist/StudioPreferences.d.ts.map +1 -1
  25. package/dist/StudioSettings.d.ts +14 -0
  26. package/dist/StudioSettings.d.ts.map +1 -1
  27. package/dist/StudioSettings.js +19 -2
  28. package/dist/capture/CaptureAudio.d.ts +3 -1
  29. package/dist/capture/CaptureAudio.d.ts.map +1 -1
  30. package/dist/capture/CaptureAudio.js +51 -29
  31. package/dist/capture/MonitoringMode.d.ts +2 -0
  32. package/dist/capture/MonitoringMode.d.ts.map +1 -0
  33. package/dist/capture/MonitoringMode.js +1 -0
  34. package/dist/capture/RecordAudio.d.ts.map +1 -1
  35. package/dist/capture/RecordAudio.js +1 -0
  36. package/dist/capture/index.d.ts +1 -0
  37. package/dist/capture/index.d.ts.map +1 -1
  38. package/dist/capture/index.js +1 -0
  39. package/dist/dawproject/DawProjectImporter.d.ts.map +1 -1
  40. package/dist/dawproject/DawProjectImporter.js +4 -0
  41. package/dist/processors.js +24 -24
  42. package/dist/processors.js.map +4 -4
  43. package/dist/project/Project.d.ts +7 -1
  44. package/dist/project/Project.d.ts.map +1 -1
  45. package/dist/project/Project.js +58 -8
  46. package/dist/project/ProjectApi.d.ts +1 -1
  47. package/dist/project/ProjectApi.d.ts.map +1 -1
  48. package/dist/project/ProjectApi.js +17 -3
  49. package/dist/project/ProjectMigration.d.ts.map +1 -1
  50. package/dist/project/ProjectMigration.js +3 -2
  51. package/dist/project/audio/AudioContentFactory.d.ts +5 -0
  52. package/dist/project/audio/AudioContentFactory.d.ts.map +1 -1
  53. package/dist/project/audio/AudioContentFactory.js +13 -0
  54. package/dist/project/migration/MigrateNeuralAmpDeviceBox.d.ts +4 -0
  55. package/dist/project/migration/MigrateNeuralAmpDeviceBox.d.ts.map +1 -0
  56. package/dist/project/migration/MigrateNeuralAmpDeviceBox.js +29 -0
  57. package/dist/project/migration/index.d.ts +1 -0
  58. package/dist/project/migration/index.d.ts.map +1 -1
  59. package/dist/project/migration/index.js +1 -0
  60. package/dist/ui/{generic → clipboard}/ClipboardManager.d.ts +3 -3
  61. package/dist/ui/clipboard/ClipboardManager.d.ts.map +1 -0
  62. package/dist/ui/clipboard/ClipboardManager.js +147 -0
  63. package/dist/ui/clipboard/ClipboardUtils.d.ts +12 -0
  64. package/dist/ui/clipboard/ClipboardUtils.d.ts.map +1 -0
  65. package/dist/ui/clipboard/ClipboardUtils.js +94 -0
  66. package/dist/ui/{generic → clipboard}/ContextMenu.d.ts +1 -1
  67. package/dist/ui/clipboard/ContextMenu.d.ts.map +1 -0
  68. package/dist/ui/{generic → clipboard}/ContextMenu.js +1 -1
  69. package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.d.ts +18 -0
  70. package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.d.ts.map +1 -0
  71. package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.js +215 -0
  72. package/dist/ui/clipboard/types/DevicesClipboardHandler.d.ts +18 -0
  73. package/dist/ui/clipboard/types/DevicesClipboardHandler.d.ts.map +1 -0
  74. package/dist/ui/clipboard/types/DevicesClipboardHandler.js +188 -0
  75. package/dist/ui/clipboard/types/NotesClipboardHandler.d.ts +21 -0
  76. package/dist/ui/clipboard/types/NotesClipboardHandler.d.ts.map +1 -0
  77. package/dist/ui/clipboard/types/NotesClipboardHandler.js +72 -0
  78. package/dist/ui/clipboard/types/RegionsClipboardHandler.d.ts +24 -0
  79. package/dist/ui/clipboard/types/RegionsClipboardHandler.d.ts.map +1 -0
  80. package/dist/ui/clipboard/types/RegionsClipboardHandler.js +137 -0
  81. package/dist/ui/clipboard/types/ValuesClipboardHandler.d.ts +22 -0
  82. package/dist/ui/clipboard/types/ValuesClipboardHandler.d.ts.map +1 -0
  83. package/dist/ui/clipboard/types/ValuesClipboardHandler.js +135 -0
  84. package/dist/ui/index.d.ts +14 -3
  85. package/dist/ui/index.d.ts.map +1 -1
  86. package/dist/ui/index.js +14 -3
  87. package/dist/ui/menu/MenuItems.d.ts.map +1 -0
  88. package/dist/ui/timeline/RegionClipResolver.d.ts +5 -1
  89. package/dist/ui/timeline/RegionClipResolver.d.ts.map +1 -1
  90. package/dist/ui/timeline/RegionClipResolver.js +5 -1
  91. package/dist/ui/timeline/RegionKeepExistingResolver.d.ts +34 -0
  92. package/dist/ui/timeline/RegionKeepExistingResolver.d.ts.map +1 -0
  93. package/dist/ui/timeline/RegionKeepExistingResolver.js +171 -0
  94. package/dist/ui/timeline/RegionOverlapResolver.d.ts +33 -0
  95. package/dist/ui/timeline/RegionOverlapResolver.d.ts.map +1 -0
  96. package/dist/ui/timeline/RegionOverlapResolver.js +79 -0
  97. package/dist/ui/timeline/RegionPushExistingResolver.d.ts +31 -0
  98. package/dist/ui/timeline/RegionPushExistingResolver.d.ts.map +1 -0
  99. package/dist/ui/timeline/RegionPushExistingResolver.js +159 -0
  100. package/dist/ui/timeline/TimelineFocus.d.ts +14 -0
  101. package/dist/ui/timeline/TimelineFocus.d.ts.map +1 -0
  102. package/dist/ui/timeline/TimelineFocus.js +45 -0
  103. package/dist/ui/timeline/TrackResolver.d.ts +11 -0
  104. package/dist/ui/timeline/TrackResolver.d.ts.map +1 -0
  105. package/dist/ui/timeline/TrackResolver.js +5 -0
  106. package/dist/workers-main.js +1 -1
  107. package/dist/workers-main.js.map +3 -3
  108. package/package.json +62 -62
  109. package/dist/ui/generic/ClipboardManager.d.ts.map +0 -1
  110. package/dist/ui/generic/ClipboardManager.js +0 -77
  111. package/dist/ui/generic/ContextMenu.d.ts.map +0 -1
  112. package/dist/ui/generic/MenuItems.d.ts.map +0 -1
  113. /package/dist/ui/{generic → menu}/MenuItems.d.ts +0 -0
  114. /package/dist/ui/{generic → menu}/MenuItems.js +0 -0
@@ -0,0 +1,54 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ // Singleton - one clock worker shared across engine instances
11
+ import { Lazy } from "@opendaw/lib-std";
12
+ let instance;
13
+ export class HRClockWorker {
14
+ static get() { return new HRClockWorker(); }
15
+ sab;
16
+ #worker;
17
+ constructor() {
18
+ // Layout (32 bytes):
19
+ // int32[0]: request counter
20
+ // int32[1]: start response counter (which request this start timestamp is for)
21
+ // int32[2]: end response counter (which request this end timestamp is for)
22
+ // float64[2]: start timestamp (bytes 16-23)
23
+ // float64[3]: end timestamp (bytes 24-31)
24
+ this.sab = new SharedArrayBuffer(32);
25
+ const code = `
26
+ onmessage = (e) => {
27
+ const int32 = new Int32Array(e.data)
28
+ const float64 = new Float64Array(e.data)
29
+ let lastCounter = 0
30
+ while (true) {
31
+ Atomics.wait(int32, 0, lastCounter)
32
+ lastCounter = Atomics.load(int32, 0)
33
+ const isStart = (lastCounter & 1) === 1
34
+ if (isStart) {
35
+ float64[2] = performance.now()
36
+ Atomics.store(int32, 1, lastCounter)
37
+ } else {
38
+ float64[3] = performance.now()
39
+ Atomics.store(int32, 2, lastCounter)
40
+ }
41
+ }
42
+ }
43
+ `;
44
+ const blob = new Blob([code], { type: "application/javascript" });
45
+ this.#worker = new Worker(URL.createObjectURL(blob));
46
+ this.#worker.postMessage(this.sab);
47
+ }
48
+ }
49
+ __decorate([
50
+ Lazy,
51
+ __metadata("design:type", Function),
52
+ __metadata("design:paramtypes", []),
53
+ __metadata("design:returntype", HRClockWorker)
54
+ ], HRClockWorker, "get", null);
@@ -1 +1 @@
1
- {"version":3,"file":"OfflineEngineRenderer.d.ts","sourceRoot":"","sources":["../src/OfflineEngineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,GAAG,EAAa,MAAM,EAAS,QAAQ,EAAmB,MAAM,kBAAkB,CAAA;AAClG,OAAO,EAAC,SAAS,EAAO,MAAM,kBAAkB,CAAA;AAEhD,OAAO,EAGH,wBAAwB,EAIxB,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;WAmHpB,KAAK,CAAC,MAAM,EAAE,OAAO,EACf,sBAAsB,EAAE,MAAM,CAAC,wBAAwB,CAAC,EACxD,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,GAAE,GAAY,GACxC,OAAO,CAAC,SAAS,CAAC;IAwBrB,OAAO;IAkBP,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,SAAS,IAAI,IAAI;IAKX,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM3C,MAAM,CACR,MAAM,EAAE,yBAAyB,EACjC,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,WAAW,CAAC,EAAE,WAAW,GAC1B,OAAO,CAAC,SAAS,CAAC;CAkCxB"}
1
+ {"version":3,"file":"OfflineEngineRenderer.d.ts","sourceRoot":"","sources":["../src/OfflineEngineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,GAAG,EAAa,MAAM,EAAS,QAAQ,EAA6B,MAAM,kBAAkB,CAAA;AAC5G,OAAO,EAAC,SAAS,EAAO,MAAM,kBAAkB,CAAA;AAEhD,OAAO,EAGH,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;WAoHpB,KAAK,CAAC,MAAM,EAAE,OAAO,EACf,sBAAsB,EAAE,MAAM,CAAC,wBAAwB,CAAC,EACxD,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,GAAE,GAAY,GACxC,OAAO,CAAC,SAAS,CAAC;IAwBrB,OAAO;IAkBP,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,SAAS,IAAI,IAAI;IAKX,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM3C,MAAM,CACR,MAAM,EAAE,yBAAyB,EACjC,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,WAAW,CAAC,EAAE,WAAW,GAC1B,OAAO,CAAC,SAAS,CAAC;CAqCxB"}
@@ -1,6 +1,6 @@
1
- import { Errors, isDefined, Option, panic, Terminator } from "@opendaw/lib-std";
1
+ import { Errors, isDefined, Option, panic, Terminator, TimeSpan } from "@opendaw/lib-std";
2
2
  import { AudioData } from "@opendaw/lib-dsp";
3
- import { Communicator, Messenger } from "@opendaw/lib-runtime";
3
+ import { Communicator, Messenger, Wait } from "@opendaw/lib-runtime";
4
4
  import { ExportStemsConfiguration } from "@opendaw/studio-adapters";
5
5
  import { AudioWorklets } from "./AudioWorklets";
6
6
  import { MIDIReceiver } from "./midi";
@@ -90,6 +90,7 @@ export class OfflineEngineRenderer {
90
90
  scheduleClipPlay(clipIds) { dispatcher.dispatchAndForget(this.scheduleClipPlay, clipIds); }
91
91
  scheduleClipStop(trackIds) { dispatcher.dispatchAndForget(this.scheduleClipStop, trackIds); }
92
92
  setupMIDI(port, buffer) { dispatcher.dispatchAndForget(this.setupMIDI, port, buffer); }
93
+ updateMonitoringMap(map) { dispatcher.dispatchAndForget(this.updateMonitoringMap, map); }
93
94
  loadClickSound(index, data) { dispatcher.dispatchAndForget(this.loadClickSound, index, data); }
94
95
  terminate() { dispatcher.dispatchAndForget(this.terminate); }
95
96
  });
@@ -170,6 +171,9 @@ export class OfflineEngineRenderer {
170
171
  };
171
172
  }
172
173
  this.#progressPort.onmessage = (event) => progress(event.data.frames / this.#sampleRate);
174
+ while (!await this.#engineCommands.queryLoadingComplete()) {
175
+ await Wait.timeSpan(TimeSpan.millis(100));
176
+ }
173
177
  this.play();
174
178
  this.#protocol.render(config).then(channels => {
175
179
  if (cancelled) {
@@ -1,4 +1,4 @@
1
- import { int, Observer, Option, Subscription, Terminable, UUID } from "@opendaw/lib-std";
1
+ import { int, Observer, Option, Procedure, Subscription, Terminable, UUID } from "@opendaw/lib-std";
2
2
  import { AudioData } from "@opendaw/lib-dsp";
3
3
  import { Peaks } from "@opendaw/lib-fusion";
4
4
  import { RingBuffer, SampleLoader, SampleLoaderState } from "@opendaw/studio-adapters";
@@ -8,6 +8,7 @@ export declare class RecordingWorklet extends AudioWorkletNode implements Termin
8
8
  constructor(context: BaseAudioContext, config: RingBuffer.Config);
9
9
  own<T extends Terminable>(terminable: T): T;
10
10
  limit(count: int): void;
11
+ set onSaved(callback: Procedure<UUID.Bytes>);
11
12
  setFillLength(value: int): void;
12
13
  get numberOfFrames(): int;
13
14
  get data(): Option<AudioData>;
@@ -1 +1 @@
1
- {"version":3,"file":"RecordingWorklet.d.ts","sourceRoot":"","sources":["../src/RecordingWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,GAAG,EAEH,QAAQ,EACR,MAAM,EAGN,YAAY,EACZ,UAAU,EAEV,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,SAAS,EAAW,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAC,KAAK,EAAc,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAEH,UAAU,EACV,YAAY,EACZ,iBAAiB,EAEpB,MAAM,0BAA0B,CAAA;AAMjC,qBAAa,gBAAiB,SAAQ,gBAAiB,YAAW,UAAU,EAAE,YAAY;;IAGtF,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAkB;gBAa/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM;IAuBhE,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;IAE3C,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IAEvB,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IAE/B,IAAI,cAAc,IAAI,GAAG,CAA6C;IACtE,IAAI,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAoB;IACjD,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAA6E;IACvG,IAAI,KAAK,IAAI,iBAAiB,CAAqB;IAEnD,UAAU,IAAI,IAAI;IAElB,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,YAAY;IAQ9D,SAAS,IAAI,IAAI;IAMjB,QAAQ,IAAI,MAAM;CAqCrB"}
1
+ {"version":3,"file":"RecordingWorklet.d.ts","sourceRoot":"","sources":["../src/RecordingWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,GAAG,EAEH,QAAQ,EACR,MAAM,EAEN,SAAS,EAET,YAAY,EACZ,UAAU,EAEV,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,SAAS,EAAW,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAC,KAAK,EAAc,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAEH,UAAU,EACV,YAAY,EACZ,iBAAiB,EAEpB,MAAM,0BAA0B,CAAA;AAMjC,qBAAa,gBAAiB,SAAQ,gBAAiB,YAAW,UAAU,EAAE,YAAY;;IAGtF,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAkB;gBAc/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM;IAuBhE,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;IAE3C,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IAOvB,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAyC;IAEpF,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IAE/B,IAAI,cAAc,IAAI,GAAG,CAA6C;IACtE,IAAI,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAoB;IACjD,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAA6E;IACvG,IAAI,KAAK,IAAI,iBAAiB,CAAqB;IAEnD,UAAU,IAAI,IAAI;IAElB,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,YAAY;IAQ9D,SAAS,IAAI,IAAI;IAMjB,QAAQ,IAAI,MAAM;CAsCrB"}
@@ -18,6 +18,7 @@ export class RecordingWorklet extends AudioWorkletNode {
18
18
  #isRecording = true;
19
19
  #limitSamples = Number.POSITIVE_INFINITY;
20
20
  #state = { type: "record" };
21
+ #onSaved = Option.None;
21
22
  constructor(context, config) {
22
23
  super(context, "recording-processor", {
23
24
  numberOfInputs: 1,
@@ -40,7 +41,13 @@ export class RecordingWorklet extends AudioWorkletNode {
40
41
  });
41
42
  }
42
43
  own(terminable) { return this.#terminator.own(terminable); }
43
- limit(count) { this.#limitSamples = count; }
44
+ limit(count) {
45
+ this.#limitSamples = count;
46
+ if (this.numberOfFrames >= this.#limitSamples) {
47
+ this.#finalize().catch(error => console.warn(error));
48
+ }
49
+ }
50
+ set onSaved(callback) { this.#onSaved = Option.wrap(callback); }
44
51
  setFillLength(value) { this.#peakWriter.numFrames = value; }
45
52
  get numberOfFrames() { return this.#output.length * RenderQuantum; }
46
53
  get data() { return this.#data; }
@@ -88,6 +95,7 @@ export class RecordingWorklet extends AudioWorkletNode {
88
95
  meta
89
96
  };
90
97
  await SampleStorage.get().save(sample);
98
+ this.#onSaved.ifSome(callback => callback(this.uuid));
91
99
  this.#setState({ type: "loaded" });
92
100
  this.terminate();
93
101
  return sample;
@@ -1 +1 @@
1
- {"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAIrC,8BAAsB,OAAO,CAAC,IAAI,SAAS;IAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE,GAAG,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM;IAA7C,SAAS,aAAsB,MAAM,EAAE,MAAM;IAE7C,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IACvC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAEzC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3C,cAAc,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAK7C,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9D,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;CAgB7C"}
1
+ {"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAIrC,8BAAsB,OAAO,CAAC,IAAI,SAAS;IAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE,GAAG,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM;IAA7C,SAAS,aAAsB,MAAM,EAAE,MAAM;IAE7C,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IACvC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAEzC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAS3C,cAAc,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAK7C,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9D,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;CAgB7C"}
package/dist/Storage.js CHANGED
@@ -8,6 +8,7 @@ export class Storage {
8
8
  }
9
9
  async deleteItem(uuid) {
10
10
  const path = `${this.folder}/${UUID.toString(uuid)}`;
11
+ console.debug(`deleteItem '${path}'`);
11
12
  const uuids = await this.loadTrashedIds();
12
13
  uuids.push(UUID.toString(uuid));
13
14
  await this.saveTrashedIds(uuids);
@@ -14,18 +14,27 @@ export declare const StudioPreferences: import("@opendaw/lib-fusion").Preference
14
14
  engine: {
15
15
  "note-audition-while-editing": boolean;
16
16
  "auto-create-output-compressor": boolean;
17
+ "stop-playback-when-overloading": boolean;
17
18
  };
18
19
  pointer: {
19
20
  "dragging-use-pointer-lock": boolean;
20
21
  "modifying-controls-wheel": boolean;
21
22
  "normalize-mouse-wheel": boolean;
22
23
  };
24
+ editing: {
25
+ "overlapping-regions-behaviour": "clip" | "push-existing" | "keep-existing";
26
+ "show-clipboard-menu": boolean;
27
+ };
23
28
  debug: {
24
29
  "footer-show-fps-meter": boolean;
25
30
  "footer-show-samples-memory": boolean;
26
31
  "footer-show-build-infos": boolean;
32
+ "show-cpu-stats": boolean;
27
33
  "enable-beta-features": boolean;
28
34
  "enable-debug-menu": boolean;
29
35
  };
36
+ storage: {
37
+ "auto-delete-orphaned-samples": boolean;
38
+ };
30
39
  }>;
31
40
  //# sourceMappingURL=StudioPreferences.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StudioPreferences.d.ts","sourceRoot":"","sources":["../src/StudioPreferences.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAwD,CAAA"}
1
+ {"version":3,"file":"StudioPreferences.d.ts","sourceRoot":"","sources":["../src/StudioPreferences.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAwD,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const FpsOptions: readonly [24, 25, 29.97, 30];
3
+ export declare const OverlappingRegionsBehaviourOptions: readonly ["clip", "push-existing", "keep-existing"];
3
4
  export declare const StudioSettingsSchema: z.ZodObject<{
4
5
  visibility: z.ZodDefault<z.ZodObject<{
5
6
  "visible-help-hints": z.ZodBoolean;
@@ -16,19 +17,32 @@ export declare const StudioSettingsSchema: z.ZodObject<{
16
17
  engine: z.ZodDefault<z.ZodObject<{
17
18
  "note-audition-while-editing": z.ZodBoolean;
18
19
  "auto-create-output-compressor": z.ZodBoolean;
20
+ "stop-playback-when-overloading": z.ZodBoolean;
19
21
  }, z.core.$strip>>;
20
22
  pointer: z.ZodDefault<z.ZodObject<{
21
23
  "dragging-use-pointer-lock": z.ZodBoolean;
22
24
  "modifying-controls-wheel": z.ZodBoolean;
23
25
  "normalize-mouse-wheel": z.ZodBoolean;
24
26
  }, z.core.$strip>>;
27
+ editing: z.ZodDefault<z.ZodObject<{
28
+ "overlapping-regions-behaviour": z.ZodEnum<{
29
+ clip: "clip";
30
+ "push-existing": "push-existing";
31
+ "keep-existing": "keep-existing";
32
+ }>;
33
+ "show-clipboard-menu": z.ZodBoolean;
34
+ }, z.core.$strip>>;
25
35
  debug: z.ZodDefault<z.ZodObject<{
26
36
  "footer-show-fps-meter": z.ZodBoolean;
27
37
  "footer-show-samples-memory": z.ZodBoolean;
28
38
  "footer-show-build-infos": z.ZodBoolean;
39
+ "show-cpu-stats": z.ZodBoolean;
29
40
  "enable-beta-features": z.ZodBoolean;
30
41
  "enable-debug-menu": z.ZodBoolean;
31
42
  }, z.core.$strip>>;
43
+ storage: z.ZodDefault<z.ZodObject<{
44
+ "auto-delete-orphaned-samples": z.ZodBoolean;
45
+ }, z.core.$strip>>;
32
46
  }, z.core.$strip>;
33
47
  export type StudioSettings = z.infer<typeof StudioSettingsSchema>;
34
48
  //# sourceMappingURL=StudioSettings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StudioSettings.d.ts","sourceRoot":"","sources":["../src/StudioSettings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAA;AAGrB,eAAO,MAAM,UAAU,8BAA+B,CAAA;AAEtD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+C/B,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA"}
1
+ {"version":3,"file":"StudioSettings.d.ts","sourceRoot":"","sources":["../src/StudioSettings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAA;AAGrB,eAAO,MAAM,UAAU,8BAA+B,CAAA;AACtD,eAAO,MAAM,kCAAkC,qDAAsD,CAAA;AAErG,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+D/B,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { Browser } from "@opendaw/lib-dom";
3
3
  export const FpsOptions = [24, 25, 29.97, 30];
4
+ export const OverlappingRegionsBehaviourOptions = ["clip", "push-existing", "keep-existing"];
4
5
  export const StudioSettingsSchema = z.object({
5
6
  "visibility": z.object({
6
7
  "visible-help-hints": z.boolean(),
@@ -21,10 +22,12 @@ export const StudioSettingsSchema = z.object({
21
22
  }).default({ musical: true, absolute: false, details: false, fps: 25 }),
22
23
  "engine": z.object({
23
24
  "note-audition-while-editing": z.boolean(),
24
- "auto-create-output-compressor": z.boolean()
25
+ "auto-create-output-compressor": z.boolean(),
26
+ "stop-playback-when-overloading": z.boolean()
25
27
  }).default({
26
28
  "note-audition-while-editing": true,
27
- "auto-create-output-compressor": true
29
+ "auto-create-output-compressor": true,
30
+ "stop-playback-when-overloading": true
28
31
  }),
29
32
  "pointer": z.object({
30
33
  "dragging-use-pointer-lock": z.boolean(),
@@ -35,17 +38,31 @@ export const StudioSettingsSchema = z.object({
35
38
  "modifying-controls-wheel": false,
36
39
  "normalize-mouse-wheel": true
37
40
  }),
41
+ "editing": z.object({
42
+ "overlapping-regions-behaviour": z.enum(OverlappingRegionsBehaviourOptions),
43
+ "show-clipboard-menu": z.boolean()
44
+ }).default({
45
+ "overlapping-regions-behaviour": "clip",
46
+ "show-clipboard-menu": false
47
+ }),
38
48
  "debug": z.object({
39
49
  "footer-show-fps-meter": z.boolean(),
40
50
  "footer-show-samples-memory": z.boolean(),
41
51
  "footer-show-build-infos": z.boolean(),
52
+ "show-cpu-stats": z.boolean(),
42
53
  "enable-beta-features": z.boolean(),
43
54
  "enable-debug-menu": z.boolean()
44
55
  }).default({
45
56
  "footer-show-fps-meter": false,
46
57
  "footer-show-samples-memory": false,
47
58
  "footer-show-build-infos": false,
59
+ "show-cpu-stats": false,
48
60
  "enable-beta-features": false,
49
61
  "enable-debug-menu": false
62
+ }),
63
+ "storage": z.object({
64
+ "auto-delete-orphaned-samples": z.boolean()
65
+ }).default({
66
+ "auto-delete-orphaned-samples": false
50
67
  })
51
68
  });
@@ -2,11 +2,13 @@ import { MutableObservableOption, Option, Terminable } from "@opendaw/lib-std";
2
2
  import { AudioUnitBox, CaptureAudioBox } from "@opendaw/studio-boxes";
3
3
  import { Capture } from "./Capture";
4
4
  import { CaptureDevices } from "./CaptureDevices";
5
+ import { MonitoringMode } from "./MonitoringMode";
5
6
  export declare class CaptureAudio extends Capture<CaptureAudioBox> {
6
7
  #private;
7
8
  constructor(manager: CaptureDevices, audioUnitBox: AudioUnitBox, captureAudioBox: CaptureAudioBox);
8
9
  get isMonitoring(): boolean;
9
- set isMonitoring(value: boolean);
10
+ get monitoringMode(): MonitoringMode;
11
+ set monitoringMode(value: MonitoringMode);
10
12
  get gainDb(): number;
11
13
  get requestChannels(): Option<1 | 2>;
12
14
  set requestChannels(value: 1 | 2);
@@ -1 +1 @@
1
- {"version":3,"file":"CaptureAudio.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,uBAAuB,EAEvB,MAAM,EAEN,UAAU,EACb,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAC,YAAY,EAAE,eAAe,EAAC,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAM/C,qBAAa,YAAa,SAAQ,OAAO,CAAC,eAAe,CAAC;;gBAc1C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe;IAkCjG,IAAI,YAAY,IAAI,OAAO,CAA4B;IACvD,IAAI,YAAY,CAAC,KAAK,EAAE,OAAO,EAS9B;IACD,IAAI,MAAM,IAAI,MAAM,CAAsB;IAC1C,IAAI,eAAe,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAA+B;IACnE,IAAI,eAAe,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAmD;IACnF,IAAI,MAAM,IAAI,uBAAuB,CAAC,WAAW,CAAC,CAAsB;IACxE,IAAI,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,CAEnC;IACD,IAAI,KAAK,IAAI,MAAM,CAAsE;IACzF,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAA+D;IAChG,IAAI,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAE/C;IACD,IAAI,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,CAAiD;IACpF,IAAI,qBAAqB,IAAI,MAAM,CAAsD;IAEnF,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA2BvC,cAAc,IAAI,UAAU;CAwG/B"}
1
+ {"version":3,"file":"CaptureAudio.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,uBAAuB,EAEvB,MAAM,EAEN,UAAU,EACb,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAC,YAAY,EAAE,eAAe,EAAC,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAK/C,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAE/C,qBAAa,YAAa,SAAQ,OAAO,CAAC,eAAe,CAAC;;gBAe1C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe;IAwCjG,IAAI,YAAY,IAAI,OAAO,CAAwC;IACnE,IAAI,cAAc,IAAI,cAAc,CAA8B;IAClE,IAAI,cAAc,CAAC,KAAK,EAAE,cAAc,EAQvC;IACD,IAAI,MAAM,IAAI,MAAM,CAAsB;IAC1C,IAAI,eAAe,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAA+B;IACnE,IAAI,eAAe,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAmD;IACnF,IAAI,MAAM,IAAI,uBAAuB,CAAC,WAAW,CAAC,CAAsB;IACxE,IAAI,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,CAEnC;IACD,IAAI,KAAK,IAAI,MAAM,CAAsE;IACzF,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAA+D;IAChG,IAAI,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAE/C;IACD,IAAI,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,CAAiD;IACpF,IAAI,qBAAqB,IAAI,MAAM,CAA6C;IAE1E,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BvC,cAAc,IAAI,UAAU;CAsH/B"}
@@ -8,7 +8,7 @@ import { RenderQuantum } from "../RenderQuantum";
8
8
  export class CaptureAudio extends Capture {
9
9
  #stream;
10
10
  #streamGenerator;
11
- #isMonitoring = false;
11
+ #monitoringMode = "off";
12
12
  #requestChannels = Option.None;
13
13
  #gainDb = 0.0;
14
14
  #audioChain = null;
@@ -21,6 +21,12 @@ export class CaptureAudio extends Capture {
21
21
  const channels = owner.getValue();
22
22
  this.#requestChannels = channels === 1 || channels === 2 ? Option.wrap(channels) : Option.None;
23
23
  this.#stream.ifSome(stream => this.#rebuildAudioChain(stream));
24
+ // Re-register monitoring if in effects mode (channel count may have changed)
25
+ if (this.#monitoringMode === "effects" && isDefined(this.#audioChain)) {
26
+ const engine = this.manager.project.engine;
27
+ engine.unregisterMonitoringSource(this.audioUnitBox.address.uuid);
28
+ engine.registerMonitoringSource(this.audioUnitBox.address.uuid, this.#audioChain.gainNode, this.#audioChain.channelCount);
29
+ }
24
30
  }), captureAudioBox.gainDb.catchupAndSubscribe(owner => {
25
31
  this.#gainDb = owner.getValue();
26
32
  if (isDefined(this.#audioChain)) {
@@ -40,19 +46,18 @@ export class CaptureAudio extends Capture {
40
46
  }
41
47
  }));
42
48
  }
43
- get isMonitoring() { return this.#isMonitoring; }
44
- set isMonitoring(value) {
45
- if (this.#isMonitoring === value) {
49
+ get isMonitoring() { return this.#monitoringMode !== "off"; }
50
+ get monitoringMode() { return this.#monitoringMode; }
51
+ set monitoringMode(value) {
52
+ if (this.#monitoringMode === value) {
46
53
  return;
47
54
  }
48
- this.#isMonitoring = value;
49
- if (this.#isMonitoring) {
55
+ this.#disconnectMonitoring();
56
+ this.#monitoringMode = value;
57
+ if (this.#monitoringMode !== "off") {
50
58
  this.armed.setValue(true);
51
- this.#connectMonitoring();
52
- }
53
- else {
54
- this.#disconnectMonitoring();
55
59
  }
60
+ this.#connectMonitoring();
56
61
  }
57
62
  get gainDb() { return this.#gainDb; }
58
63
  get requestChannels() { return this.#requestChannels; }
@@ -67,7 +72,7 @@ export class CaptureAudio extends Capture {
67
72
  return this.#stream.flatMap(stream => Option.wrap(stream.getAudioTracks().at(0)));
68
73
  }
69
74
  get outputNode() { return Option.wrap(this.#audioChain?.gainNode); }
70
- get effectiveChannelCount() { return this.#audioChain?.gainNode.channelCount ?? 1; }
75
+ get effectiveChannelCount() { return this.#audioChain?.channelCount ?? 1; }
71
76
  async prepareRecording() {
72
77
  const { project } = this.manager;
73
78
  const { env: { audioContext, audioWorklets, sampleManager } } = project;
@@ -87,8 +92,7 @@ export class CaptureAudio extends Capture {
87
92
  if (!isDefined(audioChain)) {
88
93
  return Promise.reject("No audio chain available for recording.");
89
94
  }
90
- const { gainNode } = audioChain;
91
- const channelCount = gainNode.channelCount;
95
+ const { gainNode, channelCount } = audioChain;
92
96
  const recordingWorklet = audioWorklets.createRecording(channelCount, RenderQuantum);
93
97
  sampleManager.record(recordingWorklet);
94
98
  gainNode.connect(recordingWorklet);
@@ -127,7 +131,7 @@ export class CaptureAudio extends Capture {
127
131
  }
128
132
  this.#stopStream();
129
133
  const deviceId = this.deviceId.getValue().unwrapOrUndefined() ?? AudioDevices.defaultInput?.deviceId;
130
- const channelCount = this.#requestChannels.unwrapOrElse(1);
134
+ const channelCount = this.#requestChannels.unwrapOrElse(2);
131
135
  return AudioDevices.requestStream({
132
136
  deviceId: isDefined(deviceId) ? { exact: deviceId } : undefined,
133
137
  echoCancellation: false,
@@ -155,21 +159,19 @@ export class CaptureAudio extends Capture {
155
159
  this.#stream.clear(stream => stream.getAudioTracks().forEach(track => track.stop()));
156
160
  }
157
161
  #rebuildAudioChain(stream) {
158
- const wasMonitoring = this.#isMonitoring && isDefined(this.#audioChain);
162
+ const wasMonitoringMode = this.#monitoringMode !== "off" && isDefined(this.#audioChain) ? this.#monitoringMode : "off";
159
163
  this.#destroyAudioChain();
160
164
  const { audioContext } = this.manager.project.env;
161
165
  const sourceNode = audioContext.createMediaStreamSource(stream);
162
166
  const gainNode = audioContext.createGain();
163
167
  gainNode.gain.value = dbToGain(this.#gainDb);
164
- const streamChannelCount = stream.getAudioTracks().at(0)?.getSettings().channelCount ?? 1;
165
- const requestMono = this.#requestChannels.mapOr(channels => channels === 1, false);
166
- if (requestMono && streamChannelCount === 2) {
167
- gainNode.channelCount = 1;
168
- gainNode.channelCountMode = "explicit";
169
- }
168
+ const streamChannelCount = Math.min(stream.getAudioTracks().at(0)?.getSettings().channelCount ?? 2, 2);
169
+ const channelCount = this.#requestChannels.unwrapOrElse(streamChannelCount);
170
+ gainNode.channelCount = channelCount;
171
+ gainNode.channelCountMode = "explicit";
170
172
  sourceNode.connect(gainNode);
171
- this.#audioChain = { sourceNode, gainNode };
172
- if (wasMonitoring || this.#isMonitoring) {
173
+ this.#audioChain = { sourceNode, gainNode, channelCount };
174
+ if (wasMonitoringMode !== "off" || this.#monitoringMode !== "off") {
173
175
  this.#connectMonitoring();
174
176
  }
175
177
  }
@@ -182,15 +184,35 @@ export class CaptureAudio extends Capture {
182
184
  }
183
185
  }
184
186
  #connectMonitoring() {
185
- if (isDefined(this.#audioChain)) {
186
- const { audioContext } = this.manager.project.env;
187
- this.#audioChain.gainNode.connect(audioContext.destination);
187
+ if (!isDefined(this.#audioChain)) {
188
+ return;
189
+ }
190
+ switch (this.#monitoringMode) {
191
+ case "off":
192
+ break;
193
+ case "direct":
194
+ this.#audioChain.gainNode.connect(this.manager.project.env.audioContext.destination);
195
+ break;
196
+ case "effects":
197
+ const engine = this.manager.project.engine;
198
+ engine.registerMonitoringSource(this.audioUnitBox.address.uuid, this.#audioChain.gainNode, this.#audioChain.channelCount);
199
+ break;
188
200
  }
189
201
  }
190
202
  #disconnectMonitoring() {
191
- if (isDefined(this.#audioChain)) {
192
- const { audioContext } = this.manager.project.env;
193
- this.#audioChain.gainNode.disconnect(audioContext.destination);
203
+ if (!isDefined(this.#audioChain)) {
204
+ return;
205
+ }
206
+ switch (this.#monitoringMode) {
207
+ case "off":
208
+ break;
209
+ case "direct":
210
+ this.#audioChain.gainNode.disconnect(this.manager.project.env.audioContext.destination);
211
+ break;
212
+ case "effects":
213
+ this.#audioChain.gainNode.disconnect();
214
+ this.manager.project.engine.unregisterMonitoringSource(this.audioUnitBox.address.uuid);
215
+ break;
194
216
  }
195
217
  }
196
218
  }
@@ -0,0 +1,2 @@
1
+ export type MonitoringMode = "off" | "direct" | "effects";
2
+ //# sourceMappingURL=MonitoringMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonitoringMode.d.ts","sourceRoot":"","sources":["../../src/capture/MonitoringMode.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqD,UAAU,EAA6B,MAAM,kBAAkB,CAAA;AAG3H,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;AAGjC,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,UAkKL,CAAA;;CACJ"}
1
+ {"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqD,UAAU,EAA6B,MAAM,kBAAkB,CAAA;AAG3H,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;AAGjC,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,UAmKL,CAAA;;CACJ"}
@@ -96,6 +96,7 @@ export var RecordAudio;
96
96
  const previousTrack = currentTake.mapOr(take => take.trackBox, null);
97
97
  currentTake = Option.wrap(createTakeRegion(position, currentWaveformOffset, previousTrack));
98
98
  };
99
+ recordingWorklet.onSaved = uuid => project.trackUserCreatedSample(uuid);
99
100
  terminator.ownAll(Terminable.create(() => {
100
101
  tryCatch(() => sourceNode.disconnect(recordingWorklet));
101
102
  if (recordingWorklet.numberOfFrames === 0 || fileBox.isEmpty()) {
@@ -2,5 +2,6 @@ export * from "./Capture";
2
2
  export * from "./CaptureAudio";
3
3
  export * from "./CaptureMidi";
4
4
  export * from "./CaptureDevices";
5
+ export * from "./MonitoringMode";
5
6
  export * from "./Recording";
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capture/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capture/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA"}
@@ -2,4 +2,5 @@ export * from "./Capture";
2
2
  export * from "./CaptureAudio";
3
3
  export * from "./CaptureMidi";
4
4
  export * from "./CaptureDevices";
5
+ export * from "./MonitoringMode";
5
6
  export * from "./Recording";
@@ -1 +1 @@
1
- {"version":3,"file":"DawProjectImporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAiBH,IAAI,EAEP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAcH,aAAa,EAUhB,MAAM,yBAAyB,CAAA;AA2BhC,OAAO,EAOH,eAAe,EAElB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAIvC,yBAAiB,gBAAgB,CAAC;IAW9B,KAAY,MAAM,GAAG;QACjB,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,QAAQ,EAAE,eAAe,CAAA;KAC5B,CAAA;IAOM,MAAM,IAAI,GAAU,QAAQ,aAAa,EAAE,WAAW,UAAU,CAAC,gBAAgB,KAAG,OAAO,CAAC,MAAM,CAycxG,CAAA;CAaJ"}
1
+ {"version":3,"file":"DawProjectImporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAiBH,IAAI,EAEP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAcH,aAAa,EAUhB,MAAM,yBAAyB,CAAA;AA2BhC,OAAO,EAOH,eAAe,EAElB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAIvC,yBAAiB,gBAAgB,CAAC;IAW9B,KAAY,MAAM,GAAG;QACjB,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,QAAQ,EAAE,eAAe,CAAA;KAC5B,CAAA;IAOM,MAAM,IAAI,GAAU,QAAQ,aAAa,EAAE,WAAW,UAAU,CAAC,gBAAgB,KAAG,OAAO,CAAC,MAAM,CA6cxG,CAAA;CAaJ"}
@@ -328,6 +328,10 @@ export var DawProjectImport;
328
328
  const loopDuration = clip.loopEnd ?? warpDistance;
329
329
  const durationInPulses = duration * PPQN.Quarter;
330
330
  const loopDurationInPulses = loopDuration * PPQN.Quarter;
331
+ if (loopDurationInPulses < 1) {
332
+ console.warn(`Skipping clip '${clip.name}': loop duration too small (${loopDurationInPulses} ppqn)`);
333
+ return;
334
+ }
331
335
  const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
332
336
  const pitchStretch = AudioPitchStretchBox.create(boxGraph, UUID.generate());
333
337
  AudioContentHelpers.addDefaultWarpMarkers(boxGraph, pitchStretch, loopDurationInPulses, audioFileBox.endInSeconds.getValue());