@opendaw/studio-core 0.0.102 → 0.0.104
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.
- package/dist/OfflineEngineRenderer.d.ts +3 -1
- package/dist/OfflineEngineRenderer.d.ts.map +1 -1
- package/dist/OfflineEngineRenderer.js +10 -2
- package/dist/capture/CaptureMidi.js +1 -1
- package/dist/capture/RecordAutomation.d.ts +6 -0
- package/dist/capture/RecordAutomation.d.ts.map +1 -0
- package/dist/capture/RecordAutomation.js +252 -0
- package/dist/capture/Recording.d.ts +3 -0
- package/dist/capture/Recording.d.ts.map +1 -1
- package/dist/capture/Recording.js +16 -36
- package/dist/capture/index.d.ts +1 -0
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +1 -0
- package/dist/offline-engine.js +1 -1
- package/dist/offline-engine.js.map +4 -4
- package/dist/processors.js +17 -17
- package/dist/processors.js.map +3 -3
- package/dist/project/Project.d.ts +1 -0
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +7 -5
- package/dist/project/ProjectApi.d.ts +5 -2
- package/dist/project/ProjectApi.d.ts.map +1 -1
- package/dist/project/ProjectApi.js +37 -17
- package/dist/ui/clipboard/ClipboardManager.d.ts.map +1 -1
- package/dist/ui/clipboard/ClipboardManager.js +34 -2
- package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.d.ts.map +1 -1
- package/dist/ui/clipboard/types/AudioUnitsClipboardHandler.js +6 -0
- package/dist/ui/clipboard/types/RegionsClipboardHandler.d.ts.map +1 -1
- package/dist/ui/clipboard/types/RegionsClipboardHandler.js +4 -0
- package/dist/ui/menu/MenuItems.d.ts +2 -2
- package/dist/ui/menu/MenuItems.d.ts.map +1 -1
- package/dist/ui/timeline/RegionClipResolver.d.ts +2 -2
- package/dist/ui/timeline/RegionClipResolver.d.ts.map +1 -1
- package/dist/ui/timeline/RegionClipResolver.js +40 -37
- package/dist/ui/timeline/RegionClipResolver.test.js +400 -0
- package/dist/ysync/YService.d.ts.map +1 -1
- package/dist/ysync/YService.js +1 -2
- package/package.json +15 -15
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { int, Option, Progress } from "@opendaw/lib-std";
|
|
2
|
-
import { AudioData } from "@opendaw/lib-dsp";
|
|
2
|
+
import { AudioData, ppqn } from "@opendaw/lib-dsp";
|
|
3
3
|
import { ExportStemsConfiguration, OfflineEngineRenderConfig } from "@opendaw/studio-adapters";
|
|
4
4
|
import { Project } from "./project";
|
|
5
5
|
export declare class OfflineEngineRenderer {
|
|
@@ -14,6 +14,8 @@ export declare class OfflineEngineRenderer {
|
|
|
14
14
|
get totalFrames(): int;
|
|
15
15
|
play(): void;
|
|
16
16
|
stop(): void;
|
|
17
|
+
setPosition(position: ppqn): void;
|
|
18
|
+
waitForLoading(): Promise<void>;
|
|
17
19
|
terminate(): void;
|
|
18
20
|
step(samples: int): Promise<Float32Array[]>;
|
|
19
21
|
render(config: OfflineEngineRenderConfig, progress: Progress.Handler, abortSignal?: AbortSignal): Promise<AudioData>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OfflineEngineRenderer.d.ts","sourceRoot":"","sources":["../src/OfflineEngineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,GAAG,EAAa,MAAM,EAAS,QAAQ,EAA6B,MAAM,kBAAkB,CAAA;AAC5G,OAAO,EAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"OfflineEngineRenderer.d.ts","sourceRoot":"","sources":["../src/OfflineEngineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,GAAG,EAAa,MAAM,EAAS,QAAQ,EAA6B,MAAM,kBAAkB,CAAA;AAC5G,OAAO,EAAC,SAAS,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAEhD,OAAO,EAIH,wBAAwB,EAKxB,yBAAyB,EAC5B,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAOjC,qBAAa,qBAAqB;;IAC9B,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKjC,MAAM,CAAC,YAAY,IAAI,MAAM;WAIhB,MAAM,CAAC,MAAM,EAAE,OAAO,EACf,sBAAsB,EAAE,MAAM,CAAC,wBAAwB,CAAC,EACxD,UAAU,GAAE,GAAY,GACzC,OAAO,CAAC,qBAAqB,CAAC;WAoHpB,KAAK,CAAC,MAAM,EAAE,OAAO,EACf,sBAAsB,EAAE,MAAM,CAAC,wBAAwB,CAAC,EACxD,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,GAAE,GAAY,GACxC,OAAO,CAAC,SAAS,CAAC;IAwBrB,OAAO;IAkBP,IAAI,UAAU,IAAI,GAAG,CAA0B;IAC/C,IAAI,gBAAgB,IAAI,GAAG,CAAgC;IAC3D,IAAI,WAAW,IAAI,GAAG,CAA2B;IAEjD,IAAI,IAAI,IAAI;IAIZ,IAAI,IAAI,IAAI;IAKZ,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IAI3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrC,SAAS,IAAI,IAAI;IAKX,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM3C,MAAM,CACR,MAAM,EAAE,yBAAyB,EACjC,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,WAAW,CAAC,EAAE,WAAW,GAC1B,OAAO,CAAC,SAAS,CAAC;CAqCxB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Errors, isDefined, Option, panic, Terminator, TimeSpan } from "@opendaw/lib-std";
|
|
2
2
|
import { AudioData } from "@opendaw/lib-dsp";
|
|
3
3
|
import { Communicator, Messenger, Wait } from "@opendaw/lib-runtime";
|
|
4
|
-
import { ExportStemsConfiguration } from "@opendaw/studio-adapters";
|
|
4
|
+
import { EngineStateSchema, ExportStemsConfiguration } from "@opendaw/studio-adapters";
|
|
5
5
|
import { AudioWorklets } from "./AudioWorklets";
|
|
6
6
|
import { MIDIReceiver } from "./midi";
|
|
7
7
|
let workerUrl = Option.None;
|
|
@@ -35,7 +35,7 @@ export class OfflineEngineRenderer {
|
|
|
35
35
|
});
|
|
36
36
|
const channel = new MessageChannel();
|
|
37
37
|
const progressChannel = new MessageChannel();
|
|
38
|
-
const syncStreamBuffer = new SharedArrayBuffer(
|
|
38
|
+
const syncStreamBuffer = new SharedArrayBuffer(EngineStateSchema().bytesTotal + 1);
|
|
39
39
|
const controlFlagsBuffer = new SharedArrayBuffer(4);
|
|
40
40
|
const terminator = new Terminator();
|
|
41
41
|
const engineMessenger = Messenger.for(channel.port2);
|
|
@@ -150,6 +150,14 @@ export class OfflineEngineRenderer {
|
|
|
150
150
|
this.#engineCommands.stop(true);
|
|
151
151
|
this.#protocol.stop();
|
|
152
152
|
}
|
|
153
|
+
setPosition(position) {
|
|
154
|
+
this.#engineCommands.setPosition(position);
|
|
155
|
+
}
|
|
156
|
+
async waitForLoading() {
|
|
157
|
+
while (!await this.#engineCommands.queryLoadingComplete()) {
|
|
158
|
+
await Wait.timeSpan(TimeSpan.millis(100));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
153
161
|
terminate() {
|
|
154
162
|
this.#terminator.terminate();
|
|
155
163
|
this.#worker.terminate();
|
|
@@ -45,7 +45,7 @@ export class CaptureMidi extends Capture {
|
|
|
45
45
|
some: id => {
|
|
46
46
|
const device = MidiDevices.findInputDeviceById(id);
|
|
47
47
|
if (device.isEmpty()) {
|
|
48
|
-
return
|
|
48
|
+
return `Could not find device with id '${id}'`;
|
|
49
49
|
}
|
|
50
50
|
const deviceName = device.unwrapOrUndefined()?.name ?? "Unknown device";
|
|
51
51
|
return this.#filterChannel.match({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecordAutomation.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAutomation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,UAAU,EAAkB,MAAM,kBAAkB,CAAA;AAc5G,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAGlC,yBAAiB,gBAAgB,CAAC;IAevB,MAAM,KAAK,GAAI,SAAS,OAAO,KAAG,UAsPxC,CAAA;CACJ"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { Option, quantizeCeil, quantizeFloor, Terminable, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { Interpolation, PPQN } from "@opendaw/lib-dsp";
|
|
3
|
+
import { Address } from "@opendaw/lib-box";
|
|
4
|
+
import { TrackBox, ValueEventBox, ValueEventCollectionBox, ValueRegionBox } from "@opendaw/studio-boxes";
|
|
5
|
+
import { ColorCodes, Devices, InterpolationFieldAdapter, TrackBoxAdapter, TrackType, ValueEventCollectionBoxAdapter } from "@opendaw/studio-adapters";
|
|
6
|
+
import { RegionClipResolver } from "../ui";
|
|
7
|
+
export var RecordAutomation;
|
|
8
|
+
(function (RecordAutomation) {
|
|
9
|
+
const Eplison = 0.01;
|
|
10
|
+
RecordAutomation.start = (project) => {
|
|
11
|
+
const { editing, engine, boxAdapters, parameterFieldAdapters, boxGraph, timelineBox } = project;
|
|
12
|
+
const activeRecordings = Address.newSet(state => state.adapter.address);
|
|
13
|
+
let lastPosition = engine.position.getValue();
|
|
14
|
+
const createRegion = (trackBoxAdapter, adapter, startPos, previousUnitValue, value, floating) => {
|
|
15
|
+
const trackBox = trackBoxAdapter.box;
|
|
16
|
+
project.selection.deselect(...trackBoxAdapter.regions.collection.asArray()
|
|
17
|
+
.filter(region => region.isSelected)
|
|
18
|
+
.map(region => region.box));
|
|
19
|
+
RegionClipResolver.fromRange(trackBoxAdapter, startPos, startPos + PPQN.SemiQuaver)();
|
|
20
|
+
const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
|
|
21
|
+
const regionBox = ValueRegionBox.create(boxGraph, UUID.generate(), box => {
|
|
22
|
+
box.position.setValue(startPos);
|
|
23
|
+
box.duration.setValue(PPQN.SemiQuaver);
|
|
24
|
+
box.loopDuration.setValue(PPQN.SemiQuaver);
|
|
25
|
+
box.hue.setValue(ColorCodes.forTrackType(TrackType.Value));
|
|
26
|
+
box.label.setValue(adapter.name);
|
|
27
|
+
box.events.refer(collectionBox.owners);
|
|
28
|
+
box.regions.refer(trackBox.regions);
|
|
29
|
+
});
|
|
30
|
+
project.selection.select(regionBox);
|
|
31
|
+
const interpolation = floating ? Interpolation.Linear : Interpolation.None;
|
|
32
|
+
let lastEventBox;
|
|
33
|
+
if (previousUnitValue !== value) {
|
|
34
|
+
ValueEventBox.create(boxGraph, UUID.generate(), box => {
|
|
35
|
+
box.position.setValue(0);
|
|
36
|
+
box.value.setValue(previousUnitValue);
|
|
37
|
+
box.events.refer(collectionBox.events);
|
|
38
|
+
});
|
|
39
|
+
lastEventBox = ValueEventBox.create(boxGraph, UUID.generate(), box => {
|
|
40
|
+
box.position.setValue(0);
|
|
41
|
+
box.index.setValue(1);
|
|
42
|
+
box.value.setValue(value);
|
|
43
|
+
box.events.refer(collectionBox.events);
|
|
44
|
+
});
|
|
45
|
+
InterpolationFieldAdapter.write(lastEventBox.interpolation, interpolation);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
lastEventBox = ValueEventBox.create(boxGraph, UUID.generate(), box => {
|
|
49
|
+
box.position.setValue(0);
|
|
50
|
+
box.value.setValue(value);
|
|
51
|
+
box.events.refer(collectionBox.events);
|
|
52
|
+
});
|
|
53
|
+
InterpolationFieldAdapter.write(lastEventBox.interpolation, interpolation);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
adapter, trackBoxAdapter, regionBox, collectionBox,
|
|
57
|
+
startPosition: startPos, floating, lastValue: value,
|
|
58
|
+
lastRelativePosition: 0, lastEventBox
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
const findOrCreateTrack = (adapter) => {
|
|
62
|
+
const deviceBox = adapter.field.box;
|
|
63
|
+
const deviceAdapterOpt = Option.tryCatch(() => boxAdapters.adapterFor(deviceBox, Devices.isAny));
|
|
64
|
+
if (deviceAdapterOpt.isEmpty()) {
|
|
65
|
+
console.warn(`Cannot record automation: could not find device adapter for ${deviceBox.name}`);
|
|
66
|
+
return Option.None;
|
|
67
|
+
}
|
|
68
|
+
const deviceAdapter = deviceAdapterOpt.unwrap();
|
|
69
|
+
const audioUnitAdapter = deviceAdapter.audioUnitBoxAdapter();
|
|
70
|
+
const tracks = audioUnitAdapter.tracks;
|
|
71
|
+
const existing = tracks.controls(adapter.field);
|
|
72
|
+
if (existing.nonEmpty()) {
|
|
73
|
+
return Option.wrap(existing.unwrap());
|
|
74
|
+
}
|
|
75
|
+
const trackBox = TrackBox.create(boxGraph, UUID.generate(), box => {
|
|
76
|
+
box.index.setValue(tracks.collection.getMinFreeIndex());
|
|
77
|
+
box.type.setValue(TrackType.Value);
|
|
78
|
+
box.tracks.refer(audioUnitAdapter.box.tracks);
|
|
79
|
+
box.target.refer(adapter.field);
|
|
80
|
+
});
|
|
81
|
+
return Option.wrap(boxAdapters.adapterFor(trackBox, TrackBoxAdapter));
|
|
82
|
+
};
|
|
83
|
+
const handleWrite = ({ adapter, previousUnitValue }) => {
|
|
84
|
+
if (!engine.isRecording.getValue()) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const position = engine.position.getValue();
|
|
88
|
+
const value = adapter.getUnitValue();
|
|
89
|
+
const existingState = activeRecordings.opt(adapter.address);
|
|
90
|
+
if (existingState.isEmpty()) {
|
|
91
|
+
editing.modify(() => {
|
|
92
|
+
const trackOpt = findOrCreateTrack(adapter);
|
|
93
|
+
if (trackOpt.isEmpty()) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const trackBoxAdapter = trackOpt.unwrap();
|
|
97
|
+
const startPos = quantizeFloor(position, PPQN.SemiQuaver);
|
|
98
|
+
const floating = adapter.valueMapping.floating();
|
|
99
|
+
const state = createRegion(trackBoxAdapter, adapter, startPos, previousUnitValue, value, floating);
|
|
100
|
+
activeRecordings.add(state);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const state = existingState.unwrap();
|
|
105
|
+
if (position < state.startPosition) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const relativePosition = position - state.startPosition;
|
|
109
|
+
if (relativePosition === state.lastRelativePosition) {
|
|
110
|
+
editing.modify(() => {
|
|
111
|
+
state.lastEventBox.value.setValue(value);
|
|
112
|
+
state.lastValue = value;
|
|
113
|
+
}, false);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
editing.modify(() => {
|
|
117
|
+
const interpolation = state.floating ? Interpolation.Linear : Interpolation.None;
|
|
118
|
+
state.lastEventBox = ValueEventBox.create(boxGraph, UUID.generate(), box => {
|
|
119
|
+
box.position.setValue(relativePosition);
|
|
120
|
+
box.value.setValue(value);
|
|
121
|
+
box.events.refer(state.collectionBox.events);
|
|
122
|
+
});
|
|
123
|
+
InterpolationFieldAdapter.write(state.lastEventBox.interpolation, interpolation);
|
|
124
|
+
state.lastValue = value;
|
|
125
|
+
state.lastRelativePosition = relativePosition;
|
|
126
|
+
}, false);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const handlePosition = () => {
|
|
131
|
+
if (!engine.isRecording.getValue()) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (activeRecordings.size() === 0) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const currentPosition = engine.position.getValue();
|
|
138
|
+
const loopEnabled = timelineBox.loopArea.enabled.getValue();
|
|
139
|
+
const loopFrom = timelineBox.loopArea.from.getValue();
|
|
140
|
+
const loopTo = timelineBox.loopArea.to.getValue();
|
|
141
|
+
if (loopEnabled && currentPosition < lastPosition) {
|
|
142
|
+
editing.modify(() => {
|
|
143
|
+
const snapshot = [...activeRecordings.values()];
|
|
144
|
+
for (const state of snapshot) {
|
|
145
|
+
if (!state.regionBox.isAttached()) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const finalDuration = Math.max(PPQN.SemiQuaver, quantizeCeil(loopTo - state.startPosition, PPQN.SemiQuaver));
|
|
149
|
+
const oldDuration = state.regionBox.duration.getValue();
|
|
150
|
+
if (finalDuration > oldDuration) {
|
|
151
|
+
RegionClipResolver.fromRange(state.trackBoxAdapter, state.startPosition + oldDuration, state.startPosition + finalDuration)();
|
|
152
|
+
}
|
|
153
|
+
if (finalDuration !== state.lastRelativePosition) {
|
|
154
|
+
ValueEventBox.create(boxGraph, UUID.generate(), box => {
|
|
155
|
+
box.position.setValue(finalDuration);
|
|
156
|
+
box.value.setValue(state.lastValue);
|
|
157
|
+
box.events.refer(state.collectionBox.events);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
state.regionBox.duration.setValue(finalDuration);
|
|
161
|
+
state.regionBox.loopDuration.setValue(finalDuration);
|
|
162
|
+
simplifyRecordedEvents(state);
|
|
163
|
+
project.selection.deselect(state.regionBox);
|
|
164
|
+
const newStartPos = quantizeFloor(loopFrom, PPQN.SemiQuaver);
|
|
165
|
+
const newState = createRegion(state.trackBoxAdapter, state.adapter, newStartPos, state.lastValue, state.lastValue, state.floating);
|
|
166
|
+
activeRecordings.removeByKey(state.adapter.address);
|
|
167
|
+
activeRecordings.add(newState);
|
|
168
|
+
}
|
|
169
|
+
}, false);
|
|
170
|
+
}
|
|
171
|
+
lastPosition = currentPosition;
|
|
172
|
+
editing.modify(() => {
|
|
173
|
+
for (const state of activeRecordings.values()) {
|
|
174
|
+
if (!state.regionBox.isAttached()) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const oldDuration = state.regionBox.duration.getValue();
|
|
178
|
+
const maxDuration = loopEnabled
|
|
179
|
+
? loopTo - state.startPosition
|
|
180
|
+
: Infinity;
|
|
181
|
+
const newDuration = Math.max(PPQN.SemiQuaver, quantizeCeil(Math.min(maxDuration, currentPosition - state.startPosition), PPQN.SemiQuaver));
|
|
182
|
+
if (newDuration > oldDuration) {
|
|
183
|
+
RegionClipResolver.fromRange(state.trackBoxAdapter, state.startPosition + oldDuration, state.startPosition + newDuration)();
|
|
184
|
+
}
|
|
185
|
+
state.regionBox.duration.setValue(newDuration);
|
|
186
|
+
state.regionBox.loopDuration.setValue(newDuration);
|
|
187
|
+
}
|
|
188
|
+
}, false);
|
|
189
|
+
};
|
|
190
|
+
const simplifyRecordedEvents = (state) => {
|
|
191
|
+
if (!state.floating) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const adapter = boxAdapters.adapterFor(state.collectionBox, ValueEventCollectionBoxAdapter);
|
|
195
|
+
const events = [...adapter.events.asArray()];
|
|
196
|
+
const keep = [];
|
|
197
|
+
for (const event of events) {
|
|
198
|
+
while (keep.length >= 2) {
|
|
199
|
+
const a = keep[keep.length - 2];
|
|
200
|
+
const b = keep[keep.length - 1];
|
|
201
|
+
if (a.position === b.position || b.position === event.position) {
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
if (a.interpolation.type !== "linear" || b.interpolation.type !== "linear") {
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
const t = (b.position - a.position) / (event.position - a.position);
|
|
208
|
+
const expected = a.value + t * (event.value - a.value);
|
|
209
|
+
if (Math.abs(b.value - expected) > Eplison) {
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
keep.pop();
|
|
213
|
+
b.box.delete();
|
|
214
|
+
}
|
|
215
|
+
keep.push(event);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const handleTermination = () => {
|
|
219
|
+
if (activeRecordings.size() === 0) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const finalPosition = engine.position.getValue();
|
|
223
|
+
editing.modify(() => {
|
|
224
|
+
for (const state of activeRecordings.values()) {
|
|
225
|
+
if (!state.regionBox.isAttached()) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const finalDuration = Math.max(0, quantizeCeil(finalPosition - state.startPosition, PPQN.SemiQuaver));
|
|
229
|
+
if (finalDuration <= 0) {
|
|
230
|
+
state.regionBox.delete();
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const oldDuration = state.regionBox.duration.getValue();
|
|
234
|
+
if (finalDuration > oldDuration) {
|
|
235
|
+
RegionClipResolver.fromRange(state.trackBoxAdapter, state.startPosition + oldDuration, state.startPosition + finalDuration)();
|
|
236
|
+
}
|
|
237
|
+
if (finalDuration !== state.lastRelativePosition) {
|
|
238
|
+
ValueEventBox.create(boxGraph, UUID.generate(), box => {
|
|
239
|
+
box.position.setValue(finalDuration);
|
|
240
|
+
box.value.setValue(state.lastValue);
|
|
241
|
+
box.events.refer(state.collectionBox.events);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
state.regionBox.duration.setValue(finalDuration);
|
|
245
|
+
state.regionBox.loopDuration.setValue(finalDuration);
|
|
246
|
+
simplifyRecordedEvents(state);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
return Terminable.many(parameterFieldAdapters.subscribeWrites(handleWrite), engine.position.subscribe(handlePosition), Terminable.create(handleTermination));
|
|
251
|
+
};
|
|
252
|
+
})(RecordAutomation || (RecordAutomation = {}));
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { Terminable } from "@opendaw/lib-std";
|
|
2
2
|
import { Project } from "../project";
|
|
3
|
+
import { ppqn } from "@opendaw/lib-dsp";
|
|
3
4
|
export declare class Recording {
|
|
4
5
|
#private;
|
|
5
6
|
readonly countIn: boolean;
|
|
7
|
+
readonly startPosition: ppqn;
|
|
6
8
|
static get isRecording(): boolean;
|
|
7
9
|
static start(project: Project, countIn: boolean): Promise<Terminable>;
|
|
8
10
|
static wasCountingIn(): boolean;
|
|
11
|
+
static wasStartingAt(): ppqn;
|
|
9
12
|
private constructor();
|
|
10
13
|
}
|
|
11
14
|
//# sourceMappingURL=Recording.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Recording.d.ts","sourceRoot":"","sources":["../../src/capture/Recording.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Recording.d.ts","sourceRoot":"","sources":["../../src/capture/Recording.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,UAAU,EAAa,MAAM,kBAAkB,CAAA;AAE/E,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAGrC,qBAAa,SAAS;;IA8CE,QAAQ,CAAC,OAAO,EAAE,OAAO;IAAE,QAAQ,CAAC,aAAa,EAAE,IAAI;IA7C3E,MAAM,KAAK,WAAW,IAAI,OAAO,CAA2B;WAE/C,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAwC3E,MAAM,CAAC,aAAa,IAAI,OAAO;IAC/B,MAAM,CAAC,aAAa,IAAI,IAAI;IAE5B,OAAO;CACV"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { assert, Errors, Option, Terminable, Terminator } from "@opendaw/lib-std";
|
|
2
2
|
import { Promises } from "@opendaw/lib-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import { AudioUnitBox } from "@opendaw/studio-boxes";
|
|
5
|
-
import { InstrumentFactories } from "@opendaw/studio-adapters";
|
|
3
|
+
import { RecordAutomation } from "./RecordAutomation";
|
|
6
4
|
export class Recording {
|
|
7
5
|
countIn;
|
|
6
|
+
startPosition;
|
|
8
7
|
static get isRecording() { return this.#isRecording; }
|
|
9
8
|
static async start(project, countIn) {
|
|
10
9
|
if (this.#isRecording) {
|
|
@@ -12,21 +11,19 @@ export class Recording {
|
|
|
12
11
|
}
|
|
13
12
|
this.#isRecording = true;
|
|
14
13
|
assert(this.#instance.isEmpty(), "Recording already in progress");
|
|
15
|
-
this.#prepare(project);
|
|
16
14
|
const { captureDevices, engine, editing } = project;
|
|
17
15
|
const terminator = new Terminator();
|
|
18
16
|
const captures = captureDevices.filterArmed();
|
|
19
|
-
if (captures.length
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
if (captures.length > 0) {
|
|
18
|
+
const { status, error } = await Promises.tryCatch(Promise.all(captures.map(capture => capture.prepareRecording())));
|
|
19
|
+
if (status === "rejected") {
|
|
20
|
+
this.#isRecording = false;
|
|
21
|
+
return Errors.warn(String(error));
|
|
22
|
+
}
|
|
23
|
+
captures.forEach(capture => capture.clearRecordedRegions());
|
|
24
|
+
terminator.ownAll(...captures.map(capture => capture.startRecording()));
|
|
27
25
|
}
|
|
28
|
-
|
|
29
|
-
terminator.ownAll(...captures.map(capture => capture.startRecording()));
|
|
26
|
+
terminator.own(RecordAutomation.start(project));
|
|
30
27
|
engine.prepareRecordingState(countIn);
|
|
31
28
|
const { isRecording, isCountingIn } = engine;
|
|
32
29
|
const stop = () => {
|
|
@@ -37,32 +34,15 @@ export class Recording {
|
|
|
37
34
|
this.#isRecording = false;
|
|
38
35
|
};
|
|
39
36
|
terminator.ownAll(engine.isRecording.subscribe(stop), engine.isCountingIn.subscribe(stop), Terminable.create(() => Recording.#instance = Option.None));
|
|
40
|
-
this.#instance = Option.wrap(new Recording(countIn));
|
|
37
|
+
this.#instance = Option.wrap(new Recording(countIn, engine.position.getValue()));
|
|
41
38
|
return terminator;
|
|
42
39
|
}
|
|
43
|
-
static #prepare({ api, captureDevices, editing, rootBox, userEditingManager }) {
|
|
44
|
-
const captures = captureDevices.filterArmed();
|
|
45
|
-
const instruments = rootBox.audioUnits.pointerHub.incoming()
|
|
46
|
-
.map(({ box }) => asInstanceOf(box, AudioUnitBox))
|
|
47
|
-
.filter(box => box.type.getValue() === AudioUnitType.Instrument);
|
|
48
|
-
if (instruments.length === 0) {
|
|
49
|
-
const { audioUnitBox } = editing
|
|
50
|
-
.modify(() => api.createInstrument(InstrumentFactories.Tape))
|
|
51
|
-
.unwrap("Could not create Tape");
|
|
52
|
-
captureDevices.get(audioUnitBox.address.uuid)
|
|
53
|
-
.unwrap("Could not unwrap capture")
|
|
54
|
-
.armed.setValue(true);
|
|
55
|
-
}
|
|
56
|
-
else if (captures.length === 0) {
|
|
57
|
-
userEditingManager.audioUnit.get()
|
|
58
|
-
.ifSome(({ box: { address: { uuid } } }) => captureDevices.get(uuid)
|
|
59
|
-
.ifSome(capture => capture.armed.setValue(true))); // auto arm editing audio-unit
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
40
|
static #isRecording = false;
|
|
63
41
|
static #instance = Option.None;
|
|
64
42
|
static wasCountingIn() { return this.#instance.mapOr(recording => recording.countIn, () => false); }
|
|
65
|
-
|
|
43
|
+
static wasStartingAt() { return this.#instance.mapOr(recording => recording.startPosition, () => 0.0); }
|
|
44
|
+
constructor(countIn, startPosition) {
|
|
66
45
|
this.countIn = countIn;
|
|
46
|
+
this.startPosition = startPosition;
|
|
67
47
|
}
|
|
68
48
|
}
|
package/dist/capture/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capture/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capture/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA"}
|
package/dist/capture/index.js
CHANGED
package/dist/offline-engine.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var d=n=>n!=null;var y=(n,e="asDefined failed")=>n??g(U(e));var U=n=>n instanceof Function?n():n;var z=n=>{throw new Error(`Unhandled ${n}`)},g=n=>{throw typeof n=="string"?new Error(n):n},q=(n,e)=>n?void 0:g(U(e));var V=n=>new Proxy({},{get(){return g(n)}});var N=class{value;status="success";constructor(e){this.value=e}error=V("Cannot access error when succeeded")},$=class{error;status="failure";constructor(e){this.error=e}value=V("Cannot access value when failed")},G=n=>{try{return new N(n())}catch(e){return new $(e)}};var Y=()=>{};var _;(function(n){n[n.Ascending=1]="Ascending",n[n.Descending=-1]="Descending"})(_||(_={}));var v=class{static#e=Object.freeze(new Array(0));static empty=()=>this.#e;static clear=e=>{e.length=0};static replace=(e,t)=>{e.length=0,e.push(...t)};static consume=(e,t)=>{for(let s=0;s<e.length;)t(e[s])?e.splice(s,1):s++};static peekFirst=e=>e.at(0)??null;static peekLast=e=>e.at(-1)??null;static getFirst=(e,t)=>y(e.at(0),t);static getLast=(e,t)=>y(e.at(-1),t);static getPrev=(e,t)=>{let s=e.indexOf(t);return s===-1?g(`${t} not found in ${e}`):y(e.at((s-1)%e.length),"Internal Error")};static getNext=(e,t)=>{let s=e.indexOf(t);return s===-1?g(`${t} not found in ${e}`):y(e.at((s+1)%e.length),"Internal Error")};static removeLast=(e,t)=>y(e.pop(),t);static create=(e,t)=>{let s=new Array(t);for(let r=0;r<t;r++)s[r]=e(r);return s};static equals=(e,t)=>{if(e.length!==t.length)return!1;for(let s=0;s<e.length;s++)if(e[s]!==t[s])return!1;return!0};static satisfy=(e,t)=>{if(e.length<2)return!0;let s=e[0];for(let r=1;r<e.length;r++)if(!t(s,e[r]))return!1;return!0};static remove=(e,t)=>{let s=e.indexOf(t);if(s===-1)return g(`${t} not found in ${e}`);e.splice(s,1)};static removeIf=(e,t)=>{for(let s=e.length-1;s>=0;s--)t(e[s])&&e.splice(s,1)};static removeOpt=(e,t)=>{let s=e.indexOf(t);return s===-1?!1:(e.splice(s,1),!0)};static hasDuplicates=e=>new Set(e).size<e.length;static removeDuplicates=e=>{let t=0,s=new Set;for(let r of e)s.has(r)||(s.add(r),e[t++]=r);return e.length=t,e};static removeDuplicateKeys=(e,t)=>{let s=0,r=new Set;for(let i of e){let c=i[t];r.has(c)||(r.add(c),e[s++]=i)}return e.length=s,e};static subtract(e,t,s){return e.filter(r=>!t.some(i=>s(r,i)))}static intersect(e,t,s){return e.filter(r=>t.some(i=>s(r,i)))}static merge(e,t,s){return[...e.filter(r=>!t.some(i=>s(r,i))),...t]}static*iterate(e){for(let t=0;t<e.length;t++)yield e[t]}static*iterateReverse(e){for(let t=e.length-1;t>=0;t--)yield e[t]}static*iterateStateFull(e){let t=e.length-1;for(let s=0;s<=t;s++)yield{value:e[s],isFirst:s===0,isLast:s===t}}static*iterateAdjacent(e){if(!(e.length<=1))for(let t=1,s=e[0];t<e.length;t++){let r=e[t];yield[s,r],s=r}}static isSorted(e,t=_.Ascending){if(e.length<2)return!0;let s=e[0];for(let r=1;r<e.length;r++){let i=e[r];if(Math.sign(s-i)===t)return!1;s=i}return!0}static toRecord(e,t){return e.reduce((s,r)=>(s[t(r)]=r,s),{})}static concatArrayBuffers(e,t){let s=new ArrayBuffer(e.byteLength+t.byteLength),r=new Uint8Array(s);return r.set(new Uint8Array(e),0),r.set(new Uint8Array(t),e.byteLength),s}};var S=class{static*empty(){}static one(e){return[e]}static count(e){let t=0;for(let s of e)t++;return t}static some(e,t){for(let s of e)if(t(s))return!0;return!1}static every(e,t){for(let s of e)if(!t(s))return!1;return!0}static reduce(e,t,s){let r=s,i=0;for(let c of e)r=t(r,c,i++);return r}static includes(e,t){for(let s of e)if(s===t)return!0;return!1}static forEach(e,t){for(let s of e)t(s)}static*map(e,t){let s=0;for(let r of e)yield t(r,s++)}static*take(e,t){let s=0;for(let r of e){if(s++>=t)return;yield r}}static filter(e,t){let s=[];for(let r of e)t(r)&&s.push(r);return s}static filterMap(e,t){let s=[];for(let r of e){let i=t(r);d(i)&&s.push(i)}return s}static reverse(e){let t=[];for(let s of e)t.push(s);return t.reverse()}static*pairWise(e){let t=e[Symbol.iterator](),{done:s,value:r}=t.next(),i=r;if(s!==!0)for(;;){let{done:c,value:o}=t.next();if(c===!0){yield[i,null];return}yield[i,o],i=o}}};var K=Object.freeze({Empty:{terminate:Y},create:n=>({terminate:n}),many:(...n)=>({terminate:()=>{for(;n.length>0;)n.pop().terminate()}})});var T=class{static subscribeMany(e,...t){return K.many(...t.map(s=>s.subscribe(()=>e(s))))}#e=new Set;subscribe(e){return this.#e.add(e),{terminate:()=>this.#e.delete(e)}}isEmpty(){return this.#e.size===0}notify(e){this.#e.forEach(t=>t(e))}observers(){return this.#e}terminate(){this.#e.clear()}};var O=class n{static createEstimator=()=>{let e=performance.now(),t=n.millis(Number.POSITIVE_INFINITY),s=0;return r=>{if(r===0)return n.POSITIVE_INFINITY;if(r>=1)return n.millis(0);let i=performance.now()-e;return i>s*1e3&&(t=n.millis(i/r-i),s++),t}};static POSITIVE_INFINITY=new n(Number.POSITIVE_INFINITY);static millis=e=>new n(e);static seconds=e=>new n(e*n.#e);static minutes=e=>new n(e*n.#t);static hours=e=>new n(e*n.#r);static days=e=>new n(e*n.#o);static toHHMMSS=e=>((e/3600|0)+100).toString().slice(1)+":"+((e/60|0)%60+100).toString().slice(1)+":"+(e%60+100).toString().slice(1);static#e=1e3;static#t=6e4;static#r=36e5;static#o=864e5;#s;constructor(e){this.#s=e}millis(){return this.#s}absSeconds(){return Math.abs(this.#s)/n.#e}absMinutes(){return Math.abs(this.#s)/n.#t}absHours(){return Math.abs(this.#s)/n.#r}absDays(){return Math.abs(this.#s)/n.#o}split(){return{d:Math.floor(this.absDays()),h:Math.floor(this.absHours())%24,m:Math.floor(this.absMinutes())%60,s:Math.floor(this.absSeconds())%60}}isNow(){return this.#s===0}isPast(){return this.#s<0}isFuture(){return this.#s>0}toUnitString(){let e,t,s=Math.floor(Math.abs(this.#s)/1e3),r=Math.floor(s/60),i=Math.floor(r/60),c=Math.floor(i/24);return s<60?(e=s,t="second"):r<60?(e=r,t="minute"):i<24?(e=i,t="hour"):(e=c,t="day"),new Intl.RelativeTimeFormat("en",{numeric:"auto",style:"long"}).format(e*Math.sign(this.#s),t)}toString(){if(isNaN(this.#s))return"NaN";if(!isFinite(this.#s))return"\u221E";let{d:e,h:t,m:s,s:r}=this.split();return e>0?[n.#n("d",e),n.#n("h",t),n.#n("m",s),n.#n("s",r)].join(", "):t>0?[n.#n("h",t),n.#n("m",s),n.#n("s",r)].join(", "):s>0?[n.#n("m",s),n.#n("s",r)].join(", "):r>0?n.#n("s",r):"now"}static#n=(e,t)=>{switch(e){case"d":return`${t} ${t<2?"day":"days"}`;case"h":return`${t} ${t<2?"hour":"hours"}`;case"m":return`${t} ${t<2?"minute":"minutes"}`;case"s":return`${t} ${t<2?"second":"seconds"}`;default:return z(e)}}};var A;(function(n){class e{value;constructor(o){this.value=o}}n.Transfer=e,n.makeTransferable=c=>new e(c),n.sender=(c,o)=>o(new r(c)),n.executor=(c,o)=>new i(c,o);let t=c=>{let o=[];for(let a of c)a instanceof e?o.push(a.value):(a instanceof MessagePort||typeof ImageBitmap<"u"&&a instanceof ImageBitmap||typeof OffscreenCanvas<"u"&&a instanceof OffscreenCanvas)&&o.push(a);return o},s=c=>c instanceof e?c.value:c;class r{#e;#t=new Map;#r;#o=0;constructor(o){this.#e=o,this.#r=o.subscribe(this.#s)}terminate(){this.#r.terminate()}dispatchAndForget=(o,...a)=>{let u=t(a);this.#e.send({type:"send",returnId:!1,func:o.name,args:Array.from(S.map(a,f=>({value:s(f)})))},u)};dispatchAndReturn=(o,...a)=>new Promise((u,f)=>{let p=S.reduce(a,(l,m,x)=>(typeof m=="function"&&l.push([x,m]),l),[]);this.#t.set(this.#o,{executorTuple:{resolve:u,reject:f},callbacks:new Map(p)});let h=t(a);this.#e.send({type:"send",returnId:this.#o,func:o.name,args:Array.from(S.map(a,(l,m)=>typeof l=="function"?{callback:m}:{value:s(l)}))},h),this.#o++});#s=o=>{let a=this.#t.get(o.returnId);d(a)?o.type==="resolve"?(a.executorTuple.resolve(o.resolve),this.#t.delete(o.returnId)):o.type==="reject"?(a.executorTuple.reject(o.reject),this.#t.delete(o.returnId)):o.type==="callback"&&a.callbacks?.get(o.funcAt).apply(this,o.args):g(`Promise has already been resolved. ${JSON.stringify(o)}`)}}class i{#e;#t;#r;constructor(o,a){this.#e=o,this.#t=a,this.#r=o.subscribe(this.#o)}terminate(){this.#r.terminate()}#o=o=>{q(o.type==="send",()=>"Message type must be 'send'");let a=Object.getPrototypeOf(this.#t)===Object.getPrototypeOf({})?this.#t:Object.getPrototypeOf(this.#t),u=y(a[o.func],`${o.func.toString()} does not exists on ${this.#t}`),f=o.returnId;if(f===!1)u.apply(this.#t,o.args.map(p=>"value"in p?p.value:g(`${o.func.toString()} has no promise.`)));else try{u.apply(this.#t,o.args.map(h=>"callback"in h?(...l)=>this.#i(f,h.callback,l):h.value)).then(h=>{try{this.#s(f,h)}catch(l){this.#n(f,l)}},h=>this.#n(f,h))}catch(p){this.#n(f,p)}};#s=(o,a)=>this.#e.send({type:"resolve",returnId:o,resolve:a});#n=(o,a)=>this.#e.send({type:"reject",returnId:o,reject:a});#i=(o,a,u)=>this.#e.send({type:"callback",returnId:o,funcAt:a,args:u})}n.Executor=i})(A||(A={}));var W={for:n=>new D(n)},re=[],D=class{#e;#t=new T;constructor(e){if(this.#e=e,d(e.onmessage)||d(e.onmessageerror))throw console.error(e),new Error(`${e} is already wrapped.`);e.onmessage=t=>this.#t.notify(t.data),e.onmessageerror=t=>{throw new Error(t.type)}}send(e,t){this.#e.postMessage(e,t??re)}channel(e){return new k(this,e)}subscribe(e){return this.#t.subscribe(e)}terminate(){this.#t.terminate(),this.#e.onmessage=null,this.#e.onmessageerror=null}},k=class n{#e;#t;#r=new T;#o;constructor(e,t){this.#e=e,this.#t=t,this.#o=e.subscribe(s=>{"__id__"in s&&s.__id__==="42"&&"message"in s&&"channel"in s&&s.channel===t&&this.#r.notify(s.message)})}send(e,t){this.#e.send({__id__:"42",channel:this.#t,message:e},t)}channel(e){return new n(this,e)}subscribe(e){return this.#r.subscribe(e)}terminate(){this.#o.terminate(),this.#r.terminate()}};var F;(function(n){n.frame=()=>new Promise(e=>requestAnimationFrame(()=>e())),n.frames=e=>new Promise(t=>{let s=e,r=()=>{--s<=0?t():requestAnimationFrame(r)};requestAnimationFrame(r)}),n.timeSpan=(e,...t)=>new Promise(s=>setTimeout(s,e.millis(),...t)),n.event=(e,t)=>new Promise(s=>e.addEventListener(t,s,{once:!0})),n.observable=e=>new Promise(t=>{let s=e.subscribe(()=>{s.terminate(),t()})}),n.complete=e=>new Promise((t,s)=>{let r=setInterval(()=>{let{status:i,value:c,error:o}=G(()=>e.next());if(i==="success"){let{done:a,value:u}=c;a&&(clearInterval(r),t(u))}else clearInterval(r),s(o)},0)})})(F||(F={}));var C=(n,e)=>Math.floor(3840/e)*n,Z=(n,e=4,t=4)=>{let s=C(1,t),r=Math.floor(n/s),i=Math.floor(r/e),o=(Math.floor(n)-C(i*e,t))%s,a=Math.floor(o/240),u=o%240;return{bars:i,beats:r-i*e,semiquavers:a,ticks:u}},J=(n,e)=>n*e/60*960,X=(n,e)=>n*60/960/e,oe=(n,e)=>e*60/960/n,ie=(n,e,t)=>J(n/t,e),ae=(n,e,t)=>X(n,e)*t,ee={Bar:3840,Quarter:960,SemiQuaver:240,fromSignature:C,toParts:Z,secondsToPulses:J,pulsesToSeconds:X,secondsToBpm:oe,samplesToPulses:ie,pulsesToSamples:ae,toString:(n,e=4,t=4)=>{let{bars:s,beats:r,semiquavers:i,ticks:c}=Z(n|0,e,t);return`${s+1}.${r+1}.${i+1}:${c}`}};var P=128,Oe=ee.fromSignature(1,48);var ce=Math.log(10)/20;var te=n=>Math.exp(n*ce);var L=class{port;constructor(){this.port=globalThis.__workletPort__}};function se(n){let e=globalThis;e.sampleRate=n.sampleRate,e.currentFrame=0,e.currentTime=0,e.AudioWorkletProcessor=L,e.registerProcessor=(t,s)=>{e.__registeredProcessors__=e.__registeredProcessors__||{},e.__registeredProcessors__[t]=s}}function R(n,e){let t=globalThis;t.currentFrame=n,t.currentTime=n/e}var B=null,Q=null,M=48e3,I=2,j=!1,b=0;A.executor(W.for(self).channel("offline-engine"),{async initialize(n,e,t){M=t.sampleRate,I=t.numberOfChannels,Q=e,b=0,se({sampleRate:M}),globalThis.__workletPort__=n,await import(t.processorsUrl);let s=globalThis.__registeredProcessors__["engine-processor"];B=new s({processorOptions:{syncStreamBuffer:t.syncStreamBuffer,controlFlagsBuffer:t.controlFlagsBuffer,project:t.project,exportConfiguration:t.exportConfiguration}})},async step(n){let e=v.create(()=>new Float32Array(n),I),t=v.create(()=>new Float32Array(P),I),s=0;for(;s<n;){let r=[t];R(b,M),B.process([[]],r),b+=P;let i=n-s,c=Math.min(i,P);for(let o=0;o<I;o++)e[o].set(r[0][o].subarray(0,c),s);s+=c}return e},async render(n){let{silenceThresholdDb:e,silenceDurationSeconds:t,maxDurationSeconds:s}=n,r=te(e??-72),i=Math.ceil((t??10)*M),c=d(s)?Math.ceil(s*M):1/0,o=v.create(()=>[],I),a=0,u=!1,f=0;for(j=!0,await F.timeSpan(O.seconds(0));j&&b<c;){let l=[v.create(()=>new Float32Array(P),I)];R(b,M);let m=B.process([[]],l),x=0;for(let w of l[0])for(let ne of w){let H=Math.abs(ne);H>x&&(x=H)}let E=x<=r;if(x>r&&(u=!0),E&&u){if(a+=P,a>=i)break}else a=0;for(let w=0;w<I;w++)o[w].push(l[0][w].slice());if(b+=P,!m)break;b-f>=M&&(f=b,d(Q)&&Q.postMessage({frames:b}),await new Promise(w=>setTimeout(w,0)))}let p=b-a+Math.min(M/4,a);return v.create(h=>{let l=new Float32Array(p),m=0;for(let x of o[h]){if(m>=p)break;let E=Math.min(x.length,p-m);l.set(x.subarray(0,E),m),m+=E}return l},I)},stop(){j=!1}});
|
|
1
|
+
var m=s=>s!=null;var b=(s,e="asDefined failed")=>s??p(S(e));var S=s=>s instanceof Function?s():s;var U=s=>{throw new Error(`Unhandled ${s}`)},p=s=>{throw typeof s=="string"?new Error(s):s},j=(s,e)=>s?void 0:p(S(e));var H=s=>new Proxy({},{get(){return p(s)}});var k=class{value;status="success";constructor(e){this.value=e}error=H("Cannot access error when succeeded")},C=class{error;status="failure";constructor(e){this.error=e}value=H("Cannot access value when failed")},G=s=>{try{return new k(s())}catch(e){return new C(e)}};var q=()=>{};var $;(function(s){s[s.Ascending=1]="Ascending",s[s.Descending=-1]="Descending"})($||($={}));var v=class{static#e=Object.freeze(new Array(0));static empty=()=>this.#e;static clear=e=>{e.length=0};static replace=(e,t)=>{e.length=0,e.push(...t)};static consume=(e,t)=>{for(let r=0;r<e.length;)t(e[r])?e.splice(r,1):r++};static peekFirst=e=>e.at(0)??null;static peekLast=e=>e.at(-1)??null;static getFirst=(e,t)=>b(e.at(0),t);static getLast=(e,t)=>b(e.at(-1),t);static getPrev=(e,t)=>{let r=e.indexOf(t);return r===-1?p(`${t} not found in ${e}`):b(e.at((r-1)%e.length),"Internal Error")};static getNext=(e,t)=>{let r=e.indexOf(t);return r===-1?p(`${t} not found in ${e}`):b(e.at((r+1)%e.length),"Internal Error")};static removeLast=(e,t)=>b(e.pop(),t);static create=(e,t)=>{let r=new Array(t);for(let n=0;n<t;n++)r[n]=e(n);return r};static equals=(e,t)=>{if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return!1;return!0};static satisfy=(e,t)=>{if(e.length<2)return!0;let r=e[0];for(let n=1;n<e.length;n++)if(!t(r,e[n]))return!1;return!0};static remove=(e,t)=>{let r=e.indexOf(t);if(r===-1)return p(`${t} not found in ${e}`);e.splice(r,1)};static removeIf=(e,t)=>{for(let r=e.length-1;r>=0;r--)t(e[r])&&e.splice(r,1)};static removeOpt=(e,t)=>{let r=e.indexOf(t);return r===-1?!1:(e.splice(r,1),!0)};static hasDuplicates=e=>new Set(e).size<e.length;static removeDuplicates=e=>{let t=0,r=new Set;for(let n of e)r.has(n)||(r.add(n),e[t++]=n);return e.length=t,e};static removeDuplicateKeys=(e,t)=>{let r=0,n=new Set;for(let i of e){let c=i[t];n.has(c)||(n.add(c),e[r++]=i)}return e.length=r,e};static subtract(e,t,r){return e.filter(n=>!t.some(i=>r(n,i)))}static intersect(e,t,r){return e.filter(n=>t.some(i=>r(n,i)))}static merge(e,t,r){return[...e.filter(n=>!t.some(i=>r(n,i))),...t]}static*iterate(e){for(let t=0;t<e.length;t++)yield e[t]}static*iterateReverse(e){for(let t=e.length-1;t>=0;t--)yield e[t]}static*iterateStateFull(e){let t=e.length-1;for(let r=0;r<=t;r++)yield{value:e[r],isFirst:r===0,isLast:r===t}}static*iterateAdjacent(e){if(!(e.length<=1))for(let t=1,r=e[0];t<e.length;t++){let n=e[t];yield[r,n],r=n}}static isSorted(e,t=$.Ascending){if(e.length<2)return!0;let r=e[0];for(let n=1;n<e.length;n++){let i=e[n];if(Math.sign(r-i)===t)return!1;r=i}return!0}static toRecord(e,t){return e.reduce((r,n)=>(r[t(n)]=n,r),{})}static concatArrayBuffers(e,t){let r=new ArrayBuffer(e.byteLength+t.byteLength),n=new Uint8Array(r);return n.set(new Uint8Array(e),0),n.set(new Uint8Array(t),e.byteLength),r}};var E;(function(s){s.wrap=t=>m(t)?new e(t):s.None,s.from=t=>s.wrap(t()),s.tryCatch=t=>{try{return s.wrap(t())}catch{return s.None}},s.execute=(t,...r)=>s.wrap(t?.apply(null,r)),s.async=t=>t.then(r=>s.wrap(r),()=>s.None);class e{#e;constructor(r){this.#e=b(r)}unwrap(){return this.#e}unwrapOrElse(r){return this.#e}unwrapOrNull(){return this.#e}unwrapOrUndefined(){return this.#e}contains(r){return r===this.#e}match(r){return r.some(this.#e)}ifSome(r){return r(this.#e)}ifAbsent(r){}isEmpty(){return!1}nonEmpty(){return!0}map(r){return s.wrap(r(this.#e))}mapOr(r,n){return r(this.#e)}flatMap(r){return r(this.#e)}equals(r){return this.unwrapOrNull()===r.unwrapOrNull()}assert(r){return this}toString(){return`{Option.Some(${this.#e})}`}get[Symbol.toStringTag](){return this.toString()}}s.Some=e,s.None=new class{unwrap=t=>p(m(t)?S(t):"unwrap failed");unwrapOrElse=t=>S(t);unwrapOrNull=()=>null;unwrapOrUndefined=()=>{};contains=t=>!1;match=t=>t.none();ifSome=t=>{};ifAbsent=t=>t(void 0);isEmpty=()=>!0;nonEmpty=()=>!1;map=t=>s.None;mapOr=(t,r)=>S(r);flatMap=t=>s.None;equals=t=>t.isEmpty();assert=t=>p(S(t)??"assert failed");toString=()=>"{Option.None}";get[Symbol.toStringTag](){return this.toString()}}})(E||(E={}));var I=class{static*empty(){}static one(e){return[e]}static count(e){let t=0;for(let r of e)t++;return t}static some(e,t){for(let r of e)if(t(r))return!0;return!1}static every(e,t){for(let r of e)if(!t(r))return!1;return!0}static reduce(e,t,r){let n=r,i=0;for(let c of e)n=t(n,c,i++);return n}static includes(e,t){for(let r of e)if(r===t)return!0;return!1}static forEach(e,t){for(let r of e)t(r)}static*map(e,t){let r=0;for(let n of e)yield t(n,r++)}static*take(e,t){let r=0;for(let n of e){if(r++>=t)return;yield n}}static filter(e,t){let r=[];for(let n of e)t(n)&&r.push(n);return r}static filterMap(e,t){let r=[];for(let n of e){let i=t(n);m(i)&&r.push(i)}return r}static reverse(e){let t=[];for(let r of e)t.push(r);return t.reverse()}static*pairWise(e){let t=e[Symbol.iterator](),{done:r,value:n}=t.next(),i=n;if(r!==!0)for(;;){let{done:c,value:o}=t.next();if(c===!0){yield[i,null];return}yield[i,o],i=o}}};var z=Object.freeze({Empty:{terminate:q},create:s=>({terminate:s}),many:(...s)=>({terminate:()=>{for(;s.length>0;)s.pop().terminate()}})});var O=class{static subscribeMany(e,...t){return z.many(...t.map(r=>r.subscribe(()=>e(r))))}#e=new Set;subscribe(e){return this.#e.add(e),{terminate:()=>this.#e.delete(e)}}isEmpty(){return this.#e.size===0}notify(e){this.#e.forEach(t=>t(e))}observers(){return this.#e}terminate(){this.#e.clear()}};var _=class s{static createEstimator=()=>{let e=performance.now(),t=s.millis(Number.POSITIVE_INFINITY),r=0;return n=>{if(n===0)return s.POSITIVE_INFINITY;if(n>=1)return s.millis(0);let i=performance.now()-e;return i>r*1e3&&(t=s.millis(i/n-i),r++),t}};static POSITIVE_INFINITY=new s(Number.POSITIVE_INFINITY);static millis=e=>new s(e);static seconds=e=>new s(e*s.#e);static minutes=e=>new s(e*s.#t);static hours=e=>new s(e*s.#n);static days=e=>new s(e*s.#o);static toHHMMSS=e=>((e/3600|0)+100).toString().slice(1)+":"+((e/60|0)%60+100).toString().slice(1)+":"+(e%60+100).toString().slice(1);static#e=1e3;static#t=6e4;static#n=36e5;static#o=864e5;#r;constructor(e){this.#r=e}millis(){return this.#r}absSeconds(){return Math.abs(this.#r)/s.#e}absMinutes(){return Math.abs(this.#r)/s.#t}absHours(){return Math.abs(this.#r)/s.#n}absDays(){return Math.abs(this.#r)/s.#o}split(){return{d:Math.floor(this.absDays()),h:Math.floor(this.absHours())%24,m:Math.floor(this.absMinutes())%60,s:Math.floor(this.absSeconds())%60}}isNow(){return this.#r===0}isPast(){return this.#r<0}isFuture(){return this.#r>0}toUnitString(){let e,t,r=Math.floor(Math.abs(this.#r)/1e3),n=Math.floor(r/60),i=Math.floor(n/60),c=Math.floor(i/24);return r<60?(e=r,t="second"):n<60?(e=n,t="minute"):i<24?(e=i,t="hour"):(e=c,t="day"),new Intl.RelativeTimeFormat("en",{numeric:"auto",style:"long"}).format(e*Math.sign(this.#r),t)}toString(){if(isNaN(this.#r))return"NaN";if(!isFinite(this.#r))return"\u221E";let{d:e,h:t,m:r,s:n}=this.split();return e>0?[s.#s("d",e),s.#s("h",t),s.#s("m",r),s.#s("s",n)].join(", "):t>0?[s.#s("h",t),s.#s("m",r),s.#s("s",n)].join(", "):r>0?[s.#s("m",r),s.#s("s",n)].join(", "):n>0?s.#s("s",n):"now"}static#s=(e,t)=>{switch(e){case"d":return`${t} ${t<2?"day":"days"}`;case"h":return`${t} ${t<2?"hour":"hours"}`;case"m":return`${t} ${t<2?"minute":"minutes"}`;case"s":return`${t} ${t<2?"second":"seconds"}`;default:return U(e)}}};var F;(function(s){class e{value;constructor(o){this.value=o}}s.Transfer=e,s.makeTransferable=c=>new e(c),s.sender=(c,o)=>o(new n(c)),s.executor=(c,o)=>new i(c,o);let t=c=>{let o=[];for(let a of c)a instanceof e?o.push(a.value):(a instanceof MessagePort||typeof ImageBitmap<"u"&&a instanceof ImageBitmap||typeof OffscreenCanvas<"u"&&a instanceof OffscreenCanvas)&&o.push(a);return o},r=c=>c instanceof e?c.value:c;class n{#e;#t=new Map;#n;#o=0;constructor(o){this.#e=o,this.#n=o.subscribe(this.#r)}terminate(){this.#n.terminate()}dispatchAndForget=(o,...a)=>{let l=t(a);this.#e.send({type:"send",returnId:!1,func:o.name,args:Array.from(I.map(a,u=>({value:r(u)})))},l)};dispatchAndReturn=(o,...a)=>new Promise((l,u)=>{let w=I.reduce(a,(h,d,x)=>(typeof d=="function"&&h.push([x,d]),h),[]);this.#t.set(this.#o,{executorTuple:{resolve:l,reject:u},callbacks:new Map(w)});let f=t(a);this.#e.send({type:"send",returnId:this.#o,func:o.name,args:Array.from(I.map(a,(h,d)=>typeof h=="function"?{callback:d}:{value:r(h)}))},f),this.#o++});#r=o=>{let a=this.#t.get(o.returnId);m(a)?o.type==="resolve"?(a.executorTuple.resolve(o.resolve),this.#t.delete(o.returnId)):o.type==="reject"?(a.executorTuple.reject(o.reject),this.#t.delete(o.returnId)):o.type==="callback"&&a.callbacks?.get(o.funcAt).apply(this,o.args):p(`Promise has already been resolved. ${JSON.stringify(o)}`)}}class i{#e;#t;#n;constructor(o,a){this.#e=o,this.#t=a,this.#n=o.subscribe(this.#o)}terminate(){this.#n.terminate()}#o=o=>{j(o.type==="send",()=>"Message type must be 'send'");let a=Object.getPrototypeOf(this.#t)===Object.getPrototypeOf({})?this.#t:Object.getPrototypeOf(this.#t),l=b(a[o.func],`${o.func.toString()} does not exists on ${this.#t}`),u=o.returnId;if(u===!1)l.apply(this.#t,o.args.map(w=>"value"in w?w.value:p(`${o.func.toString()} has no promise.`)));else try{l.apply(this.#t,o.args.map(f=>"callback"in f?(...h)=>this.#i(u,f.callback,h):f.value)).then(f=>{try{this.#r(u,f)}catch(h){this.#s(u,h)}},f=>this.#s(u,f))}catch(w){this.#s(u,w)}};#r=(o,a)=>this.#e.send({type:"resolve",returnId:o,resolve:a});#s=(o,a)=>this.#e.send({type:"reject",returnId:o,reject:a});#i=(o,a,l)=>this.#e.send({type:"callback",returnId:o,funcAt:a,args:l})}s.Executor=i})(F||(F={}));var V={for:s=>new R(s)},se=[],R=class{#e;#t=new O;constructor(e){if(this.#e=e,m(e.onmessage)||m(e.onmessageerror))throw console.error(e),new Error(`${e} is already wrapped.`);e.onmessage=t=>this.#t.notify(t.data),e.onmessageerror=t=>{throw new Error(t.type)}}send(e,t){this.#e.postMessage(e,t??se)}channel(e){return new D(this,e)}subscribe(e){return this.#t.subscribe(e)}terminate(){this.#t.terminate(),this.#e.onmessage=null,this.#e.onmessageerror=null}},D=class s{#e;#t;#n=new O;#o;constructor(e,t){this.#e=e,this.#t=t,this.#o=e.subscribe(r=>{"__id__"in r&&r.__id__==="42"&&"message"in r&&"channel"in r&&r.channel===t&&this.#n.notify(r.message)})}send(e,t){this.#e.send({__id__:"42",channel:this.#t,message:e},t)}channel(e){return new s(this,e)}subscribe(e){return this.#n.subscribe(e)}terminate(){this.#o.terminate(),this.#n.terminate()}};var A;(function(s){s.frame=()=>new Promise(e=>requestAnimationFrame(()=>e())),s.frames=e=>new Promise(t=>{let r=e,n=()=>{--r<=0?t():requestAnimationFrame(n)};requestAnimationFrame(n)}),s.timeSpan=(e,...t)=>new Promise(r=>setTimeout(r,e.millis(),...t)),s.event=(e,t)=>new Promise(r=>e.addEventListener(t,r,{once:!0})),s.observable=e=>new Promise(t=>{let r=e.subscribe(()=>{r.terminate(),t()})}),s.complete=e=>new Promise((t,r)=>{let n=setInterval(()=>{let{status:i,value:c,error:o}=G(()=>e.next());if(i==="success"){let{done:a,value:l}=c;a&&(clearInterval(n),t(l))}else clearInterval(n),r(o)},0)})})(A||(A={}));var L=(s,e)=>Math.floor(3840/e)*s,Y=(s,e=4,t=4)=>{let r=L(1,t),n=Math.floor(s/r),i=Math.floor(n/e),o=(Math.floor(s)-L(i*e,t))%r,a=Math.floor(o/240),l=o%240;return{bars:i,beats:n-i*e,semiquavers:a,ticks:l}},K=(s,e)=>s*e/60*960,Z=(s,e)=>s*60/960/e,ne=(s,e)=>e*60/960/s,oe=(s,e,t)=>K(s/t,e),ie=(s,e,t)=>Z(s,e)*t,J={Bar:3840,Quarter:960,SemiQuaver:240,fromSignature:L,toParts:Y,secondsToPulses:K,pulsesToSeconds:Z,secondsToBpm:ne,samplesToPulses:oe,pulsesToSamples:ie,toString:(s,e=4,t=4)=>{let{bars:r,beats:n,semiquavers:i,ticks:c}=Y(s|0,e,t);return`${r+1}.${n+1}.${i+1}:${c}`}};var M=128,Fe=J.fromSignature(1,48);var ae=Math.log(10)/20;var X=s=>Math.exp(s*ae);var g=globalThis,B=class{port;constructor(){this.port=g.__workletPort__}process(e,t){return!1}},ee=s=>{g.sampleRate=s.sampleRate,g.currentFrame=0,g.currentTime=0,g.AudioWorkletProcessor=B,g.registerProcessor=(e,t)=>{g.__registeredProcessors__=g.__registeredProcessors__||{},g.__registeredProcessors__[e]=t}},Q=(s,e)=>{g.currentFrame=s,g.currentTime=s/e};var te=globalThis,N=E.None;F.executor(V.for(self).channel("offline-engine"),{async initialize(s,e,t){ee({sampleRate:t.sampleRate}),te.__workletPort__=s,await import(t.processorsUrl);let r=te.__registeredProcessors__["engine-processor"];N=E.wrap({processor:new r({processorOptions:{syncStreamBuffer:t.syncStreamBuffer,controlFlagsBuffer:t.controlFlagsBuffer,hrClockBuffer:new SharedArrayBuffer(32),project:t.project,exportConfiguration:t.exportConfiguration}}),progressPort:e,sampleRate:t.sampleRate,numberOfChannels:t.numberOfChannels,totalFrames:0,running:!1})},async step(s){let e=N.unwrap(),t=v.create(()=>new Float32Array(s),e.numberOfChannels),r=v.create(()=>new Float32Array(M),e.numberOfChannels),n=0;for(;n<s;){let i=[r];Q(e.totalFrames,e.sampleRate),e.processor.process([[]],i),e.totalFrames+=M;let c=s-n,o=Math.min(c,M);for(let a=0;a<e.numberOfChannels;a++)t[a].set(i[0][a].subarray(0,o),n);n+=o}return t},async render(s){let e=N.unwrap(),{silenceThresholdDb:t,silenceDurationSeconds:r,maxDurationSeconds:n}=s,i=X(t??-72),c=Math.ceil((r??10)*e.sampleRate),o=m(n)?Math.ceil(n*e.sampleRate):1/0,a=v.create(()=>[],e.numberOfChannels),l=0,u=!1,w=0;for(e.running=!0,await A.timeSpan(_.seconds(0));e.running&&e.totalFrames<o;){let d=[v.create(()=>new Float32Array(M),e.numberOfChannels)];Q(e.totalFrames,e.sampleRate);let x=e.processor.process([[]],d),P=0;for(let y of d[0])for(let re of y){let W=Math.abs(re);W>P&&(P=W)}let T=P<=i;if(P>i&&(u=!0),T&&u){if(l+=M,l>=c)break}else l=0;for(let y=0;y<e.numberOfChannels;y++)a[y].push(d[0][y].slice());if(e.totalFrames+=M,!x)break;e.totalFrames-w>=e.sampleRate&&(w=e.totalFrames,e.progressPort.postMessage({frames:e.totalFrames}),await new Promise(y=>setTimeout(y,0)))}let f=e.totalFrames-l+Math.min(e.sampleRate/4,l);return v.create(h=>{let d=new Float32Array(f),x=0;for(let P of a[h]){if(x>=f)break;let T=Math.min(P.length,f-x);d.set(P.subarray(0,T),x),x+=T}return d},e.numberOfChannels)},stop(){N.unwrap().running=!1}});
|
|
2
2
|
//# sourceMappingURL=offline-engine.js.map
|