@opendaw/studio-core 0.0.18 → 0.0.20

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 (111) hide show
  1. package/dist/AudioInputDevices.d.ts +8 -0
  2. package/dist/AudioInputDevices.d.ts.map +1 -0
  3. package/dist/AudioInputDevices.js +30 -0
  4. package/dist/AudioUnitOrdering.d.ts +3 -0
  5. package/dist/AudioUnitOrdering.d.ts.map +1 -0
  6. package/dist/AudioUnitOrdering.js +7 -0
  7. package/dist/EffectBox.d.ts +2 -2
  8. package/dist/EffectBox.d.ts.map +1 -1
  9. package/dist/Engine.d.ts +31 -10
  10. package/dist/Engine.d.ts.map +1 -1
  11. package/dist/EngineFacade.d.ts +22 -11
  12. package/dist/EngineFacade.d.ts.map +1 -1
  13. package/dist/EngineFacade.js +39 -22
  14. package/dist/EngineWorklet.d.ts +22 -13
  15. package/dist/EngineWorklet.d.ts.map +1 -1
  16. package/dist/EngineWorklet.js +47 -56
  17. package/dist/MeterWorklet.d.ts.map +1 -1
  18. package/dist/MeterWorklet.js +2 -2
  19. package/dist/Project.d.ts +7 -3
  20. package/dist/Project.d.ts.map +1 -1
  21. package/dist/Project.js +22 -4
  22. package/dist/ProjectApi.d.ts +0 -1
  23. package/dist/ProjectApi.d.ts.map +1 -1
  24. package/dist/ProjectApi.js +16 -11
  25. package/dist/ProjectEnv.d.ts +1 -0
  26. package/dist/ProjectEnv.d.ts.map +1 -1
  27. package/dist/ProjectMigration.d.ts.map +1 -1
  28. package/dist/ProjectMigration.js +20 -3
  29. package/dist/RecordingWorklet.d.ts +15 -3
  30. package/dist/RecordingWorklet.d.ts.map +1 -1
  31. package/dist/RecordingWorklet.js +111 -16
  32. package/dist/WorkerAgents.d.ts +2 -2
  33. package/dist/WorkerAgents.d.ts.map +1 -1
  34. package/dist/Worklets.d.ts +1 -1
  35. package/dist/Worklets.d.ts.map +1 -1
  36. package/dist/Worklets.js +2 -2
  37. package/dist/capture/Capture.d.ts +22 -0
  38. package/dist/capture/Capture.d.ts.map +1 -0
  39. package/dist/capture/Capture.js +32 -0
  40. package/dist/capture/CaptureAudio.d.ts +17 -0
  41. package/dist/capture/CaptureAudio.d.ts.map +1 -0
  42. package/dist/capture/CaptureAudio.js +106 -0
  43. package/dist/capture/CaptureManager.d.ts +12 -0
  44. package/dist/capture/CaptureManager.d.ts.map +1 -0
  45. package/dist/capture/CaptureManager.js +38 -0
  46. package/dist/capture/CaptureMidi.d.ts +13 -0
  47. package/dist/capture/CaptureMidi.d.ts.map +1 -0
  48. package/dist/capture/CaptureMidi.js +50 -0
  49. package/dist/capture/RecordAudio.d.ts +21 -0
  50. package/dist/capture/RecordAudio.d.ts.map +1 -0
  51. package/dist/capture/RecordAudio.js +66 -0
  52. package/dist/capture/RecordMidi.d.ts +15 -0
  53. package/dist/capture/RecordMidi.d.ts.map +1 -0
  54. package/dist/capture/RecordMidi.js +85 -0
  55. package/dist/capture/RecordTrack.d.ts +7 -0
  56. package/dist/capture/RecordTrack.d.ts.map +1 -0
  57. package/dist/capture/RecordTrack.js +23 -0
  58. package/dist/capture/Recording.d.ts +9 -0
  59. package/dist/capture/Recording.d.ts.map +1 -0
  60. package/dist/capture/Recording.js +65 -0
  61. package/dist/capture/RecordingContext.d.ts +14 -0
  62. package/dist/capture/RecordingContext.d.ts.map +1 -0
  63. package/dist/capture/RecordingContext.js +1 -0
  64. package/dist/dawproject/AudioUnitExportLayout.d.ts +10 -0
  65. package/dist/dawproject/AudioUnitExportLayout.d.ts.map +1 -0
  66. package/dist/dawproject/AudioUnitExportLayout.js +64 -0
  67. package/dist/dawproject/BuiltinDevices.d.ts +9 -0
  68. package/dist/dawproject/BuiltinDevices.d.ts.map +1 -0
  69. package/dist/dawproject/BuiltinDevices.js +70 -0
  70. package/dist/dawproject/DawProject.d.ts +22 -0
  71. package/dist/dawproject/DawProject.d.ts.map +1 -0
  72. package/dist/dawproject/DawProject.js +49 -0
  73. package/dist/dawproject/DawProjectExporter.d.ts +9 -0
  74. package/dist/dawproject/DawProjectExporter.d.ts.map +1 -0
  75. package/dist/dawproject/DawProjectExporter.js +252 -0
  76. package/dist/dawproject/DawProjectExporter.test.d.ts +2 -0
  77. package/dist/dawproject/DawProjectExporter.test.d.ts.map +1 -0
  78. package/dist/dawproject/DawProjectExporter.test.js +49 -0
  79. package/dist/dawproject/DawProjectImport.d.ts +12 -0
  80. package/dist/dawproject/DawProjectImport.d.ts.map +1 -0
  81. package/dist/dawproject/DawProjectImport.js +389 -0
  82. package/dist/dawproject/DawProjectImport.test.d.ts +2 -0
  83. package/dist/dawproject/DawProjectImport.test.d.ts.map +1 -0
  84. package/dist/dawproject/DawProjectImport.test.js +15 -0
  85. package/dist/dawproject/DeviceIO.d.ts +8 -0
  86. package/dist/dawproject/DeviceIO.d.ts.map +1 -0
  87. package/dist/dawproject/DeviceIO.js +63 -0
  88. package/dist/index.d.ts +12 -2
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +12 -2
  91. package/dist/processors.js +3 -3
  92. package/dist/processors.js.map +4 -4
  93. package/dist/samples/MainThreadSampleLoader.d.ts +1 -0
  94. package/dist/samples/MainThreadSampleLoader.d.ts.map +1 -1
  95. package/dist/samples/MainThreadSampleLoader.js +10 -6
  96. package/dist/samples/MainThreadSampleManager.d.ts +5 -5
  97. package/dist/samples/MainThreadSampleManager.d.ts.map +1 -1
  98. package/dist/samples/MainThreadSampleManager.js +1 -0
  99. package/dist/samples/SampleProvider.d.ts +2 -2
  100. package/dist/samples/SampleProvider.d.ts.map +1 -1
  101. package/dist/samples/SampleStorage.d.ts.map +1 -1
  102. package/dist/samples/SampleStorage.js +2 -3
  103. package/dist/workers.js +2 -2
  104. package/dist/workers.js.map +4 -4
  105. package/package.json +17 -17
  106. package/dist/DawProjectIO.d.ts +0 -7
  107. package/dist/DawProjectIO.d.ts.map +0 -1
  108. package/dist/DawProjectIO.js +0 -73
  109. package/dist/samples/SamplePeaks.d.ts +0 -6
  110. package/dist/samples/SamplePeaks.d.ts.map +0 -1
  111. package/dist/samples/SamplePeaks.js +0 -9
package/dist/Project.js CHANGED
@@ -7,7 +7,7 @@ import { AudioUnitType } from "@opendaw/studio-enums";
7
7
  import { Mixer } from "./Mixer";
8
8
  import { ProjectApi } from "./ProjectApi";
9
9
  import { ProjectMigration } from "./ProjectMigration";
10
- import { DawProjectIO } from "./DawProjectIO";
10
+ import { CaptureManager } from "./capture/CaptureManager";
11
11
  // Main Entry Point for a Project
12
12
  //
13
13
  export class Project {
@@ -54,6 +54,10 @@ export class Project {
54
54
  ProjectMigration.migrate(skeleton);
55
55
  return new Project(env, skeleton.boxGraph, skeleton.mandatoryBoxes);
56
56
  }
57
+ static skeleton(env, skeleton) {
58
+ ProjectMigration.migrate(skeleton);
59
+ return new Project(env, skeleton.boxGraph, skeleton.mandatoryBoxes);
60
+ }
57
61
  #terminator = new Terminator();
58
62
  #env;
59
63
  boxGraph;
@@ -63,6 +67,7 @@ export class Project {
63
67
  masterAudioUnit;
64
68
  timelineBox;
65
69
  api;
70
+ captureManager;
66
71
  editing;
67
72
  selection;
68
73
  boxAdapters;
@@ -78,8 +83,8 @@ export class Project {
78
83
  this.masterBusBox = masterBusBox;
79
84
  this.masterAudioUnit = masterAudioUnit;
80
85
  this.timelineBox = timelineBox;
81
- this.liveStreamReceiver = this.#terminator.own(new LiveStreamReceiver());
82
86
  this.api = new ProjectApi(this);
87
+ this.captureManager = this.#terminator.own(new CaptureManager(this));
83
88
  this.editing = new Editing(this.boxGraph);
84
89
  this.selection = new VertexSelection(this.editing, this.boxGraph);
85
90
  this.parameterFieldAdapters = new ParameterFieldAdapters();
@@ -87,20 +92,34 @@ export class Project {
87
92
  this.userEditingManager = new UserEditingManager(this.editing);
88
93
  this.userEditingManager.follow(this.userInterfaceBox);
89
94
  this.selection.switch(this.userInterfaceBox.selection);
95
+ this.liveStreamReceiver = this.#terminator.own(new LiveStreamReceiver());
90
96
  this.mixer = new Mixer(this.rootBoxAdapter.audioUnits);
91
97
  console.debug(`Project was created on ${this.rootBoxAdapter.created.toString()}`);
92
98
  }
93
99
  own(terminable) { return this.#terminator.own(terminable); }
94
100
  ownAll(...terminables) { return this.#terminator.ownAll(...terminables); }
95
101
  spawn() { return this.#terminator.spawn(); }
102
+ get env() { return this.#env; }
96
103
  get bpm() { return this.timelineBox.bpm.getValue(); }
97
104
  get rootBoxAdapter() { return this.boxAdapters.adapterFor(this.rootBox, RootBoxAdapter); }
98
105
  get timelineBoxAdapter() { return this.boxAdapters.adapterFor(this.timelineBox, TimelineBoxAdapter); }
99
- get audioManager() { return this.#env.sampleManager; }
106
+ get sampleManager() { return this.#env.sampleManager; }
100
107
  get clipSequencing() { return panic("Only available in audio context"); }
101
108
  get isAudioContext() { return false; }
102
109
  get isMainThread() { return true; }
103
110
  get liveStreamBroadcaster() { return panic("Only available in audio context"); }
111
+ get skeleton() {
112
+ return {
113
+ boxGraph: this.boxGraph,
114
+ mandatoryBoxes: {
115
+ rootBox: this.rootBox,
116
+ timelineBox: this.timelineBox,
117
+ masterBusBox: this.masterBusBox,
118
+ masterAudioUnit: this.masterAudioUnit,
119
+ userInterfaceBox: this.userInterfaceBox
120
+ }
121
+ };
122
+ }
104
123
  toArrayBuffer() {
105
124
  const output = ByteArrayOutput.create();
106
125
  output.writeInt(ProjectDecoder.MAGIC_HEADER_OPEN);
@@ -119,5 +138,4 @@ export class Project {
119
138
  }
120
139
  copy() { return Project.load(this.#env, this.toArrayBuffer()); }
121
140
  terminate() { this.#terminator.terminate(); }
122
- toDawProject() { return DawProjectIO.encode(this); }
123
141
  }
@@ -39,7 +39,6 @@ export type NoteRegionParams = {
39
39
  };
40
40
  export declare class ProjectApi {
41
41
  #private;
42
- static readonly AudioUnitOrdering: Record<string, int>;
43
42
  constructor(project: Project);
44
43
  setBpm(value: number): void;
45
44
  catchupAndSubscribeBpm(observer: Observer<number>): Subscription;
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectApi.d.ts","sourceRoot":"","sources":["../src/ProjectApi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ProjectApi.d.ts","sourceRoot":"","sources":["../src/ProjectApi.ts"],"names":[],"mappings":"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"}
@@ -2,17 +2,12 @@ import { asDefined, asInstanceOf, assert, clamp, Option, Strings, UUID } from "@
2
2
  import { PPQN } from "@opendaw/lib-dsp";
3
3
  import { IndexedBox, StringField } from "@opendaw/lib-box";
4
4
  import { AudioUnitType } from "@opendaw/studio-enums";
5
- import { AudioBusBox, AudioUnitBox, NoteClipBox, NoteEventBox, NoteEventCollectionBox, NoteRegionBox, TrackBox, ValueClipBox, ValueEventCollectionBox, ValueRegionBox } from "@opendaw/studio-boxes";
5
+ import { AudioBusBox, AudioUnitBox, CaptureAudioBox, CaptureMidiBox, NoteClipBox, NoteEventBox, NoteEventCollectionBox, NoteRegionBox, TrackBox, ValueClipBox, ValueEventCollectionBox, ValueRegionBox } from "@opendaw/studio-boxes";
6
6
  import { IconSymbol, TrackType } from "@opendaw/studio-adapters";
7
7
  import { ColorCodes } from "./ColorCodes";
8
+ import { AudioUnitOrdering } from "./AudioUnitOrdering";
8
9
  // noinspection JSUnusedGlobalSymbols
9
10
  export class ProjectApi {
10
- static AudioUnitOrdering = {
11
- [AudioUnitType.Instrument]: 0,
12
- [AudioUnitType.Aux]: 1,
13
- [AudioUnitType.Bus]: 2,
14
- [AudioUnitType.Output]: 3
15
- };
16
11
  #project;
17
12
  constructor(project) { this.#project = project; }
18
13
  setBpm(value) {
@@ -34,7 +29,7 @@ export class ProjectApi {
34
29
  const inputBox = asDefined(asInstanceOf(box, AudioUnitBox).input.pointerHub.incoming().at(0)).box;
35
30
  return "label" in inputBox && inputBox.label instanceof StringField ? inputBox.label.getValue() : "N/A";
36
31
  });
37
- const audioUnitBox = this.#createAudioUnit(AudioUnitType.Instrument, index);
32
+ const audioUnitBox = this.#createAudioUnit(AudioUnitType.Instrument, this.#trackTypeToCapture(boxGraph, trackType), index);
38
33
  const uniqueName = Strings.getUniqueName(existingNames, name ?? defaultName);
39
34
  const iconSymbol = icon ?? defaultIcon;
40
35
  const instrumentBox = create(boxGraph, audioUnitBox.input, uniqueName, iconSymbol);
@@ -58,7 +53,7 @@ export class ProjectApi {
58
53
  box.icon.setValue(IconSymbol.toName(icon));
59
54
  box.color.setValue(color);
60
55
  });
61
- const audioUnitBox = this.#createAudioUnit(type);
56
+ const audioUnitBox = this.#createAudioUnit(type, Option.None);
62
57
  TrackBox.create(boxGraph, UUID.generate(), box => {
63
58
  box.tracks.refer(audioUnitBox.tracks);
64
59
  box.target.refer(audioUnitBox);
@@ -182,7 +177,7 @@ export class ProjectApi {
182
177
  IndexedBox.removeOrder(rootBox.audioUnits, audioUnitBox.index.getValue());
183
178
  audioUnitBox.delete();
184
179
  }
185
- #createAudioUnit(type, index) {
180
+ #createAudioUnit(type, capture, index) {
186
181
  const { boxGraph, rootBox, masterBusBox } = this.#project;
187
182
  const insertIndex = index ?? this.#sortAudioUnitOrdering(type);
188
183
  console.debug(`createAudioUnit type: ${type}, insertIndex: ${insertIndex}`);
@@ -191,6 +186,7 @@ export class ProjectApi {
191
186
  box.output.refer(masterBusBox.input);
192
187
  box.index.setValue(insertIndex);
193
188
  box.type.setValue(type);
189
+ capture.ifSome(capture => box.capture.refer(capture));
194
190
  });
195
191
  }
196
192
  #createTrack({ field, target, trackType, insertIndex }) {
@@ -203,7 +199,6 @@ export class ProjectApi {
203
199
  });
204
200
  }
205
201
  #sortAudioUnitOrdering(type) {
206
- const { AudioUnitOrdering } = ProjectApi;
207
202
  const { rootBox } = this.#project;
208
203
  const boxes = IndexedBox.collectIndexedBoxes(rootBox.audioUnits, AudioUnitBox);
209
204
  const order = AudioUnitOrdering[type];
@@ -219,4 +214,14 @@ export class ProjectApi {
219
214
  }
220
215
  return insertIndex;
221
216
  }
217
+ #trackTypeToCapture(boxGraph, trackType) {
218
+ switch (trackType) {
219
+ case TrackType.Audio:
220
+ return Option.wrap(CaptureAudioBox.create(boxGraph, UUID.generate()));
221
+ case TrackType.Notes:
222
+ return Option.wrap(CaptureMidiBox.create(boxGraph, UUID.generate()));
223
+ default:
224
+ return Option.None;
225
+ }
226
+ }
222
227
  }
@@ -1,5 +1,6 @@
1
1
  import { SampleManager } from "@opendaw/studio-adapters";
2
2
  export interface ProjectEnv {
3
+ sampleRate: number;
3
4
  sampleManager: SampleManager;
4
5
  }
5
6
  //# sourceMappingURL=ProjectEnv.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectEnv.d.ts","sourceRoot":"","sources":["../src/ProjectEnv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,0BAA0B,CAAA;AAEtD,MAAM,WAAW,UAAU;IACvB,aAAa,EAAE,aAAa,CAAA;CAC/B"}
1
+ {"version":3,"file":"ProjectEnv.d.ts","sourceRoot":"","sources":["../src/ProjectEnv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,0BAA0B,CAAA;AAEtD,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,aAAa,CAAA;CAC/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectMigration.d.ts","sourceRoot":"","sources":["../src/ProjectMigration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAUvD,qBAAa,gBAAgB;IACzB,MAAM,CAAC,OAAO,CAAC,EAAC,QAAQ,EAAE,cAAc,EAAC,EAAE,cAAc,CAAC,QAAQ,GAAG,IAAI;CAoD5E"}
1
+ {"version":3,"file":"ProjectMigration.d.ts","sourceRoot":"","sources":["../src/ProjectMigration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAevD,qBAAa,gBAAgB;IACzB,MAAM,CAAC,OAAO,CAAC,EAAC,QAAQ,EAAE,cAAc,EAAC,EAAE,cAAc,CAAC,QAAQ,GAAG,IAAI;CAoE5E"}
@@ -1,5 +1,6 @@
1
- import { GrooveShuffleBox, ValueEventCurveBox } from "@opendaw/studio-boxes";
2
- import { asInstanceOf, UUID } from "@opendaw/lib-std";
1
+ import { CaptureAudioBox, CaptureMidiBox, GrooveShuffleBox, ValueEventCurveBox } from "@opendaw/studio-boxes";
2
+ import { asDefined, asInstanceOf, UUID } from "@opendaw/lib-std";
3
+ import { AudioUnitType } from "@opendaw/studio-enums";
3
4
  export class ProjectMigration {
4
5
  static migrate({ boxGraph, mandatoryBoxes }) {
5
6
  const { rootBox } = mandatoryBoxes;
@@ -16,7 +17,8 @@ export class ProjectMigration {
16
17
  boxGraph.endTransaction();
17
18
  }
18
19
  // TODO We can remove this when we delete all not-migrated, local(!) project files from my machine
19
- boxGraph.boxes().forEach(box => box.accept({
20
+ // We need to run on a copy, because we might add more boxes during the migration
21
+ boxGraph.boxes().slice().forEach(box => box.accept({
20
22
  visitZeitgeistDeviceBox: (box) => {
21
23
  if (box.groove.targetAddress.isEmpty()) {
22
24
  console.debug("Migrate 'ZeitgeistDeviceBox' to GrooveShuffleBox");
@@ -54,6 +56,21 @@ export class ProjectMigration {
54
56
  boxGraph.endTransaction();
55
57
  }
56
58
  }
59
+ },
60
+ visitAudioUnitBox: (box) => {
61
+ if (box.type.getValue() !== AudioUnitType.Instrument || box.capture.nonEmpty()) {
62
+ return;
63
+ }
64
+ boxGraph.beginTransaction();
65
+ const captureBox = asDefined(box.input.pointerHub.incoming().at(0)?.box
66
+ .accept({
67
+ visitVaporisateurDeviceBox: () => CaptureMidiBox.create(boxGraph, UUID.generate()),
68
+ visitNanoDeviceBox: () => CaptureMidiBox.create(boxGraph, UUID.generate()),
69
+ visitPlayfieldDeviceBox: () => CaptureMidiBox.create(boxGraph, UUID.generate()),
70
+ visitTapeDeviceBox: () => CaptureAudioBox.create(boxGraph, UUID.generate())
71
+ }));
72
+ box.capture.refer(captureBox);
73
+ boxGraph.endTransaction();
57
74
  }
58
75
  }));
59
76
  }
@@ -1,6 +1,18 @@
1
- import { RingBuffer } from "@opendaw/studio-adapters";
2
- export declare class RecordingWorklet extends AudioWorkletNode {
1
+ import { int, Observer, Option, Subscription, Terminable, UUID } from "@opendaw/lib-std";
2
+ import { AudioData, RingBuffer, SampleLoader, SampleLoaderState } from "@opendaw/studio-adapters";
3
+ import { Peaks } from "@opendaw/lib-fusion";
4
+ export declare class RecordingWorklet extends AudioWorkletNode implements Terminable, SampleLoader {
3
5
  #private;
4
- constructor(context: BaseAudioContext, config: RingBuffer.Config);
6
+ readonly uuid: UUID.Format;
7
+ constructor(context: BaseAudioContext, config: RingBuffer.Config, outputLatency: number);
8
+ get numberOfFrames(): int;
9
+ get data(): Option<AudioData>;
10
+ get peaks(): Option<Peaks>;
11
+ get state(): SampleLoaderState;
12
+ invalidate(): void;
13
+ subscribe(observer: Observer<SampleLoaderState>): Subscription;
14
+ finalize(): Promise<void>;
15
+ terminate(): void;
16
+ toString(): string;
5
17
  }
6
18
  //# sourceMappingURL=RecordingWorklet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RecordingWorklet.d.ts","sourceRoot":"","sources":["../src/RecordingWorklet.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,UAAU,EAAC,MAAM,0BAA0B,CAAA;AAIrE,qBAAa,gBAAiB,SAAQ,gBAAgB;;gBAGtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM;CAuBnE"}
1
+ {"version":3,"file":"RecordingWorklet.d.ts","sourceRoot":"","sources":["../src/RecordingWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,GAAG,EAIH,QAAQ,EACR,MAAM,EAEN,YAAY,EACZ,UAAU,EACV,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACH,SAAS,EAET,UAAU,EACV,YAAY,EACZ,iBAAiB,EAEpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,KAAK,EAAgC,MAAM,qBAAqB,CAAA;AA2CxE,qBAAa,gBAAiB,SAAQ,gBAAiB,YAAW,UAAU,EAAE,YAAY;;IACtF,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAkB;gBAahC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM;IAgCvF,IAAI,cAAc,IAAI,GAAG,CAA6C;IACtE,IAAI,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAoB;IACjD,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAqB;IAC/C,IAAI,KAAK,IAAI,iBAAiB,CAAqB;IAEnD,UAAU,IAAI,IAAI;IAElB,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,YAAY;IAQxD,QAAQ;IAyBd,SAAS,IAAI,IAAI;IAKjB,QAAQ,IAAI,MAAM;CAMrB"}
@@ -1,31 +1,126 @@
1
- import { EmptyExec } from "@opendaw/lib-std";
2
- import { Files } from "@opendaw/lib-dom";
1
+ import { Arrays, assert, ByteArrayInput, isUndefined, Notifier, Option, Progress, Terminable, UUID } from "@opendaw/lib-std";
3
2
  import { mergeChunkPlanes, RingBuffer } from "@opendaw/studio-adapters";
4
- import { encodeWavFloat } from "./Wav";
3
+ import { SamplePeaks, SamplePeakWorker } from "@opendaw/lib-fusion";
5
4
  import { RenderQuantum } from "./RenderQuantum";
5
+ import { WorkerAgents } from "./WorkerAgents";
6
+ import { SampleStorage } from "./samples/SampleStorage";
7
+ import { BPMTools } from "@opendaw/lib-dsp";
8
+ class PeaksWriter {
9
+ numChannels;
10
+ data;
11
+ stages;
12
+ dataOffset = 0;
13
+ shift = 7;
14
+ dataIndex;
15
+ numFrames = 0 | 0;
16
+ constructor(numChannels) {
17
+ this.numChannels = numChannels;
18
+ this.data = Arrays.create(() => new Int32Array(1 << 20), numChannels); // TODO auto-resize
19
+ this.dataIndex = new Int32Array(numChannels);
20
+ this.stages = [this];
21
+ }
22
+ get numPeaks() { return Math.ceil(this.numFrames / (1 << this.shift)); }
23
+ unitsEachPeak() { return 1 << this.shift; }
24
+ append(frames) {
25
+ for (let channel = 0; channel < this.numChannels; ++channel) {
26
+ const channelFrames = frames[channel];
27
+ assert(channelFrames.length === RenderQuantum, "Invalid number of frames.");
28
+ let min = Number.POSITIVE_INFINITY;
29
+ let max = Number.NEGATIVE_INFINITY;
30
+ for (let i = 0; i < RenderQuantum; ++i) {
31
+ const frame = channelFrames[i];
32
+ min = Math.min(frame, min);
33
+ max = Math.max(frame, max);
34
+ }
35
+ this.data[channel][this.dataIndex[channel]++] = SamplePeakWorker.pack(min, max);
36
+ }
37
+ this.numFrames += RenderQuantum;
38
+ }
39
+ nearest(_unitsPerPixel) { return this.stages.at(0) ?? null; }
40
+ }
6
41
  export class RecordingWorklet extends AudioWorkletNode {
42
+ uuid = UUID.generate();
43
+ #output;
44
+ #notifier;
7
45
  #reader;
8
- constructor(context, config) {
46
+ #peakWriter;
47
+ #data = Option.None;
48
+ #peaks = Option.None;
49
+ #isRecording = true;
50
+ #truncateLatency;
51
+ #state = { type: "record" };
52
+ constructor(context, config, outputLatency) {
9
53
  super(context, "recording-processor", {
10
54
  numberOfInputs: 1,
11
55
  channelCount: config.numberOfChannels,
12
56
  channelCountMode: "explicit",
13
57
  processorOptions: config
14
58
  });
15
- const sampleRate = this.context.sampleRate;
16
- const output = [];
17
- const seconds = 3.1452;
18
- const numFrames = Math.ceil(sampleRate * seconds);
19
- console.debug(`numFrames: ${numFrames}`);
59
+ if (isUndefined(outputLatency)) {
60
+ // TODO Talk to the user
61
+ console.warn("outputLatency is undefined. Please use Chrome.");
62
+ }
63
+ this.#peakWriter = new PeaksWriter(config.numberOfChannels);
64
+ this.#truncateLatency = Math.floor((outputLatency ?? 0) * this.context.sampleRate / RenderQuantum);
65
+ this.#output = [];
66
+ this.#notifier = new Notifier();
20
67
  this.#reader = RingBuffer.reader(config, array => {
21
- output.push(array);
22
- if (output.length * RenderQuantum >= numFrames) {
23
- this.#reader.stop();
24
- const channels = mergeChunkPlanes(output, numFrames);
25
- const wav = encodeWavFloat({ channels, numFrames, sampleRate });
26
- Files.save(wav, { suggestedName: "recording.wav" })
27
- .then(() => console.debug("WAV saved"), EmptyExec);
68
+ if (this.#isRecording) {
69
+ if (this.#truncateLatency === 0) {
70
+ this.#output.push(array);
71
+ this.#peakWriter.append(array);
72
+ }
73
+ else {
74
+ if (--this.#truncateLatency === 0) {
75
+ this.#peaks = Option.wrap(this.#peakWriter);
76
+ }
77
+ }
28
78
  }
29
79
  });
30
80
  }
81
+ get numberOfFrames() { return this.#output.length * RenderQuantum; }
82
+ get data() { return this.#data; }
83
+ get peaks() { return this.#peaks; }
84
+ get state() { return this.#state; }
85
+ invalidate() { }
86
+ subscribe(observer) {
87
+ if (this.#state.type === "loaded") {
88
+ observer(this.#state);
89
+ return Terminable.Empty;
90
+ }
91
+ return this.#notifier.subscribe(observer);
92
+ }
93
+ async finalize() {
94
+ this.#reader.stop();
95
+ this.#isRecording = false;
96
+ const sample_rate = this.context.sampleRate;
97
+ const numberOfFrames = this.#output.length * RenderQuantum;
98
+ const numberOfChannels = this.channelCount;
99
+ const frames = mergeChunkPlanes(this.#output, RenderQuantum, numberOfFrames);
100
+ const audioData = {
101
+ sampleRate: sample_rate,
102
+ numberOfChannels,
103
+ numberOfFrames,
104
+ frames
105
+ };
106
+ this.#data = Option.wrap(audioData);
107
+ const shifts = SamplePeaks.findBestFit(numberOfFrames);
108
+ const peaks = await WorkerAgents
109
+ .Peak.generateAsync(Progress.Empty, shifts, frames, numberOfFrames, numberOfChannels);
110
+ this.#peaks = Option.wrap(SamplePeaks.from(new ByteArrayInput(peaks)));
111
+ const bpm = BPMTools.detect(frames[0], sample_rate);
112
+ const duration = numberOfFrames / sample_rate;
113
+ const meta = { name: "Recording", bpm, sample_rate, duration };
114
+ await SampleStorage.store(this.uuid, audioData, peaks, meta);
115
+ this.#setState({ type: "loaded" });
116
+ }
117
+ terminate() {
118
+ this.#reader.stop();
119
+ this.#isRecording = false;
120
+ }
121
+ toString() { return `{RecordingWorklet}`; }
122
+ #setState(value) {
123
+ this.#state = value;
124
+ this.#notifier.notify(this.#state);
125
+ }
31
126
  }
@@ -1,10 +1,10 @@
1
1
  import { Option } from "@opendaw/lib-std";
2
- import type { OpfsProtocol, PeakProtocol } from "@opendaw/lib-fusion";
2
+ import type { OpfsProtocol, SamplePeakProtocol } from "@opendaw/lib-fusion";
3
3
  import { Messenger } from "@opendaw/lib-runtime";
4
4
  export declare class WorkerAgents {
5
5
  static install(workerURL: string): void;
6
6
  static messenger: Option<Messenger>;
7
- static get Peak(): PeakProtocol;
7
+ static get Peak(): SamplePeakProtocol;
8
8
  static get Opfs(): OpfsProtocol;
9
9
  }
10
10
  //# sourceMappingURL=WorkerAgents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WorkerAgents.d.ts","sourceRoot":"","sources":["../src/WorkerAgents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,MAAM,EAAY,MAAM,kBAAkB,CAAA;AACzE,OAAO,KAAK,EAAC,YAAY,EAAE,YAAY,EAAC,MAAM,qBAAqB,CAAA;AAEnE,OAAO,EAAe,SAAS,EAAC,MAAM,sBAAsB,CAAA;AAE5D,qBAAa,YAAY;IACrB,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKvC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAc;IAGjD,MAAM,KAAK,IAAI,IAAI,YAAY,CAa9B;IAGD,MAAM,KAAK,IAAI,IAAI,YAAY,CAS9B;CACJ"}
1
+ {"version":3,"file":"WorkerAgents.d.ts","sourceRoot":"","sources":["../src/WorkerAgents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,MAAM,EAAY,MAAM,kBAAkB,CAAA;AACzE,OAAO,KAAK,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AAEzE,OAAO,EAAe,SAAS,EAAC,MAAM,sBAAsB,CAAA;AAE5D,qBAAa,YAAY;IACrB,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKvC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAc;IAGjD,MAAM,KAAK,IAAI,IAAI,kBAAkB,CAapC;IAGD,MAAM,KAAK,IAAI,IAAI,YAAY,CAS9B;CACJ"}
@@ -11,6 +11,6 @@ export declare class Worklets {
11
11
  constructor(context: BaseAudioContext);
12
12
  createMeter(numberOfChannels: int): MeterWorklet;
13
13
  createEngine(project: Project, exportConfiguration?: ExportStemsConfiguration): EngineWorklet;
14
- createRecording(numberOfChannels: int, numChunks: int): RecordingWorklet;
14
+ createRecording(numberOfChannels: int, numChunks: int, outputLatency: number): RecordingWorklet;
15
15
  }
16
16
  //# sourceMappingURL=Worklets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Worklets.d.ts","sourceRoot":"","sources":["../src/Worklets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,wBAAwB,EAAa,MAAM,0BAA0B,CAAA;AAC7E,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAGjC,qBAAa,QAAQ;;WACJ,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAQtF,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,gBAAgB,GAAG,QAAQ;gBAMnC,OAAO,EAAE,gBAAgB;IAErC,WAAW,CAAC,gBAAgB,EAAE,GAAG,GAAG,YAAY;IAIhD,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,CAAC,EAAE,wBAAwB,GAAG,aAAa;IAI7F,eAAe,CAAC,gBAAgB,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,GAAG,gBAAgB;CAO3E"}
1
+ {"version":3,"file":"Worklets.d.ts","sourceRoot":"","sources":["../src/Worklets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,wBAAwB,EAAa,MAAM,0BAA0B,CAAA;AAC7E,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAGjC,qBAAa,QAAQ;;WACJ,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAQtF,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,gBAAgB,GAAG,QAAQ;gBAMnC,OAAO,EAAE,gBAAgB;IAErC,WAAW,CAAC,gBAAgB,EAAE,GAAG,GAAG,YAAY;IAIhD,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,CAAC,EAAE,wBAAwB,GAAG,aAAa;IAI7F,eAAe,CAAC,gBAAgB,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,GAAG,gBAAgB;CAOlG"}
package/dist/Worklets.js CHANGED
@@ -21,11 +21,11 @@ export class Worklets {
21
21
  createEngine(project, exportConfiguration) {
22
22
  return new EngineWorklet(this.#context, project, exportConfiguration);
23
23
  }
24
- createRecording(numberOfChannels, numChunks) {
24
+ createRecording(numberOfChannels, numChunks, outputLatency) {
25
25
  const audioBytes = numberOfChannels * numChunks * RenderQuantum * Float32Array.BYTES_PER_ELEMENT;
26
26
  const pointerBytes = Int32Array.BYTES_PER_ELEMENT * 2;
27
27
  const sab = new SharedArrayBuffer(audioBytes + pointerBytes);
28
28
  const buffer = { sab, numChunks, numberOfChannels, bufferSize: RenderQuantum };
29
- return new RecordingWorklet(this.#context, buffer);
29
+ return new RecordingWorklet(this.#context, buffer, outputLatency);
30
30
  }
31
31
  }
@@ -0,0 +1,22 @@
1
+ import { MutableObservableValue, Option, Terminable, UUID } from "@opendaw/lib-std";
2
+ import { AudioUnitBox } from "@opendaw/studio-boxes";
3
+ import { CaptureBox } from "@opendaw/studio-adapters";
4
+ import { RecordingContext } from "./RecordingContext";
5
+ import { CaptureManager } from "./CaptureManager";
6
+ export declare abstract class Capture<BOX extends CaptureBox = CaptureBox> implements Terminable {
7
+ #private;
8
+ protected constructor(manager: CaptureManager, audioUnitBox: AudioUnitBox, captureBox: BOX);
9
+ abstract prepareRecording(context: RecordingContext): Promise<void>;
10
+ abstract startRecording(context: RecordingContext): Terminable;
11
+ abstract get deviceLabel(): Option<string>;
12
+ get uuid(): UUID.Format;
13
+ get manager(): CaptureManager;
14
+ get audioUnitBox(): AudioUnitBox;
15
+ get captureBox(): BOX;
16
+ get armed(): MutableObservableValue<boolean>;
17
+ get deviceId(): MutableObservableValue<Option<string>>;
18
+ own<T extends Terminable>(terminable: T): T;
19
+ ownAll<T extends Terminable>(...terminables: ReadonlyArray<T>): void;
20
+ terminate(): void;
21
+ }
22
+ //# sourceMappingURL=Capture.d.ts.map
@@ -0,0 +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,CAAC,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IACnE,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU;IAC9D,QAAQ,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;IAE1C,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"}
@@ -0,0 +1,32 @@
1
+ import { DefaultObservableValue, MappedMutableObservableValue, Option, Terminator } from "@opendaw/lib-std";
2
+ export class Capture {
3
+ #terminator = new Terminator();
4
+ #manager;
5
+ #audioUnitBox;
6
+ #captureBox;
7
+ #deviceId;
8
+ #armed;
9
+ constructor(manager, audioUnitBox, captureBox) {
10
+ this.#manager = manager;
11
+ this.#audioUnitBox = audioUnitBox;
12
+ this.#captureBox = captureBox;
13
+ this.#deviceId = new MappedMutableObservableValue(captureBox.deviceId, {
14
+ fx: x => x.length > 0 ? Option.wrap(x) : Option.None,
15
+ fy: y => y.match({ none: () => "", some: x => x })
16
+ });
17
+ this.#armed = this.#terminator.own(new DefaultObservableValue(false));
18
+ this.#terminator.ownAll(this.#captureBox.deviceId.catchupAndSubscribe(owner => {
19
+ const id = owner.getValue();
20
+ this.#deviceId.setValue(id.length > 0 ? Option.wrap(id) : Option.None);
21
+ }));
22
+ }
23
+ get uuid() { return this.#audioUnitBox.address.uuid; }
24
+ get manager() { return this.#manager; }
25
+ get audioUnitBox() { return this.#audioUnitBox; }
26
+ get captureBox() { return this.#captureBox; }
27
+ get armed() { return this.#armed; }
28
+ get deviceId() { return this.#deviceId; }
29
+ own(terminable) { return this.#terminator.own(terminable); }
30
+ ownAll(...terminables) { this.#terminator.ownAll(...terminables); }
31
+ terminate() { this.#terminator.terminate(); }
32
+ }
@@ -0,0 +1,17 @@
1
+ import { ObservableOption, Option, Terminable } from "@opendaw/lib-std";
2
+ import { AudioUnitBox, CaptureAudioBox } from "@opendaw/studio-boxes";
3
+ import { Capture } from "./Capture";
4
+ import { RecordingContext } from "./RecordingContext";
5
+ import { CaptureManager } from "./CaptureManager";
6
+ export declare class CaptureAudio extends Capture<CaptureAudioBox> {
7
+ #private;
8
+ constructor(manager: CaptureManager, audioUnitBox: AudioUnitBox, captureBox: CaptureAudioBox);
9
+ get gainDb(): number;
10
+ get stream(): ObservableOption<MediaStream>;
11
+ get streamDeviceId(): Option<string>;
12
+ get deviceLabel(): Option<string>;
13
+ get streamMediaTrack(): Option<MediaStreamTrack>;
14
+ prepareRecording({}: RecordingContext): Promise<void>;
15
+ startRecording({ audioContext, worklets, project, engine, sampleManager }: RecordingContext): Terminable;
16
+ }
17
+ //# sourceMappingURL=CaptureAudio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CaptureAudio.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAO,MAAM,kBAAkB,CAAA;AACjH,OAAO,EAAC,YAAY,EAAE,eAAe,EAAC,MAAM,uBAAuB,CAAA;AACnE,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,YAAa,SAAQ,OAAO,CAAC,eAAe,CAAC;;gBAQ1C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe;IA4B5F,IAAI,MAAM,IAAI,MAAM,CAAsB;IAE1C,IAAI,MAAM,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAsB;IAEjE,IAAI,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,CAEnC;IAED,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAEhC;IAED,IAAI,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAE/C;IAEK,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D,cAAc,CAAC,EAAC,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAC,EAAE,gBAAgB,GAAG,UAAU;CA6DzG"}