@opendaw/studio-core 0.0.23 → 0.0.24

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 (102) hide show
  1. package/dist/AudioDevices.d.ts.map +1 -1
  2. package/dist/AudioDevices.js +1 -0
  3. package/dist/{Worklets.d.ts → AudioWorklets.d.ts} +6 -5
  4. package/dist/AudioWorklets.d.ts.map +1 -0
  5. package/dist/{Worklets.js → AudioWorklets.js} +3 -2
  6. package/dist/EffectFactory.d.ts +1 -1
  7. package/dist/EffectFactory.d.ts.map +1 -1
  8. package/dist/Engine.d.ts +6 -16
  9. package/dist/Engine.d.ts.map +1 -1
  10. package/dist/EngineFacade.d.ts +10 -9
  11. package/dist/EngineFacade.d.ts.map +1 -1
  12. package/dist/EngineFacade.js +28 -25
  13. package/dist/EngineWorklet.d.ts +7 -7
  14. package/dist/EngineWorklet.d.ts.map +1 -1
  15. package/dist/EngineWorklet.js +8 -16
  16. package/dist/PeaksWriter.d.ts +19 -0
  17. package/dist/PeaksWriter.d.ts.map +1 -0
  18. package/dist/PeaksWriter.js +43 -0
  19. package/dist/RecordingWorklet.d.ts +4 -2
  20. package/dist/RecordingWorklet.d.ts.map +1 -1
  21. package/dist/RecordingWorklet.js +36 -62
  22. package/dist/capture/Capture.d.ts +5 -6
  23. package/dist/capture/Capture.d.ts.map +1 -1
  24. package/dist/capture/CaptureAudio.d.ts +4 -5
  25. package/dist/capture/CaptureAudio.d.ts.map +1 -1
  26. package/dist/capture/CaptureAudio.js +26 -14
  27. package/dist/capture/{CaptureManager.d.ts → CaptureDevices.d.ts} +4 -3
  28. package/dist/capture/CaptureDevices.d.ts.map +1 -0
  29. package/dist/capture/{CaptureManager.js → CaptureDevices.js} +10 -1
  30. package/dist/capture/CaptureMidi.d.ts +8 -6
  31. package/dist/capture/CaptureMidi.d.ts.map +1 -1
  32. package/dist/capture/CaptureMidi.js +67 -47
  33. package/dist/capture/RecordAudio.d.ts +2 -2
  34. package/dist/capture/RecordAudio.d.ts.map +1 -1
  35. package/dist/capture/RecordAudio.js +50 -36
  36. package/dist/capture/RecordMidi.d.ts +3 -2
  37. package/dist/capture/RecordMidi.d.ts.map +1 -1
  38. package/dist/capture/RecordMidi.js +19 -22
  39. package/dist/capture/Recording.d.ts +2 -2
  40. package/dist/capture/Recording.d.ts.map +1 -1
  41. package/dist/capture/Recording.js +10 -11
  42. package/dist/dawproject/DawProject.d.ts +1 -1
  43. package/dist/dawproject/DawProject.d.ts.map +1 -1
  44. package/dist/dawproject/DawProject.js +3 -2
  45. package/dist/dawproject/DawProjectExporter.d.ts +1 -1
  46. package/dist/dawproject/DawProjectExporter.d.ts.map +1 -1
  47. package/dist/dawproject/DawProjectExporter.test.js +6 -5
  48. package/dist/index.d.ts +10 -6
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +10 -6
  51. package/dist/processors.js +3 -3
  52. package/dist/processors.js.map +4 -4
  53. package/dist/{Project.d.ts → project/Project.d.ts} +8 -7
  54. package/dist/project/Project.d.ts.map +1 -0
  55. package/dist/{Project.js → project/Project.js} +14 -6
  56. package/dist/{ProjectApi.d.ts → project/ProjectApi.d.ts} +5 -5
  57. package/dist/project/ProjectApi.d.ts.map +1 -0
  58. package/dist/{ProjectApi.js → project/ProjectApi.js} +2 -2
  59. package/dist/project/ProjectBundle.d.ts +8 -0
  60. package/dist/project/ProjectBundle.d.ts.map +1 -0
  61. package/dist/project/ProjectBundle.js +90 -0
  62. package/dist/project/ProjectEnv.d.ts +15 -0
  63. package/dist/project/ProjectEnv.d.ts.map +1 -0
  64. package/dist/project/ProjectMeta.d.ts +14 -0
  65. package/dist/project/ProjectMeta.d.ts.map +1 -0
  66. package/dist/project/ProjectMeta.js +12 -0
  67. package/dist/project/ProjectMigration.d.ts.map +1 -0
  68. package/dist/project/ProjectPaths.d.ts +12 -0
  69. package/dist/project/ProjectPaths.d.ts.map +1 -0
  70. package/dist/project/ProjectPaths.js +12 -0
  71. package/dist/project/ProjectProfile.d.ts +21 -0
  72. package/dist/project/ProjectProfile.d.ts.map +1 -0
  73. package/dist/project/ProjectProfile.js +83 -0
  74. package/dist/samples/MainThreadSampleLoader.d.ts +0 -2
  75. package/dist/samples/MainThreadSampleLoader.d.ts.map +1 -1
  76. package/dist/samples/MainThreadSampleLoader.js +1 -26
  77. package/dist/samples/MainThreadSampleManager.d.ts +1 -0
  78. package/dist/samples/MainThreadSampleManager.d.ts.map +1 -1
  79. package/dist/samples/MainThreadSampleManager.js +1 -0
  80. package/dist/sync-log/Commit.d.ts +1 -1
  81. package/dist/sync-log/Commit.d.ts.map +1 -1
  82. package/dist/sync-log/SyncLogReader.d.ts +2 -2
  83. package/dist/sync-log/SyncLogReader.d.ts.map +1 -1
  84. package/dist/sync-log/SyncLogReader.js +1 -1
  85. package/dist/sync-log/SyncLogWriter.d.ts +1 -1
  86. package/dist/sync-log/SyncLogWriter.d.ts.map +1 -1
  87. package/dist/workers.js +2 -2
  88. package/dist/workers.js.map +3 -3
  89. package/package.json +14 -14
  90. package/dist/Project.d.ts.map +0 -1
  91. package/dist/ProjectApi.d.ts.map +0 -1
  92. package/dist/ProjectEnv.d.ts +0 -5
  93. package/dist/ProjectEnv.d.ts.map +0 -1
  94. package/dist/ProjectMigration.d.ts.map +0 -1
  95. package/dist/Worklets.d.ts.map +0 -1
  96. package/dist/capture/CaptureManager.d.ts.map +0 -1
  97. package/dist/capture/RecordingContext.d.ts +0 -10
  98. package/dist/capture/RecordingContext.d.ts.map +0 -1
  99. package/dist/capture/RecordingContext.js +0 -1
  100. /package/dist/{ProjectEnv.js → project/ProjectEnv.js} +0 -0
  101. /package/dist/{ProjectMigration.d.ts → project/ProjectMigration.d.ts} +0 -0
  102. /package/dist/{ProjectMigration.js → project/ProjectMigration.js} +0 -0
@@ -1,17 +1,16 @@
1
1
  import { MutableObservableValue, Option, Terminable, UUID } from "@opendaw/lib-std";
2
2
  import { AudioUnitBox } from "@opendaw/studio-boxes";
3
3
  import { CaptureBox } from "@opendaw/studio-adapters";
4
- import { RecordingContext } from "./RecordingContext";
5
- import { CaptureManager } from "./CaptureManager";
4
+ import { CaptureDevices } from "./CaptureDevices";
6
5
  export declare abstract class Capture<BOX extends CaptureBox = CaptureBox> implements Terminable {
7
6
  #private;
8
- protected constructor(manager: CaptureManager, audioUnitBox: AudioUnitBox, captureBox: BOX);
7
+ protected constructor(manager: CaptureDevices, audioUnitBox: AudioUnitBox, captureBox: BOX);
9
8
  abstract get label(): string;
10
9
  abstract get deviceLabel(): Option<string>;
11
- abstract prepareRecording(context: RecordingContext): Promise<void>;
12
- abstract startRecording(context: RecordingContext): Terminable;
10
+ abstract prepareRecording(): Promise<void>;
11
+ abstract startRecording(): Terminable;
13
12
  get uuid(): UUID.Format;
14
- get manager(): CaptureManager;
13
+ get manager(): CaptureDevices;
15
14
  get audioUnitBox(): AudioUnitBox;
16
15
  get captureBox(): BOX;
17
16
  get armed(): MutableObservableValue<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"Capture.d.ts","sourceRoot":"","sources":["../../src/capture/Capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,sBAAsB,EACtB,MAAM,EACN,UAAU,EAEV,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAA;AAEnD,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAE/C,8BAAsB,OAAO,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAE,YAAW,UAAU;;IAUpF,SAAS,aAAa,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG;IAmB1F,QAAQ,KAAK,KAAK,IAAI,MAAM,CAAA;IAC5B,QAAQ,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;IAC1C,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IACnE,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU;IAE9D,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAyC;IAChE,IAAI,OAAO,IAAI,cAAc,CAAuB;IACpD,IAAI,YAAY,IAAI,YAAY,CAA4B;IAC5D,IAAI,UAAU,IAAI,GAAG,CAA0B;IAC/C,IAAI,KAAK,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAqB;IACjE,IAAI,QAAQ,IAAI,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAwB;IAE9E,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;IAC3C,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,GAAG,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI;IACpE,SAAS,IAAI,IAAI;CACpB"}
1
+ {"version":3,"file":"Capture.d.ts","sourceRoot":"","sources":["../../src/capture/Capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,sBAAsB,EACtB,MAAM,EACN,UAAU,EAEV,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAE/C,8BAAsB,OAAO,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAAE,YAAW,UAAU;;IAUpF,SAAS,aAAa,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG;IAmB1F,QAAQ,KAAK,KAAK,IAAI,MAAM,CAAA;IAC5B,QAAQ,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;IAC1C,QAAQ,CAAC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAC1C,QAAQ,CAAC,cAAc,IAAI,UAAU;IAErC,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAyC;IAChE,IAAI,OAAO,IAAI,cAAc,CAAuB;IACpD,IAAI,YAAY,IAAI,YAAY,CAA4B;IAC5D,IAAI,UAAU,IAAI,GAAG,CAA0B;IAC/C,IAAI,KAAK,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAqB;IACjE,IAAI,QAAQ,IAAI,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAwB;IAE9E,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;IAC3C,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,GAAG,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI;IACpE,SAAS,IAAI,IAAI;CACpB"}
@@ -1,18 +1,17 @@
1
1
  import { MutableObservableOption, Option, Terminable } from "@opendaw/lib-std";
2
2
  import { AudioUnitBox, CaptureAudioBox } from "@opendaw/studio-boxes";
3
3
  import { Capture } from "./Capture";
4
- import { CaptureManager } from "./CaptureManager";
5
- import { RecordingContext } from "./RecordingContext";
4
+ import { CaptureDevices } from "./CaptureDevices";
6
5
  export declare class CaptureAudio extends Capture<CaptureAudioBox> {
7
6
  #private;
8
- constructor(manager: CaptureManager, audioUnitBox: AudioUnitBox, captureAudioBox: CaptureAudioBox);
7
+ constructor(manager: CaptureDevices, audioUnitBox: AudioUnitBox, captureAudioBox: CaptureAudioBox);
9
8
  get gainDb(): number;
10
9
  get stream(): MutableObservableOption<MediaStream>;
11
10
  get streamDeviceId(): Option<string>;
12
11
  get label(): string;
13
12
  get deviceLabel(): Option<string>;
14
13
  get streamMediaTrack(): Option<MediaStreamTrack>;
15
- prepareRecording({}: RecordingContext): Promise<void>;
16
- startRecording({ audioContext, worklets, project, sampleManager }: RecordingContext): Terminable;
14
+ prepareRecording(): Promise<void>;
15
+ startRecording(): Terminable;
17
16
  }
18
17
  //# sourceMappingURL=CaptureAudio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CaptureAudio.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,uBAAuB,EAAE,MAAM,EAAE,UAAU,EAAO,MAAM,kBAAkB,CAAA;AAExH,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;AAE/C,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AAGnD,qBAAa,YAAa,SAAQ,OAAO,CAAC,eAAe,CAAC;;gBAQ1C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe;IA4BjG,IAAI,MAAM,IAAI,MAAM,CAAsB;IAE1C,IAAI,MAAM,IAAI,uBAAuB,CAAC,WAAW,CAAC,CAAsB;IAExE,IAAI,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,CAEnC;IAED,IAAI,KAAK,IAAI,MAAM,CAAsE;IAEzF,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAA+D;IAEhG,IAAI,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAE/C;IAEK,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAE3D,cAAc,CAAC,EAAC,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAC,EAAE,gBAAgB,GAAG,UAAU;CA6DjG"}
1
+ {"version":3,"file":"CaptureAudio.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,uBAAuB,EACvB,MAAM,EAEN,UAAU,EAEb,MAAM,kBAAkB,CAAA;AAEzB,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;AAI/C,qBAAa,YAAa,SAAQ,OAAO,CAAC,eAAe,CAAC;;gBAQ1C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe;IA4BjG,IAAI,MAAM,IAAI,MAAM,CAAsB;IAE1C,IAAI,MAAM,IAAI,uBAAuB,CAAC,WAAW,CAAC,CAAsB;IAExE,IAAI,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,CAEnC;IAED,IAAI,KAAK,IAAI,MAAM,CAAsE;IAEzF,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAA+D;IAEhG,IAAI,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAE/C;IAEK,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAcvC,cAAc,IAAI,UAAU;CA+D/B"}
@@ -1,4 +1,4 @@
1
- import { assert, isDefined, isUndefined, MutableObservableOption, Option, warn } from "@opendaw/lib-std";
1
+ import { abort, isDefined, isUndefined, MutableObservableOption, Option, safeExecute, Terminable, warn } from "@opendaw/lib-std";
2
2
  import { Promises } from "@opendaw/lib-runtime";
3
3
  import { Capture } from "./Capture";
4
4
  import { RecordAudio } from "./RecordAudio";
@@ -39,14 +39,29 @@ export class CaptureAudio extends Capture {
39
39
  get streamMediaTrack() {
40
40
  return this.#stream.flatMap(stream => Option.wrap(stream.getAudioTracks().at(0)));
41
41
  }
42
- async prepareRecording({}) { return this.#streamGenerator(); }
43
- startRecording({ audioContext, worklets, project, sampleManager }) {
42
+ async prepareRecording() {
43
+ const { project } = this.manager;
44
+ const { env: { audioContext } } = project;
45
+ if (isUndefined(audioContext.outputLatency)) {
46
+ const approved = await safeExecute(project.env.dialogs?.approve, "Warning", "Your browser does not support 'output latency'. This will cause timing issue while recording.", "Ignore", "Cancel");
47
+ if (!approved) {
48
+ return abort("Recording cancelled");
49
+ }
50
+ }
51
+ return this.#streamGenerator();
52
+ }
53
+ startRecording() {
54
+ const { project } = this.manager;
55
+ const { env: { audioContext, audioWorklets, sampleManager } } = project;
44
56
  const streamOption = this.#stream;
45
- assert(streamOption.nonEmpty(), "Stream not prepared.");
57
+ if (streamOption.isEmpty()) {
58
+ console.warn("No audio stream available for recording.");
59
+ return Terminable.Empty;
60
+ }
46
61
  const mediaStream = streamOption.unwrap();
47
62
  const channelCount = mediaStream.getAudioTracks().at(0)?.getSettings().channelCount ?? 1;
48
63
  const numChunks = 128;
49
- const recordingWorklet = worklets.createRecording(channelCount, numChunks, audioContext.outputLatency);
64
+ const recordingWorklet = audioWorklets.createRecording(channelCount, numChunks, audioContext.outputLatency);
50
65
  return RecordAudio.start({
51
66
  recordingWorklet,
52
67
  mediaStream,
@@ -61,20 +76,16 @@ export class CaptureAudio extends Capture {
61
76
  if (this.#stream.nonEmpty()) {
62
77
  const stream = this.#stream.unwrap();
63
78
  const settings = stream.getAudioTracks().at(0)?.getSettings();
64
- console.debug(stream.getAudioTracks());
65
79
  if (isDefined(settings)) {
66
80
  const deviceId = this.deviceId.getValue().unwrapOrUndefined();
67
- const channelCount = this.#requestChannels.unwrapOrElse(1);
68
- const satisfyChannelCount = settings.channelCount === channelCount;
69
- const satisfiedDeviceId = isUndefined(deviceId) || deviceId === settings.deviceId;
70
- if (satisfiedDeviceId && satisfyChannelCount) {
81
+ if (isUndefined(deviceId) || deviceId === settings.deviceId) {
71
82
  return Promise.resolve();
72
83
  }
73
84
  }
74
85
  }
75
86
  this.#stopStream();
76
87
  const deviceId = this.deviceId.getValue().unwrapOrUndefined();
77
- const channelCount = this.#requestChannels.unwrapOrElse(1); // as of today, browsers cap MediaStream audio to stereo.
88
+ const channelCount = this.#requestChannels.unwrapOrElse(1);
78
89
  return AudioDevices.requestStream({
79
90
  deviceId: { exact: deviceId },
80
91
  sampleRate: this.manager.project.engine.sampleRate(),
@@ -82,12 +93,13 @@ export class CaptureAudio extends Capture {
82
93
  echoCancellation: false,
83
94
  noiseSuppression: false,
84
95
  autoGainControl: false,
85
- channelCount
96
+ channelCount: { ideal: channelCount }
86
97
  }).then(stream => {
87
98
  const tracks = stream.getAudioTracks();
88
- const settings = tracks.at(0)?.getSettings();
99
+ const track = tracks.at(0);
100
+ const settings = track?.getSettings();
89
101
  const gotDeviceId = settings?.deviceId;
90
- console.debug(`new stream id: ${stream.id}, device: ${gotDeviceId ?? "Default"}`);
102
+ console.debug(`new stream. device requested: ${stream.id}, got: ${gotDeviceId ?? "Default"}. channelCount requested: ${channelCount}, got: ${settings?.channelCount}`);
91
103
  if (isUndefined(deviceId) || deviceId === gotDeviceId) {
92
104
  this.#stream.wrap(stream);
93
105
  }
@@ -1,12 +1,13 @@
1
1
  import { Option, Terminable, UUID } from "@opendaw/lib-std";
2
- import { Project } from "../Project";
2
+ import { Project } from "../project/Project";
3
3
  import { Capture } from "./Capture";
4
- export declare class CaptureManager implements Terminable {
4
+ export declare class CaptureDevices implements Terminable {
5
5
  #private;
6
6
  constructor(project: Project);
7
7
  get project(): Project;
8
8
  get(uuid: UUID.Format): Option<Capture>;
9
+ setArm(subject: Capture, exclusive: boolean): void;
9
10
  filterArmed(): ReadonlyArray<Capture>;
10
11
  terminate(): void;
11
12
  }
12
- //# sourceMappingURL=CaptureManager.d.ts.map
13
+ //# sourceMappingURL=CaptureDevices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CaptureDevices.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureDevices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,MAAM,EAA2B,UAAU,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAEpH,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAIjC,qBAAa,cAAe,YAAW,UAAU;;gBAKjC,OAAO,EAAE,OAAO;IAiB5B,IAAI,OAAO,IAAI,OAAO,CAAuB;IAE7C,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;IAEvC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI;IAUlD,WAAW,IAAI,aAAa,CAAC,OAAO,CAAC;IAKrC,SAAS,IAAI,IAAI;CAKpB"}
@@ -2,7 +2,7 @@ import { asInstanceOf, isDefined, UUID } from "@opendaw/lib-std";
2
2
  import { AudioUnitBox } from "@opendaw/studio-boxes";
3
3
  import { CaptureMidi } from "./CaptureMidi";
4
4
  import { CaptureAudio } from "./CaptureAudio";
5
- export class CaptureManager {
5
+ export class CaptureDevices {
6
6
  #project;
7
7
  #subscription;
8
8
  #captures;
@@ -26,6 +26,15 @@ export class CaptureManager {
26
26
  }
27
27
  get project() { return this.#project; }
28
28
  get(uuid) { return this.#captures.opt(uuid); }
29
+ setArm(subject, exclusive) {
30
+ const arming = !subject.armed.getValue();
31
+ subject.armed.setValue(arming);
32
+ if (arming && exclusive) {
33
+ this.#captures.values()
34
+ .filter(capture => subject !== capture)
35
+ .forEach(capture => capture.armed.setValue(false));
36
+ }
37
+ }
29
38
  filterArmed() {
30
39
  return this.#captures.values()
31
40
  .filter(capture => capture.armed.getValue() && capture.audioUnitBox.input.pointerHub.nonEmpty());
@@ -1,14 +1,16 @@
1
- import { Option, Terminable } from "@opendaw/lib-std";
1
+ import { Observer, Option, Subscription, Terminable } from "@opendaw/lib-std";
2
2
  import { AudioUnitBox, CaptureMidiBox } from "@opendaw/studio-boxes";
3
+ import { NoteSignal } from "@opendaw/studio-adapters";
3
4
  import { Capture } from "./Capture";
4
- import { RecordingContext } from "./RecordingContext";
5
- import { CaptureManager } from "./CaptureManager";
5
+ import { CaptureDevices } from "./CaptureDevices";
6
6
  export declare class CaptureMidi extends Capture<CaptureMidiBox> {
7
7
  #private;
8
- constructor(manager: CaptureManager, audioUnitBox: AudioUnitBox, captureMidiBox: CaptureMidiBox);
8
+ constructor(manager: CaptureDevices, audioUnitBox: AudioUnitBox, captureMidiBox: CaptureMidiBox);
9
+ notify(signal: NoteSignal): void;
10
+ subscribeNotes(observer: Observer<NoteSignal>): Subscription;
9
11
  get label(): string;
10
12
  get deviceLabel(): Option<string>;
11
- prepareRecording({}: RecordingContext): Promise<void>;
12
- startRecording({ project }: RecordingContext): Terminable;
13
+ prepareRecording(): Promise<void>;
14
+ startRecording(): Terminable;
13
15
  }
14
16
  //# sourceMappingURL=CaptureMidi.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CaptureMidi.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAQH,MAAM,EAEN,UAAU,EAEb,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAC,YAAY,EAAE,cAAc,EAAC,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAEjC,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAI/C,qBAAa,WAAY,SAAQ,OAAO,CAAC,cAAc,CAAC;;gBAQxC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc;IAqC/F,IAAI,KAAK,IAAI,MAAM,CAKlB;IAED,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAIhC;IAEK,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3D,cAAc,CAAC,EAAC,OAAO,EAAC,EAAE,gBAAgB,GAAG,UAAU;CA8C1D"}
1
+ {"version":3,"file":"CaptureMidi.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAOH,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,UAAU,EAEb,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAC,YAAY,EAAE,cAAc,EAAC,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAA;AAEnD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAG/C,qBAAa,WAAY,SAAQ,OAAO,CAAC,cAAc,CAAC;;gBAOxC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc;IA8B/F,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAEhC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY;IAE5D,IAAI,KAAK,IAAI,MAAM,CAgBlB;IAED,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAIhC;IAEK,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBvC,cAAc,IAAI,UAAU;CAgD/B"}
@@ -1,23 +1,26 @@
1
- import { asDefined, assert, isDefined, isUndefined, Notifier, Option, Terminable, warn } from "@opendaw/lib-std";
1
+ import { assert, isDefined, isUndefined, Notifier, Option, Terminable, warn } from "@opendaw/lib-std";
2
2
  import { Events } from "@opendaw/lib-dom";
3
3
  import { MidiData } from "@opendaw/lib-midi";
4
+ import { Promises } from "@opendaw/lib-runtime";
5
+ import { NoteSignal } from "@opendaw/studio-adapters";
6
+ import { MidiDevices } from "../MidiDevices";
4
7
  import { Capture } from "./Capture";
5
8
  import { RecordMidi } from "./RecordMidi";
6
- import { MidiDevices } from "../MidiDevices";
7
- import { Promises } from "@opendaw/lib-runtime";
8
9
  export class CaptureMidi extends Capture {
9
10
  #streamGenerator;
10
11
  #notifier = new Notifier();
11
12
  #filterChannel = Option.None;
12
- #streaming = Option.None;
13
+ #stream = Option.None;
13
14
  constructor(manager, audioUnitBox, captureMidiBox) {
14
15
  super(manager, audioUnitBox, captureMidiBox);
15
16
  this.#streamGenerator = Promises.sequential(() => this.#updateStream());
16
- this.ownAll(captureMidiBox.channel.subscribe(async (owner) => {
17
+ this.ownAll(captureMidiBox.channel.catchupAndSubscribe(async (owner) => {
17
18
  const channel = owner.getValue();
18
19
  this.#filterChannel = channel >= 0 ? Option.wrap(channel) : Option.None;
19
- await this.#streamGenerator();
20
- }), captureMidiBox.deviceId.catchupAndSubscribe(async () => {
20
+ if (this.armed.getValue()) {
21
+ await this.#streamGenerator();
22
+ }
23
+ }), captureMidiBox.deviceId.subscribe(async () => {
21
24
  if (this.armed.getValue()) {
22
25
  await this.#streamGenerator();
23
26
  }
@@ -29,22 +32,27 @@ export class CaptureMidi extends Capture {
29
32
  else {
30
33
  this.#stopStream();
31
34
  }
32
- }), this.#notifier.subscribe(event => {
33
- console.debug(MidiData.debug(event.data));
34
- const data = asDefined(event.data);
35
- const engine = manager.project.engine;
36
- if (MidiData.isNoteOn(data)) {
37
- engine.noteOn(this.uuid, MidiData.readPitch(data), MidiData.readVelocity(data));
38
- }
39
- else if (MidiData.isNoteOff(data)) {
40
- engine.noteOff(this.uuid, MidiData.readPitch(data));
41
- }
42
- }));
35
+ }), this.#notifier.subscribe((signal) => manager.project.engine.noteSignal(signal)));
43
36
  }
37
+ notify(signal) { this.#notifier.notify(signal); }
38
+ subscribeNotes(observer) { return this.#notifier.subscribe(observer); }
44
39
  get label() {
45
40
  return MidiDevices.get().mapOr(midiAccess => this.deviceId.getValue().match({
46
- none: () => this.armed.getValue() ? "Listening to all MIDI devices" : "Arm to listen to MIDI device...",
47
- some: value => `Listening to ${midiAccess.inputs.get(value)?.name}`
41
+ none: () => this.armed.getValue() ? this.#filterChannel.match({
42
+ none: () => `Listening to all devices`,
43
+ some: channel => `Listening to all devices on channel '${channel}'`
44
+ }) : "Arm to listen to MIDI device...",
45
+ some: id => {
46
+ const device = midiAccess.inputs.get(id);
47
+ if (isUndefined(device)) {
48
+ return `⚠️ Could not find device with id '${id}'`;
49
+ }
50
+ const deviceName = device.name ?? "Unknown device";
51
+ return this.#filterChannel.match({
52
+ none: () => `Listening to ${deviceName}`,
53
+ some: channel => `Listening to ${deviceName} on channel '${channel}'`
54
+ });
55
+ }
48
56
  }), "MIDI not available");
49
57
  }
50
58
  get deviceLabel() {
@@ -52,64 +60,76 @@ export class CaptureMidi extends Capture {
52
60
  .flatMap(deviceId => MidiDevices.inputs()
53
61
  .map(inputs => inputs.find(input => input.id === deviceId)?.name));
54
62
  }
55
- async prepareRecording({}) {
56
- const availableMidiDevices = MidiDevices.get();
57
- if (availableMidiDevices.isEmpty()) {
58
- return Promise.reject("MIDI is not available");
63
+ async prepareRecording() {
64
+ if (MidiDevices.get().isEmpty()) {
65
+ if (MidiDevices.canRequestMidiAccess()) {
66
+ await MidiDevices.requestPermission();
67
+ }
68
+ else {
69
+ return warn("MIDI not available");
70
+ }
71
+ }
72
+ const optInputs = MidiDevices.inputs();
73
+ if (optInputs.isEmpty()) {
74
+ return warn("MIDI not available");
75
+ }
76
+ const inputs = optInputs.unwrap();
77
+ if (inputs.length === 0) {
78
+ return;
59
79
  }
60
80
  const option = this.deviceId.getValue();
61
81
  if (option.nonEmpty()) {
62
- const { inputs } = availableMidiDevices.unwrap();
63
- const captureDevices = Array.from(inputs.values());
64
82
  const deviceId = option.unwrap();
65
- if (isUndefined(captureDevices.find(device => deviceId === device.id))) {
83
+ if (isUndefined(inputs.find(device => deviceId === device.id))) {
66
84
  return warn(`Could not find MIDI device with id: '${deviceId}'`);
67
85
  }
68
86
  }
69
87
  }
70
- startRecording({ project }) {
88
+ startRecording() {
71
89
  const availableMidiDevices = MidiDevices.inputs();
72
90
  assert(availableMidiDevices.nonEmpty(), "No MIDI input devices found");
73
- return RecordMidi.start({ notifier: this.#notifier, project, capture: this });
91
+ return RecordMidi.start({ notifier: this.#notifier, project: this.manager.project, capture: this });
74
92
  }
75
93
  async #updateStream() {
76
- // TODO Check if the requirements have been changed (are different than the current stream setup)
77
94
  if (MidiDevices.get().isEmpty()) {
78
95
  await MidiDevices.requestPermission();
79
96
  }
80
97
  const availableMidiDevices = MidiDevices.inputs();
81
- const inputs = availableMidiDevices.unwrap();
82
- const captureDevices = this.deviceId.getValue().match({
83
- none: () => inputs,
84
- some: id => inputs.filter(device => id === device.id)
98
+ const available = availableMidiDevices.unwrap();
99
+ const capturing = this.deviceId.getValue().match({
100
+ none: () => available,
101
+ some: id => available.filter(device => id === device.id)
85
102
  });
86
103
  const activeNotes = new Int8Array(128);
87
- this.#streaming.ifSome(terminable => terminable.terminate());
88
- this.#streaming = Option.wrap(Terminable.many(...captureDevices.map(input => Events.subscribe(input, "midimessage", (event) => {
104
+ this.#stream.ifSome(terminable => terminable.terminate());
105
+ this.#stream = Option.wrap(Terminable.many(...capturing.map(input => Events.subscribe(input, "midimessage", (event) => {
89
106
  const data = event.data;
90
107
  if (isDefined(data) &&
91
108
  this.#filterChannel.mapOr(channel => MidiData.readChannel(data) === channel, true)) {
109
+ const pitch = MidiData.readPitch(data);
92
110
  if (MidiData.isNoteOn(data)) {
93
- activeNotes[MidiData.readPitch(data)]++;
94
- this.#notifier.notify(event);
111
+ activeNotes[pitch]++;
112
+ this.#notifier.notify(NoteSignal.fromEvent(event, this.uuid));
95
113
  }
96
- else if (MidiData.isNoteOff(data)) {
97
- activeNotes[MidiData.readPitch(data)]--;
98
- this.#notifier.notify(event);
114
+ else if (MidiData.isNoteOff(data) && activeNotes[pitch] > 0) {
115
+ activeNotes[pitch]--;
116
+ this.#notifier.notify(NoteSignal.fromEvent(event, this.uuid));
99
117
  }
100
118
  }
101
119
  })), Terminable.create(() => activeNotes.forEach((count, index) => {
102
120
  if (count > 0) {
103
- // TODO respect channel!
104
- const event = new MessageEvent("midimessage", { data: MidiData.noteOff(index, count) });
105
- for (let i = 0; i < count; i++) {
106
- this.#notifier.notify(event);
121
+ for (let channel = 0; channel < 16; channel++) {
122
+ const event = new MessageEvent("midimessage", { data: MidiData.noteOff(channel, index) });
123
+ const signal = NoteSignal.fromEvent(event, this.uuid);
124
+ for (let i = 0; i < count; i++) {
125
+ this.#notifier.notify(signal);
126
+ }
107
127
  }
108
128
  }
109
129
  }))));
110
130
  }
111
131
  #stopStream() {
112
- this.#streaming.ifSome(terminable => terminable.terminate());
113
- this.#streaming = Option.None;
132
+ this.#stream.ifSome(terminable => terminable.terminate());
133
+ this.#stream = Option.None;
114
134
  }
115
135
  }
@@ -1,8 +1,8 @@
1
1
  import { Terminable } from "@opendaw/lib-std";
2
2
  import { SampleManager } from "@opendaw/studio-adapters";
3
- import { Project } from "../Project";
4
- import { Capture } from "./Capture";
3
+ import { Project } from "../project/Project";
5
4
  import { RecordingWorklet } from "../RecordingWorklet";
5
+ import { Capture } from "./Capture";
6
6
  export declare namespace RecordAudio {
7
7
  type RecordAudioContext = {
8
8
  recordingWorklet: RecordingWorklet;
@@ -1 +1 @@
1
- {"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGpF,OAAO,EAAC,aAAa,EAAY,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAEjC,OAAO,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AAGpD,yBAAiB,WAAW,CAAC;IACzB,KAAK,kBAAkB,GAAG;QACtB,gBAAgB,EAAE,gBAAgB,CAAA;QAClC,WAAW,EAAE,WAAW,CAAA;QACxB,aAAa,EAAE,aAAa,CAAA;QAC5B,YAAY,EAAE,YAAY,CAAA;QAC1B,OAAO,EAAE,OAAO,CAAA;QAChB,OAAO,EAAE,OAAO,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;KACjB,CAAA;IAED,MAAM,CAAC,MAAM,KAAK,GACd,0FAEG,kBAAkB,KAAG,UA2D3B,CAAA;;CACJ"}
1
+ {"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGvG,OAAO,EAAC,aAAa,EAAY,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAC1C,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,WAAW,EAAE,WAAW,CAAA;QACxB,aAAa,EAAE,aAAa,CAAA;QAC5B,YAAY,EAAE,YAAY,CAAA;QAC1B,OAAO,EAAE,OAAO,CAAA;QAChB,OAAO,EAAE,OAAO,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;KACjB,CAAA;IAED,MAAM,CAAC,MAAM,KAAK,GACd,0FAAwF,kBAAkB,KACxG,UAqEL,CAAA;;CACJ"}
@@ -1,4 +1,4 @@
1
- import { Option, quantizeFloor, Terminable, Terminator, UUID } from "@opendaw/lib-std";
1
+ import { Option, quantizeCeil, quantizeFloor, Terminable, Terminator, UUID } from "@opendaw/lib-std";
2
2
  import { dbToGain, PPQN } from "@opendaw/lib-dsp";
3
3
  import { AudioFileBox, AudioRegionBox } from "@opendaw/studio-boxes";
4
4
  import { TrackType } from "@opendaw/studio-adapters";
@@ -17,50 +17,64 @@ export var RecordAudio;
17
17
  const streamGain = audioContext.createGain();
18
18
  streamGain.gain.value = dbToGain(gainDb);
19
19
  streamSource.connect(streamGain);
20
- let writing = Option.None;
21
- const resizeRegion = () => {
22
- if (writing.isEmpty()) {
20
+ recordingWorklet.own(Terminable.create(() => {
21
+ streamGain.disconnect();
22
+ streamSource.disconnect();
23
+ }));
24
+ let recordingData = Option.None;
25
+ const createRecordingData = (position) => editing.modify(() => {
26
+ const fileDateString = new Date()
27
+ .toISOString()
28
+ .replaceAll("T", "-")
29
+ .replaceAll(".", "-")
30
+ .replaceAll(":", "-")
31
+ .replaceAll("Z", "");
32
+ const fileName = `Recording-${fileDateString}`;
33
+ const fileBox = AudioFileBox.create(boxGraph, uuid, box => box.fileName.setValue(fileName));
34
+ const regionBox = AudioRegionBox.create(boxGraph, UUID.generate(), box => {
35
+ box.file.refer(fileBox);
36
+ box.regions.refer(trackBox.regions);
37
+ box.position.setValue(position);
38
+ box.hue.setValue(ColorCodes.forTrackType(TrackType.Audio));
39
+ box.label.setValue("Recording");
40
+ });
41
+ return { fileBox, regionBox };
42
+ });
43
+ const { bpm, env: { audioContext: { sampleRate } } } = project;
44
+ terminator.ownAll(Terminable.create(() => {
45
+ if (recordingWorklet.numberOfFrames === 0 || recordingData.isEmpty()) {
46
+ console.debug("Abort recording audio.");
47
+ sampleManager.remove(uuid);
48
+ recordingWorklet.terminate();
49
+ }
50
+ else {
51
+ const { regionBox: { duration } } = recordingData.unwrap("No recording data available");
52
+ recordingWorklet.limit(PPQN.pulsesToSamples(duration.getValue(), bpm, sampleRate) | 0);
53
+ }
54
+ }), engine.position.catchupAndSubscribe(owner => {
55
+ if (!engine.isRecording.getValue()) {
23
56
  return;
24
57
  }
25
- const { regionBox } = writing.unwrap();
58
+ if (recordingData.isEmpty()) {
59
+ streamGain.connect(recordingWorklet);
60
+ recordingData = createRecordingData(quantizeFloor(owner.getValue(), beats));
61
+ }
62
+ const { regionBox } = recordingData.unwrap();
26
63
  editing.modify(() => {
27
64
  if (regionBox.isAttached()) {
28
65
  const { duration, loopDuration } = regionBox;
29
- const newDuration = Math.floor(PPQN.samplesToPulses(recordingWorklet.numberOfFrames, project.timelineBox.bpm.getValue(), audioContext.sampleRate));
66
+ const newDuration = quantizeCeil(engine.position.getValue(), beats) - regionBox.position.getValue();
30
67
  duration.setValue(newDuration);
31
68
  loopDuration.setValue(newDuration);
69
+ const totalSamples = PPQN.pulsesToSamples(newDuration, project.bpm, sampleRate) | 0;
70
+ recordingWorklet.setFillLength(totalSamples);
71
+ }
72
+ else {
73
+ terminator.terminate();
74
+ recordingData = Option.None;
32
75
  }
33
76
  }, false);
34
- };
35
- terminator.ownAll(Terminable.create(() => {
36
- recordingWorklet.finalize().then();
37
- streamGain.disconnect();
38
- streamSource.disconnect();
39
- }), engine.position.catchupAndSubscribe(owner => {
40
- if (writing.isEmpty() && engine.isRecording.getValue()) {
41
- streamGain.connect(recordingWorklet);
42
- writing = editing.modify(() => {
43
- const position = quantizeFloor(owner.getValue(), beats);
44
- const fileDateString = new Date()
45
- .toISOString()
46
- .replaceAll("T", "-")
47
- .replaceAll(".", "-")
48
- .replaceAll(":", "-")
49
- .replaceAll("Z", "");
50
- const fileName = `Recording-${fileDateString}`;
51
- const fileBox = AudioFileBox.create(boxGraph, uuid, box => box.fileName.setValue(fileName));
52
- const regionBox = AudioRegionBox.create(boxGraph, UUID.generate(), box => {
53
- box.file.refer(fileBox);
54
- box.regions.refer(trackBox.regions);
55
- box.position.setValue(position);
56
- box.hue.setValue(ColorCodes.forTrackType(TrackType.Audio));
57
- box.label.setValue("Recording");
58
- });
59
- return { fileBox, regionBox };
60
- });
61
- }
62
- resizeRegion();
63
- }), Terminable.create(() => resizeRegion()));
77
+ }));
64
78
  return terminator;
65
79
  };
66
80
  })(RecordAudio || (RecordAudio = {}));
@@ -1,9 +1,10 @@
1
1
  import { Notifier, Terminable } from "@opendaw/lib-std";
2
- import { Project } from "../Project";
2
+ import { NoteSignal } from "@opendaw/studio-adapters";
3
+ import { Project } from "../project/Project";
3
4
  import { Capture } from "./Capture";
4
5
  export declare namespace RecordMidi {
5
6
  type RecordMidiContext = {
6
- notifier: Notifier<MIDIMessageEvent>;
7
+ notifier: Notifier<NoteSignal>;
7
8
  project: Project;
8
9
  capture: Capture;
9
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"RecordMidi.d.ts","sourceRoot":"","sources":["../../src/capture/RecordMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,QAAQ,EAIR,UAAU,EAGb,MAAM,kBAAkB,CAAA;AAKzB,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAIjC,yBAAiB,UAAU,CAAC;IACxB,KAAK,iBAAiB,GAAG;QACrB,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QACrC,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,OAAO,CAAA;KACnB,CAAA;IAED,MAAM,CAAC,MAAM,KAAK,GAAI,gCAA8B,iBAAiB,KAAG,UAiEvE,CAAA;;CACJ"}
1
+ {"version":3,"file":"RecordMidi.d.ts","sourceRoot":"","sources":["../../src/capture/RecordMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,QAAQ,EAAuC,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGlH,OAAO,EAAC,UAAU,EAAY,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAIjC,yBAAiB,UAAU,CAAC;IACxB,KAAK,iBAAiB,GAAG;QACrB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC/B,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,OAAO,CAAA;KACnB,CAAA;IAED,MAAM,CAAC,MAAM,KAAK,GAAI,gCAA8B,iBAAiB,KAAG,UAiEvE,CAAA;;CACJ"}