@opendaw/studio-core 0.0.129 → 0.0.131

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 (58) hide show
  1. package/dist/AssetService.d.ts.map +1 -1
  2. package/dist/AssetService.js +11 -2
  3. package/dist/AudioOfflineRenderer.js +1 -1
  4. package/dist/Engine.d.ts +1 -1
  5. package/dist/Engine.d.ts.map +1 -1
  6. package/dist/EngineFacade.d.ts +1 -1
  7. package/dist/EngineFacade.d.ts.map +1 -1
  8. package/dist/EngineFacade.js +2 -2
  9. package/dist/EngineWorklet.d.ts +1 -1
  10. package/dist/EngineWorklet.d.ts.map +1 -1
  11. package/dist/EngineWorklet.js +9 -46
  12. package/dist/MonitoringRouter.d.ts +10 -0
  13. package/dist/MonitoringRouter.d.ts.map +1 -0
  14. package/dist/MonitoringRouter.js +89 -0
  15. package/dist/capture/CaptureAudio.d.ts +10 -0
  16. package/dist/capture/CaptureAudio.d.ts.map +1 -1
  17. package/dist/capture/CaptureAudio.js +106 -31
  18. package/dist/capture/RecordAudio.d.ts.map +1 -1
  19. package/dist/capture/RecordAudio.js +10 -2
  20. package/dist/capture/Recording.js +1 -1
  21. package/dist/processors.js +22 -22
  22. package/dist/processors.js.map +4 -4
  23. package/dist/project/AudioWavExport.d.ts +6 -0
  24. package/dist/project/AudioWavExport.d.ts.map +1 -0
  25. package/dist/project/AudioWavExport.js +15 -0
  26. package/dist/project/NoteMidiExport.d.ts +9 -0
  27. package/dist/project/NoteMidiExport.d.ts.map +1 -0
  28. package/dist/project/NoteMidiExport.js +27 -0
  29. package/dist/project/Project.d.ts.map +1 -1
  30. package/dist/project/Project.js +1 -2
  31. package/dist/project/ProjectApi.d.ts +3 -1
  32. package/dist/project/ProjectApi.d.ts.map +1 -1
  33. package/dist/project/ProjectApi.js +8 -0
  34. package/dist/project/ProjectStorage.d.ts.map +1 -1
  35. package/dist/project/ProjectStorage.js +1 -0
  36. package/dist/project/index.d.ts +2 -0
  37. package/dist/project/index.d.ts.map +1 -1
  38. package/dist/project/index.js +2 -0
  39. package/dist/project/migration/MigrateValueEventCollection.test.js +3 -3
  40. package/dist/samples/OpenSampleAPI.d.ts +1 -0
  41. package/dist/samples/OpenSampleAPI.d.ts.map +1 -1
  42. package/dist/samples/OpenSampleAPI.js +1 -0
  43. package/dist/samples/SampleService.js +1 -1
  44. package/dist/soundfont/DefaultSoundfontLoader.d.ts.map +1 -1
  45. package/dist/soundfont/DefaultSoundfontLoader.js +3 -0
  46. package/dist/soundfont/OpenSoundfontAPI.d.ts +1 -0
  47. package/dist/soundfont/OpenSoundfontAPI.d.ts.map +1 -1
  48. package/dist/soundfont/OpenSoundfontAPI.js +1 -0
  49. package/dist/soundfont/SoundfontService.js +1 -1
  50. package/dist/sync-log/SyncLogWriter.d.ts.map +1 -1
  51. package/dist/sync-log/SyncLogWriter.js +3 -2
  52. package/dist/ui/clipboard/ClipboardUtils.js +1 -1
  53. package/dist/ysync/YService.d.ts.map +1 -1
  54. package/dist/ysync/YService.js +0 -5
  55. package/dist/ysync/YSync.d.ts +2 -0
  56. package/dist/ysync/YSync.d.ts.map +1 -1
  57. package/dist/ysync/YSync.js +72 -49
  58. package/package.json +16 -15
@@ -1 +1 @@
1
- {"version":3,"file":"AssetService.d.ts","sourceRoot":"","sources":["../src/AssetService.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,EAKL,QAAQ,EACR,QAAQ,EAER,QAAQ,EAER,YAAY,EACZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAC,MAAM,EAAE,SAAS,EAAC,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAC,MAAM,uBAAuB,CAAA;AAEpE,yBAAiB,YAAY,CAAC;IAC1B,KAAY,UAAU,GAAG;QACrB,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,CAAA;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,WAAW,CAAC;QACzB,eAAe,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC;QACnC,MAAM,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAA;KAClC,CAAA;CACJ;AAED,8BAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,EAAE,GAAG,GAAG,IAAI;IACvE,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAChD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC9C,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,GAAG,gBAAgB,CAAC,CAAA;IAC3E,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAA;IAEhE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAA2B;IAE1E,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,YAAY;IAE/C,MAAM,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAI1D,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;IAExD,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE;QAAE,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,KAAK,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAyCjG,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAuChH,SAAS,CAAC,QAAQ,CAAC,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;CAClE"}
1
+ {"version":3,"file":"AssetService.d.ts","sourceRoot":"","sources":["../src/AssetService.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,EAKL,QAAQ,EACR,QAAQ,EACR,QAAQ,EAER,YAAY,EACZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAC,MAAM,EAAE,SAAS,EAAC,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAC,MAAM,uBAAuB,CAAA;AAEpE,yBAAiB,YAAY,CAAC;IAC1B,KAAY,UAAU,GAAG;QACrB,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,CAAA;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,WAAW,CAAC;QACzB,eAAe,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC;QACnC,MAAM,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAA;KAClC,CAAA;CACJ;AAED,8BAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,EAAE,GAAG,GAAG,IAAI;IACvE,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAChD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC9C,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,GAAG,gBAAgB,CAAC,CAAA;IAC3E,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAA;IAEhE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAA2B;IAE1E,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,YAAY;IAE/C,MAAM,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAI1D,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;IAExD,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE;QAAE,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,KAAK,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAkDjG,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAuChH,SAAS,CAAC,QAAQ,CAAC,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;CAClE"}
@@ -48,10 +48,19 @@ export class AssetService {
48
48
  });
49
49
  continue;
50
50
  }
51
- const asset = await this.importFile({ uuid, arrayBuffer: readResult.value, progressHandler: Progress.Empty });
51
+ const importResult = await Promises.tryCatch(this.importFile({
52
+ uuid, name: files[0].name, arrayBuffer: readResult.value, progressHandler: Progress.Empty
53
+ }));
54
+ if (importResult.status === "rejected") {
55
+ await RuntimeNotifier.info({
56
+ headline: `${this.nameSingular} Import Failed`,
57
+ message: `'${files[0].name}' could not be imported: ${String(importResult.error)}`
58
+ });
59
+ continue;
60
+ }
52
61
  await RuntimeNotifier.info({
53
62
  headline: "Replaced Asset",
54
- message: `${asset.name} has been replaced`
63
+ message: `${importResult.value.name} has been replaced`
55
64
  });
56
65
  manager.invalidate(uuid);
57
66
  }
@@ -28,7 +28,7 @@ export var AudioOfflineRenderer;
28
28
  exportConfiguration: optExportConfiguration.unwrapOrUndefined()
29
29
  });
30
30
  engineWorklet.play();
31
- engineWorklet.connect(context.destination);
31
+ engineWorklet.connect(context.destination, 0);
32
32
  await engineWorklet.isReady();
33
33
  while (!await engineWorklet.queryLoadingComplete()) {
34
34
  await Wait.timeSpan(TimeSpan.seconds(1));
package/dist/Engine.d.ts CHANGED
@@ -25,7 +25,7 @@ export interface Engine extends Terminable {
25
25
  scheduleClipStop(trackIds: ReadonlyArray<UUID.Bytes>): void;
26
26
  subscribeClipNotification(observer: Observer<ClipNotification>): Subscription;
27
27
  subscribeDeviceMessage(uuid: string, listener: Procedure<string>): Subscription;
28
- registerMonitoringSource(uuid: UUID.Bytes, node: AudioNode, numChannels: 1 | 2): void;
28
+ registerMonitoringSource(uuid: UUID.Bytes, node: AudioNode, numChannels: 1 | 2, destinationNode: AudioNode): void;
29
29
  unregisterMonitoringSource(uuid: UUID.Bytes): void;
30
30
  get position(): ObservableValue<ppqn>;
31
31
  get bpm(): ObservableValue<bpm>;
@@ -1 +1 @@
1
- {"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../src/Engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../src/Engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACpH,OAAO,EAAC,SAAS,EAAE,GAAG,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAC,gBAAgB,EAAE,iBAAiB,EAAE,UAAU,EAAC,MAAM,0BAA0B,CAAA;AACxF,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAEjC,MAAM,WAAW,MAAO,SAAQ,UAAU;IACtC,IAAI,IAAI,IAAI,CAAA;IACZ,IAAI,IAAI,IAAI,CAAA;IACZ,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAA;IACjC,gBAAgB;IAChB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IAC7C,gBAAgB;IAChB,aAAa,IAAI,IAAI,CAAA;IACrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IACxC,IAAI,IAAI,IAAI,CAAA;IACZ,KAAK,IAAI,IAAI,CAAA;IACb,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;IACZ,cAAc,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;IACnD,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,CAAA;IACtE,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAA;IACpC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY,CAAA;IAC5D,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IACxC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAA;IAC1D,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAA;IAC3D,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY,CAAA;IAC7E,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,YAAY,CAAA;IAC/E,wBAAwB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,EAAE,eAAe,EAAE,SAAS,GAAG,IAAI,CAAA;IACjH,0BAA0B,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IAElD,IAAI,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,CAAA;IACrC,IAAI,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAA;IAC/B,IAAI,SAAS,IAAI,eAAe,CAAC,OAAO,CAAC,CAAA;IACzC,IAAI,WAAW,IAAI,eAAe,CAAC,OAAO,CAAC,CAAA;IAC3C,IAAI,YAAY,IAAI,eAAe,CAAC,OAAO,CAAC,CAAA;IAC5C,IAAI,iBAAiB,IAAI,eAAe,CAAC,IAAI,CAAC,CAAA;IAC9C,IAAI,qBAAqB,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;IACpD,IAAI,WAAW,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;IAC/D,IAAI,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;IACtC,IAAI,OAAO,IAAI,OAAO,CAAA;IACtB,IAAI,WAAW,IAAI,iBAAiB,CAAA;IACpC,IAAI,UAAU,IAAI,YAAY,CAAA;IAC9B,IAAI,SAAS,IAAI,MAAM,CAAA;CAC1B"}
@@ -43,7 +43,7 @@ export declare class EngineFacade implements Engine {
43
43
  scheduleClipPlay(clipIds: ReadonlyArray<UUID.Bytes>): void;
44
44
  scheduleClipStop(trackIds: ReadonlyArray<UUID.Bytes>): void;
45
45
  subscribeDeviceMessage(uuid: string, listener: Procedure<string>): Subscription;
46
- registerMonitoringSource(uuid: UUID.Bytes, node: AudioNode, numChannels: 1 | 2): void;
46
+ registerMonitoringSource(uuid: UUID.Bytes, node: AudioNode, numChannels: 1 | 2, destinationNode: AudioNode): void;
47
47
  unregisterMonitoringSource(uuid: UUID.Bytes): void;
48
48
  terminate(): void;
49
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EngineFacade.d.ts","sourceRoot":"","sources":["../src/EngineFacade.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EngineFacade.d.ts","sourceRoot":"","sources":["../src/EngineFacade.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,sBAAsB,EACtB,GAAG,EACH,QAAQ,EACR,eAAe,EACf,QAAQ,EAER,SAAS,EACT,YAAY,EAEZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,SAAS,EAAE,GAAG,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACrD,OAAO,EACH,gBAAgB,EAChB,iBAAiB,EAGjB,UAAU,EAEb,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAGjC,qBAAa,YAAa,YAAW,MAAM;;;IAqBvC,UAAU,CAAC,OAAO,EAAE,aAAa;IAiBjC,aAAa,IAAI,IAAI;IAErB,cAAc,IAAI,IAAI;IAOtB,IAAI,IAAI,IAAI;IAUZ,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,IAAI;IAClC,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IACjC,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAC7C,aAAa,IAAI,IAAI;IAErB,IAAI,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,CAAwB;IAC7D,IAAI,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAmB;IAClD,IAAI,SAAS,IAAI,eAAe,CAAC,OAAO,CAAC,CAAyB;IAClE,IAAI,WAAW,IAAI,eAAe,CAAC,OAAO,CAAC,CAA2B;IACtE,IAAI,YAAY,IAAI,eAAe,CAAC,OAAO,CAAC,CAA4B;IACxE,IAAI,iBAAiB,IAAI,eAAe,CAAC,IAAI,CAAC,CAAiC;IAC/E,IAAI,qBAAqB,IAAI,eAAe,CAAC,GAAG,CAAC,CAAqC;IACtF,IAAI,WAAW,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAA2B;IACjG,IAAI,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,CAAuB;IAC7D,IAAI,OAAO,IAAI,OAAO,CAAmE;IACzF,IAAI,UAAU,IAAI,MAAM,CAAsF;IAC9G,IAAI,WAAW,IAAI,iBAAiB,CAAiC;IACrE,IAAI,UAAU,IAAI,YAAY,CAAiF;IAC/G,IAAI,SAAS,IAAI,MAAM,CAA8D;IAErF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACxB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;IAGxC,KAAK,IAAI,IAAI;IACb,KAAK,IAAI,IAAI;IACb,IAAI,IAAI,IAAI;IACZ,cAAc,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAGnD,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI;IAGtE,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,YAAY;IAG7E,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY;IAG5D,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI;IAGxC,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAGpC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI;IAG1D,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI;IAG3D,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,YAAY;IAG/E,wBAAwB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,EAAE,eAAe,EAAE,SAAS,GAAG,IAAI;IAGjH,0BAA0B,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI;IAIlD,SAAS,IAAI,IAAI;CAIpB"}
@@ -94,8 +94,8 @@ export class EngineFacade {
94
94
  subscribeDeviceMessage(uuid, listener) {
95
95
  return this.#worklet.unwrap("No worklet to subscribeDeviceMessage").subscribeDeviceMessage(uuid, listener);
96
96
  }
97
- registerMonitoringSource(uuid, node, numChannels) {
98
- this.#worklet.ifSome(worklet => worklet.registerMonitoringSource(uuid, node, numChannels));
97
+ registerMonitoringSource(uuid, node, numChannels, destinationNode) {
98
+ this.#worklet.ifSome(worklet => worklet.registerMonitoringSource(uuid, node, numChannels, destinationNode));
99
99
  }
100
100
  unregisterMonitoringSource(uuid) {
101
101
  this.#worklet.ifSome(worklet => worklet.unregisterMonitoringSource(uuid));
@@ -40,7 +40,7 @@ export declare class EngineWorklet extends AudioWorkletNode implements Engine {
40
40
  scheduleClipStop(trackIds: ReadonlyArray<UUID.Bytes>): void;
41
41
  subscribeClipNotification(observer: Observer<ClipNotification>): Subscription;
42
42
  subscribeDeviceMessage(uuid: string, listener: Procedure<string>): Subscription;
43
- registerMonitoringSource(uuid: UUID.Bytes, node: AudioNode, numChannels: 1 | 2): void;
43
+ registerMonitoringSource(uuid: UUID.Bytes, node: AudioNode, numChannels: 1 | 2, destinationNode: AudioNode): void;
44
44
  unregisterMonitoringSource(uuid: UUID.Bytes): void;
45
45
  terminate(): void;
46
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EngineWorklet.d.ts","sourceRoot":"","sources":["../src/EngineWorklet.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EngineWorklet.d.ts","sourceRoot":"","sources":["../src/EngineWorklet.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
- import { Arrays, DefaultObservableValue, isDefined, Notifier, Option, SetMultimap, SyncStream, Terminator, UUID } from "@opendaw/lib-std";
1
+ import { Arrays, DefaultObservableValue, Notifier, Option, SetMultimap, SyncStream, Terminator, UUID } from "@opendaw/lib-std";
2
2
  import { RenderQuantum } from "@opendaw/lib-dsp";
3
3
  import { Communicator, Messenger } from "@opendaw/lib-runtime";
4
4
  import { EngineSettingsSchema, EngineStateSchema, ExportStemsConfiguration, PERF_BUFFER_SIZE, PreferencesHost } from "@opendaw/studio-adapters";
5
5
  import { SyncSource } from "@opendaw/lib-box";
6
6
  import { AnimationFrame } from "@opendaw/lib-dom";
7
+ import { MonitoringRouter } from "./MonitoringRouter";
7
8
  import { MIDIReceiver } from "./midi";
8
9
  import { HRClockWorker } from "./HRClockWorker";
9
10
  export class EngineWorklet extends AudioWorkletNode {
@@ -34,8 +35,7 @@ export class EngineWorklet extends AudioWorkletNode {
34
35
  #consecutiveOverloadCount = 0;
35
36
  #lastCpuLoadUpdate = 0;
36
37
  #maxMsSinceLastUpdate = 0;
37
- #channelMerger = null;
38
- #monitoringSources = new Map();
38
+ #monitoringRouter = null;
39
39
  constructor(context, project, exportConfiguration, options) {
40
40
  const numberOfChannels = ExportStemsConfiguration.countStems(Option.wrap(exportConfiguration)) * 2;
41
41
  const budgetMs = (RenderQuantum / context.sampleRate) * 1000;
@@ -54,8 +54,8 @@ export class EngineWorklet extends AudioWorkletNode {
54
54
  const controlFlagsSAB = new SharedArrayBuffer(4); // 4 bytes minimum
55
55
  super(context, "engine-processor", {
56
56
  numberOfInputs: 1,
57
- numberOfOutputs: 1,
58
- outputChannelCount: [numberOfChannels],
57
+ numberOfOutputs: 2,
58
+ outputChannelCount: [numberOfChannels, 8],
59
59
  processorOptions: {
60
60
  syncStreamBuffer: reader.buffer,
61
61
  controlFlagsBuffer: controlFlagsSAB,
@@ -111,6 +111,7 @@ export class EngineWorklet extends AudioWorkletNode {
111
111
  }
112
112
  terminate() { dispatcher.dispatchAndForget(this.terminate); }
113
113
  }));
114
+ this.#monitoringRouter = this.#terminator.own(new MonitoringRouter(this, this.#commands));
114
115
  const { port, sab } = this.#terminator.own(MIDIReceiver.create(() => context instanceof AudioContext ? context.outputLatency * 1000 : 20, (deviceId, data, relativeTimeInMs) => this.#project.receivedMIDIFromEngine(deviceId, data, relativeTimeInMs)));
115
116
  this.#commands.setupMIDI(port, sab);
116
117
  Communicator.executor(messenger.channel("engine-to-client"), {
@@ -230,49 +231,11 @@ export class EngineWorklet extends AudioWorkletNode {
230
231
  this.#deviceMessageListeners.add(uuid, listener);
231
232
  return { terminate: () => this.#deviceMessageListeners.remove(uuid, listener) };
232
233
  }
233
- registerMonitoringSource(uuid, node, numChannels) {
234
- this.#monitoringSources.set(UUID.toString(uuid), { node, numChannels });
235
- this.#rebuildMonitoringMerger();
234
+ registerMonitoringSource(uuid, node, numChannels, destinationNode) {
235
+ this.#monitoringRouter.registerSource(uuid, node, numChannels, destinationNode);
236
236
  }
237
237
  unregisterMonitoringSource(uuid) {
238
- const key = UUID.toString(uuid);
239
- const entry = this.#monitoringSources.get(key);
240
- if (isDefined(entry)) {
241
- entry.node.disconnect();
242
- this.#monitoringSources.delete(key);
243
- }
244
- this.#rebuildMonitoringMerger();
245
- }
246
- #rebuildMonitoringMerger() {
247
- if (isDefined(this.#channelMerger)) {
248
- this.#channelMerger.disconnect();
249
- this.#channelMerger = null;
250
- }
251
- if (this.#monitoringSources.size === 0) {
252
- this.#commands.updateMonitoringMap([]);
253
- return;
254
- }
255
- let totalChannels = 0;
256
- for (const { numChannels } of this.#monitoringSources.values()) {
257
- totalChannels += numChannels;
258
- }
259
- this.#channelMerger = this.context.createChannelMerger(totalChannels);
260
- this.#channelMerger.connect(this);
261
- const map = [];
262
- let channel = 0;
263
- for (const [uuidString, { node, numChannels }] of this.#monitoringSources) {
264
- const uuid = UUID.parse(uuidString);
265
- const splitter = this.context.createChannelSplitter(numChannels);
266
- node.connect(splitter);
267
- const channels = [];
268
- for (let i = 0; i < numChannels; i++) {
269
- splitter.connect(this.#channelMerger, i, channel);
270
- channels.push(channel);
271
- channel++;
272
- }
273
- map.push({ uuid, channels });
274
- }
275
- this.#commands.updateMonitoringMap(map);
238
+ this.#monitoringRouter.unregisterSource(uuid);
276
239
  }
277
240
  #updateCpuLoad(budgetMs, project) {
278
241
  while (this.#lastPerfReadIndex !== this.#perfIndex) {
@@ -0,0 +1,10 @@
1
+ import { Terminable, UUID } from "@opendaw/lib-std";
2
+ import { EngineCommands } from "@opendaw/studio-adapters";
3
+ export declare class MonitoringRouter implements Terminable {
4
+ #private;
5
+ constructor(worklet: AudioWorkletNode, commands: EngineCommands);
6
+ registerSource(uuid: UUID.Bytes, sourceNode: AudioNode, numChannels: 1 | 2, destinationNode: AudioNode): void;
7
+ unregisterSource(uuid: UUID.Bytes): void;
8
+ terminate(): void;
9
+ }
10
+ //# sourceMappingURL=MonitoringRouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonitoringRouter.d.ts","sourceRoot":"","sources":["../src/MonitoringRouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,UAAU,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACtF,OAAO,EAAqB,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAW3E,qBAAa,gBAAiB,YAAW,UAAU;;gBAUnC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,cAAc;IAQ/D,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,EAAE,eAAe,EAAE,SAAS,GAAG,IAAI;IAK7G,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI;IAuDxC,SAAS,IAAI,IAAI;CAWpB"}
@@ -0,0 +1,89 @@
1
+ import { isDefined, UUID } from "@opendaw/lib-std";
2
+ const MAX_MONITORING_CHANNELS = 8;
3
+ export class MonitoringRouter {
4
+ #context;
5
+ #worklet;
6
+ #commands;
7
+ #splitter;
8
+ #sources = UUID.newSet(entry => entry.uuid);
9
+ #inputMerger = null;
10
+ #outputMergers = [];
11
+ constructor(worklet, commands) {
12
+ this.#context = worklet.context;
13
+ this.#worklet = worklet;
14
+ this.#commands = commands;
15
+ this.#splitter = this.#context.createChannelSplitter(MAX_MONITORING_CHANNELS);
16
+ worklet.connect(this.#splitter, 1);
17
+ }
18
+ registerSource(uuid, sourceNode, numChannels, destinationNode) {
19
+ this.#sources.add({ uuid, sourceNode, numChannels, destinationNode }, true);
20
+ this.#rebuild();
21
+ }
22
+ unregisterSource(uuid) {
23
+ this.#sources.removeByKeyIfExist(uuid);
24
+ this.#rebuild();
25
+ }
26
+ #rebuild() {
27
+ if (isDefined(this.#inputMerger)) {
28
+ this.#inputMerger.disconnect();
29
+ this.#inputMerger = null;
30
+ }
31
+ for (const merger of this.#outputMergers) {
32
+ merger.disconnect();
33
+ }
34
+ this.#outputMergers = [];
35
+ if (this.#sources.isEmpty()) {
36
+ this.#commands.updateMonitoringMap([]);
37
+ return;
38
+ }
39
+ let totalChannels = 0;
40
+ for (const { numChannels } of this.#sources) {
41
+ totalChannels += numChannels;
42
+ }
43
+ if (totalChannels > MAX_MONITORING_CHANNELS) {
44
+ console.warn(`MonitoringRouter: ${totalChannels} channels requested, max is ${MAX_MONITORING_CHANNELS}. Some sources will not receive effects monitoring.`);
45
+ }
46
+ const usedChannels = Math.min(totalChannels, MAX_MONITORING_CHANNELS);
47
+ this.#inputMerger = this.#context.createChannelMerger(usedChannels);
48
+ this.#inputMerger.connect(this.#worklet);
49
+ const map = [];
50
+ let channel = 0;
51
+ for (const { uuid, sourceNode, numChannels, destinationNode } of this.#sources) {
52
+ if (channel + numChannels > MAX_MONITORING_CHANNELS) {
53
+ break;
54
+ }
55
+ const inputSplitter = this.#context.createChannelSplitter(numChannels);
56
+ sourceNode.connect(inputSplitter);
57
+ const channels = [];
58
+ for (let i = 0; i < numChannels; i++) {
59
+ inputSplitter.connect(this.#inputMerger, i, channel);
60
+ channels.push(channel);
61
+ channel++;
62
+ }
63
+ map.push({ uuid, channels });
64
+ const outputMerger = this.#context.createChannelMerger(2);
65
+ if (numChannels === 2) {
66
+ this.#splitter.connect(outputMerger, channels[0], 0);
67
+ this.#splitter.connect(outputMerger, channels[1], 1);
68
+ }
69
+ else {
70
+ this.#splitter.connect(outputMerger, channels[0], 0);
71
+ this.#splitter.connect(outputMerger, channels[0], 1);
72
+ }
73
+ outputMerger.connect(destinationNode);
74
+ this.#outputMergers.push(outputMerger);
75
+ }
76
+ this.#commands.updateMonitoringMap(map);
77
+ }
78
+ terminate() {
79
+ if (isDefined(this.#inputMerger)) {
80
+ this.#inputMerger.disconnect();
81
+ this.#inputMerger = null;
82
+ }
83
+ for (const merger of this.#outputMergers) {
84
+ merger.disconnect();
85
+ }
86
+ this.#outputMergers = [];
87
+ this.#sources.clear();
88
+ }
89
+ }
@@ -19,6 +19,16 @@ export declare class CaptureAudio extends Capture<CaptureAudioBox> {
19
19
  get streamMediaTrack(): Option<MediaStreamTrack>;
20
20
  get outputNode(): Option<AudioNode>;
21
21
  get effectiveChannelCount(): number;
22
+ get monitorGainNode(): GainNode;
23
+ get monitorPanNode(): StereoPannerNode;
24
+ get monitorVolumeDb(): number;
25
+ set monitorVolumeDb(value: number);
26
+ get monitorPan(): number;
27
+ set monitorPan(value: number);
28
+ get monitorMuted(): boolean;
29
+ set monitorMuted(value: boolean);
30
+ get monitorOutputDeviceId(): Option<string>;
31
+ setMonitorOutputDevice(deviceId: Option<string>): Promise<void>;
22
32
  prepareRecording(): Promise<void>;
23
33
  startRecording(): Terminable;
24
34
  }
@@ -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;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;IA4BvC,cAAc,IAAI,UAAU;CAsH/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;;gBAsB1C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe;IA+CjG,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,CAAuD;IAC1F,IAAI,qBAAqB,IAAI,MAAM,CAA6C;IAChF,IAAI,eAAe,IAAI,QAAQ,CAA+B;IAC9D,IAAI,cAAc,IAAI,gBAAgB,CAA8B;IACpE,IAAI,eAAe,IAAI,MAAM,CAA+B;IAC5D,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,EAGhC;IACD,IAAI,UAAU,IAAI,MAAM,CAA0B;IAClD,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,EAG3B;IACD,IAAI,YAAY,IAAI,OAAO,CAA4B;IACvD,IAAI,YAAY,CAAC,KAAK,EAAE,OAAO,EAG9B;IACD,IAAI,qBAAqB,IAAI,MAAM,CAAC,MAAM,CAAC,CAAqC;IAE1E,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAoC/D,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BvC,cAAc,IAAI,UAAU;CA6H/B"}
@@ -8,29 +8,45 @@ import { RenderQuantum } from "../RenderQuantum";
8
8
  export class CaptureAudio extends Capture {
9
9
  #stream;
10
10
  #streamGenerator;
11
+ #monitorGainNode;
12
+ #monitorPanNode;
11
13
  #monitoringMode = "off";
12
14
  #requestChannels = Option.None;
13
15
  #gainDb = 0.0;
16
+ #monitorVolumeDb = 0.0;
17
+ #monitorPan = 0.0;
18
+ #monitorMuted = false;
14
19
  #audioChain = null;
15
20
  #preparedWorklet = null;
21
+ #monitorOutputDeviceId = Option.None;
22
+ #monitorAudioElement = null;
23
+ #monitorStreamDest = null;
16
24
  constructor(manager, audioUnitBox, captureAudioBox) {
17
25
  super(manager, audioUnitBox, captureAudioBox);
26
+ const { audioContext } = this.manager.project.env;
27
+ this.#monitorGainNode = audioContext.createGain();
28
+ this.#monitorGainNode.gain.value = dbToGain(this.#monitorVolumeDb);
29
+ this.#monitorPanNode = audioContext.createStereoPanner();
30
+ this.#monitorPanNode.pan.value = this.#monitorPan;
31
+ this.#monitorGainNode.connect(this.#monitorPanNode);
18
32
  this.#stream = new MutableObservableOption();
19
33
  this.#streamGenerator = Promises.sequentialize(() => this.#updateStream());
20
- this.ownAll(captureAudioBox.requestChannels.catchupAndSubscribe(owner => {
34
+ this.ownAll(Terminable.create(() => {
35
+ this.#disconnectMonitoring();
36
+ if (isDefined(this.#monitorAudioElement)) {
37
+ this.#monitorAudioElement.pause();
38
+ this.#monitorAudioElement.srcObject = null;
39
+ }
40
+ this.#monitorGainNode.disconnect();
41
+ this.#monitorPanNode.disconnect();
42
+ }), captureAudioBox.requestChannels.catchupAndSubscribe(owner => {
21
43
  const channels = owner.getValue();
22
44
  this.#requestChannels = channels === 1 || channels === 2 ? Option.wrap(channels) : Option.None;
23
45
  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
- }
30
46
  }), captureAudioBox.gainDb.catchupAndSubscribe(owner => {
31
47
  this.#gainDb = owner.getValue();
32
48
  if (isDefined(this.#audioChain)) {
33
- this.#audioChain.gainNode.gain.value = dbToGain(this.#gainDb);
49
+ this.#audioChain.recordGainNode.gain.value = dbToGain(this.#gainDb);
34
50
  }
35
51
  }), captureAudioBox.deviceId.catchupAndSubscribe(async () => {
36
52
  if (this.armed.getValue()) {
@@ -71,13 +87,67 @@ export class CaptureAudio extends Capture {
71
87
  get streamMediaTrack() {
72
88
  return this.#stream.flatMap(stream => Option.wrap(stream.getAudioTracks().at(0)));
73
89
  }
74
- get outputNode() { return Option.wrap(this.#audioChain?.gainNode); }
90
+ get outputNode() { return Option.wrap(this.#audioChain?.recordGainNode); }
75
91
  get effectiveChannelCount() { return this.#audioChain?.channelCount ?? 1; }
92
+ get monitorGainNode() { return this.#monitorGainNode; }
93
+ get monitorPanNode() { return this.#monitorPanNode; }
94
+ get monitorVolumeDb() { return this.#monitorVolumeDb; }
95
+ set monitorVolumeDb(value) {
96
+ this.#monitorVolumeDb = value;
97
+ this.#monitorGainNode.gain.value = this.#monitorMuted ? 0 : dbToGain(this.#monitorVolumeDb);
98
+ }
99
+ get monitorPan() { return this.#monitorPan; }
100
+ set monitorPan(value) {
101
+ this.#monitorPan = value;
102
+ this.#monitorPanNode.pan.value = value;
103
+ }
104
+ get monitorMuted() { return this.#monitorMuted; }
105
+ set monitorMuted(value) {
106
+ this.#monitorMuted = value;
107
+ this.#monitorGainNode.gain.value = value ? 0 : dbToGain(this.#monitorVolumeDb);
108
+ }
109
+ get monitorOutputDeviceId() { return this.#monitorOutputDeviceId; }
110
+ async setMonitorOutputDevice(deviceId) {
111
+ const oldDestination = this.#monitorDestination();
112
+ this.#monitorOutputDeviceId = deviceId;
113
+ if (isDefined(this.#monitorAudioElement)) {
114
+ this.#monitorAudioElement.pause();
115
+ this.#monitorAudioElement.srcObject = null;
116
+ this.#monitorAudioElement = null;
117
+ }
118
+ if (isDefined(this.#monitorStreamDest)) {
119
+ this.#monitorStreamDest.disconnect();
120
+ this.#monitorStreamDest = null;
121
+ }
122
+ if (deviceId.nonEmpty()) {
123
+ const { audioContext } = this.manager.project.env;
124
+ this.#monitorStreamDest = audioContext.createMediaStreamDestination();
125
+ const audio = new Audio();
126
+ audio.srcObject = this.#monitorStreamDest.stream;
127
+ try {
128
+ await audio.setSinkId(deviceId.unwrap());
129
+ await audio.play();
130
+ this.#monitorAudioElement = audio;
131
+ }
132
+ catch (reason) {
133
+ audio.srcObject = null;
134
+ this.#monitorStreamDest.disconnect();
135
+ this.#monitorStreamDest = null;
136
+ this.#monitorOutputDeviceId = Option.None;
137
+ RuntimeNotifier.info({ headline: "Output Device Error", message: `${reason}` });
138
+ return;
139
+ }
140
+ }
141
+ if (this.#monitoringMode !== "off" && isDefined(this.#audioChain)) {
142
+ this.#monitorPanNode.disconnect(oldDestination);
143
+ this.#monitorPanNode.connect(this.#monitorDestination());
144
+ }
145
+ }
76
146
  async prepareRecording() {
77
147
  const { project } = this.manager;
78
148
  const { env: { audioContext, audioWorklets, sampleManager, sampleService } } = project;
79
149
  if (isUndefined(audioContext.outputLatency)) {
80
- const approved = RuntimeNotifier.approve({
150
+ const approved = await RuntimeNotifier.approve({
81
151
  headline: "Warning",
82
152
  message: "Your browser does not support 'output latency'. This will cause timing issue while recording.",
83
153
  approveText: "Ignore",
@@ -92,12 +162,12 @@ export class CaptureAudio extends Capture {
92
162
  if (!isDefined(audioChain)) {
93
163
  return Promise.reject("No audio chain available for recording.");
94
164
  }
95
- const { gainNode, channelCount } = audioChain;
165
+ const { recordGainNode, channelCount } = audioChain;
96
166
  const recordingWorklet = audioWorklets.createRecording(channelCount, RenderQuantum);
97
167
  recordingWorklet.bpm = project.timelineBox.bpm.getValue();
98
168
  recordingWorklet.sampleService = sampleService;
99
169
  sampleManager.record(recordingWorklet);
100
- gainNode.connect(recordingWorklet);
170
+ recordGainNode.connect(recordingWorklet);
101
171
  this.#preparedWorklet = recordingWorklet;
102
172
  }
103
173
  startRecording() {
@@ -110,10 +180,10 @@ export class CaptureAudio extends Capture {
110
180
  return Terminable.Empty;
111
181
  }
112
182
  this.#preparedWorklet = null;
113
- const { gainNode } = audioChain;
183
+ const { recordGainNode } = audioChain;
114
184
  return RecordAudio.start({
115
185
  recordingWorklet,
116
- sourceNode: gainNode,
186
+ sourceNode: recordGainNode,
117
187
  sampleManager,
118
188
  project,
119
189
  capture: this,
@@ -157,47 +227,51 @@ export class CaptureAudio extends Capture {
157
227
  });
158
228
  }
159
229
  #stopStream() {
230
+ this.#disconnectMonitoring();
160
231
  this.#destroyAudioChain();
161
232
  this.#stream.clear(stream => stream.getAudioTracks().forEach(track => track.stop()));
162
233
  }
163
234
  #rebuildAudioChain(stream) {
164
- const wasMonitoringMode = this.#monitoringMode !== "off" && isDefined(this.#audioChain) ? this.#monitoringMode : "off";
235
+ this.#disconnectMonitoring();
165
236
  this.#destroyAudioChain();
166
237
  const { audioContext } = this.manager.project.env;
167
238
  const sourceNode = audioContext.createMediaStreamSource(stream);
168
- const gainNode = audioContext.createGain();
169
- gainNode.gain.value = dbToGain(this.#gainDb);
239
+ const recordGainNode = audioContext.createGain();
240
+ recordGainNode.gain.value = dbToGain(this.#gainDb);
170
241
  const streamChannelCount = Math.min(stream.getAudioTracks().at(0)?.getSettings().channelCount ?? 2, 2);
171
242
  const channelCount = this.#requestChannels.unwrapOrElse(streamChannelCount);
172
- gainNode.channelCount = channelCount;
173
- gainNode.channelCountMode = "explicit";
174
- sourceNode.connect(gainNode);
175
- this.#audioChain = { sourceNode, gainNode, channelCount };
176
- if (wasMonitoringMode !== "off" || this.#monitoringMode !== "off") {
177
- this.#connectMonitoring();
178
- }
243
+ recordGainNode.channelCount = channelCount;
244
+ recordGainNode.channelCountMode = "explicit";
245
+ sourceNode.connect(recordGainNode);
246
+ this.#audioChain = { sourceNode, recordGainNode, channelCount };
247
+ this.#connectMonitoring();
179
248
  }
180
249
  #destroyAudioChain() {
181
250
  if (isDefined(this.#audioChain)) {
182
- const { sourceNode, gainNode } = this.#audioChain;
251
+ const { sourceNode, recordGainNode } = this.#audioChain;
183
252
  sourceNode.disconnect();
184
- gainNode.disconnect();
253
+ recordGainNode.disconnect();
185
254
  this.#audioChain = null;
186
255
  }
187
256
  }
257
+ #monitorDestination() {
258
+ return this.#monitorStreamDest ?? this.manager.project.env.audioContext.destination;
259
+ }
188
260
  #connectMonitoring() {
189
261
  if (!isDefined(this.#audioChain)) {
190
262
  return;
191
263
  }
264
+ const { sourceNode, channelCount } = this.#audioChain;
192
265
  switch (this.#monitoringMode) {
193
266
  case "off":
194
267
  break;
195
268
  case "direct":
196
- this.#audioChain.gainNode.connect(this.manager.project.env.audioContext.destination);
269
+ sourceNode.connect(this.#monitorGainNode);
270
+ this.#monitorPanNode.connect(this.#monitorDestination());
197
271
  break;
198
272
  case "effects":
199
- const engine = this.manager.project.engine;
200
- engine.registerMonitoringSource(this.audioUnitBox.address.uuid, this.#audioChain.gainNode, this.#audioChain.channelCount);
273
+ this.manager.project.engine.registerMonitoringSource(this.audioUnitBox.address.uuid, sourceNode, channelCount, this.#monitorGainNode);
274
+ this.#monitorPanNode.connect(this.#monitorDestination());
201
275
  break;
202
276
  }
203
277
  }
@@ -209,11 +283,12 @@ export class CaptureAudio extends Capture {
209
283
  case "off":
210
284
  break;
211
285
  case "direct":
212
- this.#audioChain.gainNode.disconnect(this.manager.project.env.audioContext.destination);
286
+ this.#audioChain.sourceNode.disconnect(this.#monitorGainNode);
287
+ this.#monitorPanNode.disconnect(this.#monitorDestination());
213
288
  break;
214
289
  case "effects":
215
- this.#audioChain.gainNode.disconnect();
216
290
  this.manager.project.engine.unregisterMonitoringSource(this.audioUnitBox.address.uuid);
291
+ this.#monitorPanNode.disconnect(this.#monitorDestination());
217
292
  break;
218
293
  }
219
294
  }
@@ -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,UA8ML,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,UAsNL,CAAA;;CACJ"}
@@ -124,8 +124,9 @@ export var RecordAudio;
124
124
  pointer.refer(newFileBox.transientMarkers);
125
125
  }
126
126
  oldFileBox.delete();
127
- });
127
+ }, false);
128
128
  });
129
+ editing.mark();
129
130
  };
130
131
  terminator.ownAll(Terminable.create(() => {
131
132
  tryCatch(() => sourceNode.disconnect(recordingWorklet));
@@ -178,10 +179,17 @@ export var RecordAudio;
178
179
  editing.modify(() => {
179
180
  currentTake.ifSome(take => {
180
181
  const actualDurationInSeconds = take.regionBox.duration.getValue();
182
+ if (actualDurationInSeconds <= 0) {
183
+ take.regionBox.delete();
184
+ currentTake = Option.None;
185
+ return;
186
+ }
181
187
  finalizeTake(take, actualDurationInSeconds);
182
188
  currentWaveformOffset += actualDurationInSeconds;
183
189
  });
184
- startNewTake(loopFrom);
190
+ if (currentTake.nonEmpty()) {
191
+ startNewTake(loopFrom);
192
+ }
185
193
  }, false);
186
194
  }
187
195
  lastPosition = currentPosition;
@@ -37,7 +37,7 @@ export class Recording {
37
37
  if (isRecording.getValue() || isCountingIn.getValue()) {
38
38
  return;
39
39
  }
40
- editing.modify(() => terminator.terminate()); // finalizes recording
40
+ editing.modify(() => terminator.terminate(), false); // finalizes recording
41
41
  this.#isRecording = false;
42
42
  };
43
43
  terminator.ownAll(engine.isRecording.subscribe(stop), engine.isCountingIn.subscribe(stop), Terminable.create(() => Recording.#instance = Option.None));