@opendaw/studio-core 0.0.6
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/README.md +1 -0
- package/dist/Engine.d.ts +21 -0
- package/dist/Engine.d.ts.map +1 -0
- package/dist/Engine.js +1 -0
- package/dist/EngineFacade.d.ts +28 -0
- package/dist/EngineFacade.d.ts.map +1 -0
- package/dist/EngineFacade.js +50 -0
- package/dist/EngineWorklet.d.ts +30 -0
- package/dist/EngineWorklet.d.ts.map +1 -0
- package/dist/EngineWorklet.js +168 -0
- package/dist/MeterWorklet.d.ts +15 -0
- package/dist/MeterWorklet.d.ts.map +1 -0
- package/dist/MeterWorklet.js +33 -0
- package/dist/Mixer.d.ts +13 -0
- package/dist/Mixer.d.ts.map +1 -0
- package/dist/Mixer.js +110 -0
- package/dist/Project.d.ts +41 -0
- package/dist/Project.d.ts.map +1 -0
- package/dist/Project.js +173 -0
- package/dist/ProjectEnv.d.ts +5 -0
- package/dist/ProjectEnv.d.ts.map +1 -0
- package/dist/ProjectEnv.js +1 -0
- package/dist/RecordingWorklet.d.ts +9 -0
- package/dist/RecordingWorklet.d.ts.map +1 -0
- package/dist/RecordingWorklet.js +42 -0
- package/dist/Wav.d.ts +6 -0
- package/dist/Wav.d.ts.map +1 -0
- package/dist/Wav.js +46 -0
- package/dist/WorkletFactory.d.ts +8 -0
- package/dist/WorkletFactory.d.ts.map +1 -0
- package/dist/WorkletFactory.js +9 -0
- package/dist/Worklets.d.ts +22 -0
- package/dist/Worklets.d.ts.map +1 -0
- package/dist/Worklets.js +36 -0
- package/dist/engine-processor.js +6 -0
- package/dist/engine-processor.js.map +7 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/meter-processor.js +2 -0
- package/dist/meter-processor.js.map +7 -0
- package/dist/recording-processor.js +4 -0
- package/dist/recording-processor.js.map +7 -0
- package/dist/sync-log/Commit.d.ts +26 -0
- package/dist/sync-log/Commit.d.ts.map +1 -0
- package/dist/sync-log/Commit.js +76 -0
- package/dist/sync-log/SyncLogReader.d.ts +12 -0
- package/dist/sync-log/SyncLogReader.d.ts.map +1 -0
- package/dist/sync-log/SyncLogReader.js +51 -0
- package/dist/sync-log/SyncLogWriter.d.ts +10 -0
- package/dist/sync-log/SyncLogWriter.d.ts.map +1 -0
- package/dist/sync-log/SyncLogWriter.js +49 -0
- package/package.json +48 -0
package/dist/Project.js
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
import { asInstanceOf, ByteArrayOutput, Option, panic, Terminator, UUID } from "@opendaw/lib-std";
|
2
|
+
import { BoxGraph, Editing } from "@opendaw/lib-box";
|
3
|
+
import { AudioBusBox, AudioUnitBox, BoxIO, GrooveShuffleBox, RootBox, TimelineBox, UserInterfaceBox, ValueEventCurveBox } from "@opendaw/studio-boxes";
|
4
|
+
import { BoxAdapters, IconSymbol, ParameterFieldAdapters, ProjectDecoder, RootBoxAdapter, TimelineBoxAdapter, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
|
5
|
+
import { LiveStreamReceiver } from "@opendaw/lib-fusion";
|
6
|
+
import { AudioUnitType } from "@opendaw/studio-enums";
|
7
|
+
import { Mixer } from "./Mixer";
|
8
|
+
// Main Entry Point for a Project
|
9
|
+
//
|
10
|
+
export class Project {
|
11
|
+
static new(env) {
|
12
|
+
const boxGraph = new BoxGraph(Option.wrap(BoxIO.create));
|
13
|
+
const isoString = new Date().toISOString();
|
14
|
+
console.debug(`New Project created on ${isoString}`);
|
15
|
+
boxGraph.beginTransaction();
|
16
|
+
const grooveShuffleBox = GrooveShuffleBox.create(boxGraph, UUID.generate(), box => {
|
17
|
+
box.label.setValue("Groove Shuffle");
|
18
|
+
});
|
19
|
+
const rootBox = RootBox.create(boxGraph, UUID.generate(), box => {
|
20
|
+
box.groove.refer(grooveShuffleBox);
|
21
|
+
box.created.setValue(isoString);
|
22
|
+
});
|
23
|
+
const userInterfaceBox = UserInterfaceBox.create(boxGraph, UUID.generate());
|
24
|
+
const masterBusBox = AudioBusBox.create(boxGraph, UUID.generate(), box => {
|
25
|
+
box.collection.refer(rootBox.audioBusses);
|
26
|
+
box.label.setValue("Output");
|
27
|
+
box.icon.setValue(IconSymbol.toName(IconSymbol.SpeakerHeadphone));
|
28
|
+
box.color.setValue(/*Colors.blue*/ "hsl(189, 100%, 65%)"); // TODO
|
29
|
+
});
|
30
|
+
const masterAudioUnit = AudioUnitBox.create(boxGraph, UUID.generate(), box => {
|
31
|
+
box.type.setValue(AudioUnitType.Output);
|
32
|
+
box.collection.refer(rootBox.audioUnits);
|
33
|
+
box.output.refer(rootBox.outputDevice);
|
34
|
+
box.index.setValue(0);
|
35
|
+
});
|
36
|
+
const timelineBox = TimelineBox.create(boxGraph, UUID.generate());
|
37
|
+
rootBox.timeline.refer(timelineBox.root);
|
38
|
+
userInterfaceBox.root.refer(rootBox.users);
|
39
|
+
masterBusBox.output.refer(masterAudioUnit.input);
|
40
|
+
boxGraph.endTransaction();
|
41
|
+
return new Project(env, boxGraph, {
|
42
|
+
rootBox,
|
43
|
+
userInterfaceBox,
|
44
|
+
masterBusBox,
|
45
|
+
masterAudioUnit,
|
46
|
+
timelineBox
|
47
|
+
});
|
48
|
+
}
|
49
|
+
static load(env, arrayBuffer) {
|
50
|
+
const skeleton = ProjectDecoder.decode(arrayBuffer);
|
51
|
+
this.#migrate(skeleton);
|
52
|
+
return new Project(env, skeleton.boxGraph, skeleton.mandatoryBoxes);
|
53
|
+
}
|
54
|
+
static #migrate({ boxGraph, mandatoryBoxes }) {
|
55
|
+
const { rootBox } = mandatoryBoxes;
|
56
|
+
if (rootBox.groove.targetAddress.isEmpty()) {
|
57
|
+
console.debug("Migrate to global GrooveShuffleBox");
|
58
|
+
boxGraph.beginTransaction();
|
59
|
+
rootBox.groove.refer(GrooveShuffleBox.create(boxGraph, UUID.generate()));
|
60
|
+
boxGraph.endTransaction();
|
61
|
+
}
|
62
|
+
const globalShuffle = asInstanceOf(rootBox.groove.targetVertex.unwrap(), GrooveShuffleBox).label;
|
63
|
+
if (globalShuffle.getValue() !== "Groove Shuffle") {
|
64
|
+
boxGraph.beginTransaction();
|
65
|
+
globalShuffle.setValue("Groove Shuffle");
|
66
|
+
boxGraph.endTransaction();
|
67
|
+
}
|
68
|
+
// TODO We can remove this when we delete all not-migrated, local(!) project files from my machine
|
69
|
+
boxGraph.boxes().forEach(box => box.accept({
|
70
|
+
visitZeitgeistDeviceBox: (box) => {
|
71
|
+
if (box.groove.targetAddress.isEmpty()) {
|
72
|
+
console.debug("Migrate 'ZeitgeistDeviceBox' to GrooveShuffleBox");
|
73
|
+
boxGraph.beginTransaction();
|
74
|
+
box.groove.refer(rootBox.groove.targetVertex.unwrap());
|
75
|
+
boxGraph.endTransaction();
|
76
|
+
}
|
77
|
+
},
|
78
|
+
visitValueEventBox: (eventBox) => {
|
79
|
+
const slope = eventBox.slope.getValue();
|
80
|
+
if (isNaN(slope)) {
|
81
|
+
return;
|
82
|
+
} // already migrated, nothing to do
|
83
|
+
if (slope === 0.0) { // never set
|
84
|
+
console.debug("Migrate 'ValueEventBox'");
|
85
|
+
boxGraph.beginTransaction();
|
86
|
+
eventBox.slope.setValue(NaN);
|
87
|
+
boxGraph.endTransaction();
|
88
|
+
}
|
89
|
+
else if (eventBox.interpolation.getValue() === 1) { // linear
|
90
|
+
if (slope === 0.5) {
|
91
|
+
console.debug("Migrate 'ValueEventBox' to linear");
|
92
|
+
boxGraph.beginTransaction();
|
93
|
+
eventBox.slope.setValue(NaN);
|
94
|
+
boxGraph.endTransaction();
|
95
|
+
}
|
96
|
+
else {
|
97
|
+
console.debug("Migrate 'ValueEventBox' to new ValueEventCurveBox");
|
98
|
+
boxGraph.beginTransaction();
|
99
|
+
ValueEventCurveBox.create(boxGraph, UUID.generate(), box => {
|
100
|
+
box.event.refer(eventBox.interpolation);
|
101
|
+
box.slope.setValue(slope);
|
102
|
+
});
|
103
|
+
eventBox.slope.setValue(NaN);
|
104
|
+
boxGraph.endTransaction();
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}));
|
109
|
+
}
|
110
|
+
#terminator = new Terminator();
|
111
|
+
#env;
|
112
|
+
boxGraph;
|
113
|
+
rootBox;
|
114
|
+
userInterfaceBox;
|
115
|
+
masterBusBox;
|
116
|
+
masterAudioUnit;
|
117
|
+
timelineBox;
|
118
|
+
editing;
|
119
|
+
selection;
|
120
|
+
boxAdapters;
|
121
|
+
userEditingManager;
|
122
|
+
parameterFieldAdapters;
|
123
|
+
liveStreamReceiver;
|
124
|
+
mixer;
|
125
|
+
constructor(env, boxGraph, { rootBox, userInterfaceBox, masterBusBox, masterAudioUnit, timelineBox }) {
|
126
|
+
this.#env = env;
|
127
|
+
this.boxGraph = boxGraph;
|
128
|
+
this.rootBox = rootBox;
|
129
|
+
this.userInterfaceBox = userInterfaceBox;
|
130
|
+
this.masterBusBox = masterBusBox;
|
131
|
+
this.masterAudioUnit = masterAudioUnit;
|
132
|
+
this.timelineBox = timelineBox;
|
133
|
+
this.liveStreamReceiver = this.#terminator.own(new LiveStreamReceiver());
|
134
|
+
this.editing = new Editing(this.boxGraph);
|
135
|
+
this.selection = new VertexSelection(this.editing, this.boxGraph);
|
136
|
+
this.parameterFieldAdapters = new ParameterFieldAdapters();
|
137
|
+
this.boxAdapters = this.#terminator.own(new BoxAdapters(this));
|
138
|
+
this.userEditingManager = new UserEditingManager(this.editing);
|
139
|
+
this.userEditingManager.follow(this.userInterfaceBox);
|
140
|
+
this.selection.switch(this.userInterfaceBox.selection);
|
141
|
+
this.mixer = new Mixer(this.rootBoxAdapter.audioUnits);
|
142
|
+
console.debug(`Project was created on ${this.rootBoxAdapter.created.toString()}`);
|
143
|
+
}
|
144
|
+
own(terminable) { return this.#terminator.own(terminable); }
|
145
|
+
ownAll(...terminables) { return this.#terminator.ownAll(...terminables); }
|
146
|
+
spawn() { return this.#terminator.spawn(); }
|
147
|
+
get bpm() { return this.timelineBox.bpm.getValue(); }
|
148
|
+
get rootBoxAdapter() { return this.boxAdapters.adapterFor(this.rootBox, RootBoxAdapter); }
|
149
|
+
get timelineBoxAdapter() { return this.boxAdapters.adapterFor(this.timelineBox, TimelineBoxAdapter); }
|
150
|
+
get audioManager() { return this.#env.audioManager; }
|
151
|
+
get clipSequencing() { return panic("Only available in audio context"); }
|
152
|
+
get isAudioContext() { return false; }
|
153
|
+
get isMainThread() { return true; }
|
154
|
+
get liveStreamBroadcaster() { return panic("Only available in audio context"); }
|
155
|
+
toArrayBuffer() {
|
156
|
+
const output = ByteArrayOutput.create();
|
157
|
+
output.writeInt(ProjectDecoder.MAGIC_HEADER_OPEN);
|
158
|
+
output.writeInt(ProjectDecoder.FORMAT_VERSION);
|
159
|
+
// store all boxes
|
160
|
+
const boxGraphChunk = this.boxGraph.toArrayBuffer();
|
161
|
+
output.writeInt(boxGraphChunk.byteLength);
|
162
|
+
output.writeBytes(new Int8Array(boxGraphChunk));
|
163
|
+
// store mandatory boxes' addresses
|
164
|
+
UUID.toDataOutput(output, this.rootBox.address.uuid);
|
165
|
+
UUID.toDataOutput(output, this.userInterfaceBox.address.uuid);
|
166
|
+
UUID.toDataOutput(output, this.masterBusBox.address.uuid);
|
167
|
+
UUID.toDataOutput(output, this.masterAudioUnit.address.uuid);
|
168
|
+
UUID.toDataOutput(output, this.timelineBox.address.uuid);
|
169
|
+
return output.toArrayBuffer();
|
170
|
+
}
|
171
|
+
copy() { return Project.load(this.#env, this.toArrayBuffer()); }
|
172
|
+
terminate() { this.#terminator.terminate(); }
|
173
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ProjectEnv.d.ts","sourceRoot":"","sources":["../src/ProjectEnv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAA;AAE3D,MAAM,WAAW,UAAU;IACvB,YAAY,EAAE,kBAAkB,CAAA;CACnC"}
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { int } from "@opendaw/lib-std";
|
2
|
+
import { WorkletFactory } from "./WorkletFactory";
|
3
|
+
export declare class RecordingWorklet extends AudioWorkletNode {
|
4
|
+
#private;
|
5
|
+
static bootFactory(context: BaseAudioContext, url: string): Promise<WorkletFactory<RecordingWorklet>>;
|
6
|
+
static create(factory: WorkletFactory<RecordingWorklet>, numChannels: int, numChunks?: int): RecordingWorklet;
|
7
|
+
private constructor();
|
8
|
+
}
|
9
|
+
//# sourceMappingURL=RecordingWorklet.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"RecordingWorklet.d.ts","sourceRoot":"","sources":["../src/RecordingWorklet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAG/C,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAK/C,qBAAa,gBAAiB,SAAQ,gBAAgB;;WACrC,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;IAI3G,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,gBAAgB,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,GAAE,GAAQ,GAAG,gBAAgB;IAUjH,OAAO;CAuBV"}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { EmptyExec } from "@opendaw/lib-std";
|
2
|
+
import { Files } from "@opendaw/lib-dom";
|
3
|
+
import { mergeChunkPlanes, RingBuffer } from "@opendaw/studio-adapters";
|
4
|
+
import { WorkletFactory } from "./WorkletFactory";
|
5
|
+
import { encodeWavFloat } from "./Wav";
|
6
|
+
const RenderQuantum = 128;
|
7
|
+
export class RecordingWorklet extends AudioWorkletNode {
|
8
|
+
static async bootFactory(context, url) {
|
9
|
+
return WorkletFactory.boot(context, url);
|
10
|
+
}
|
11
|
+
static create(factory, numChannels, numChunks = 64) {
|
12
|
+
const audioBytes = numChannels * numChunks * RenderQuantum * Float32Array.BYTES_PER_ELEMENT;
|
13
|
+
const pointerBytes = Int32Array.BYTES_PER_ELEMENT * 2;
|
14
|
+
const sab = new SharedArrayBuffer(audioBytes + pointerBytes);
|
15
|
+
const buffer = { sab, numChunks, numChannels, bufferSize: RenderQuantum };
|
16
|
+
return factory.create(context => new RecordingWorklet(context, buffer));
|
17
|
+
}
|
18
|
+
#reader;
|
19
|
+
constructor(context, config) {
|
20
|
+
super(context, "recording-processor", {
|
21
|
+
numberOfInputs: 1,
|
22
|
+
channelCount: config.numChannels,
|
23
|
+
channelCountMode: "explicit",
|
24
|
+
processorOptions: config
|
25
|
+
});
|
26
|
+
const sampleRate = this.context.sampleRate;
|
27
|
+
const output = [];
|
28
|
+
const seconds = 3.1452;
|
29
|
+
const numFrames = Math.ceil(sampleRate * seconds);
|
30
|
+
console.debug(`numFrames: ${numFrames}`);
|
31
|
+
this.#reader = RingBuffer.reader(config, array => {
|
32
|
+
output.push(array);
|
33
|
+
if (output.length * RenderQuantum >= numFrames) {
|
34
|
+
this.#reader.stop();
|
35
|
+
const channels = mergeChunkPlanes(output, numFrames);
|
36
|
+
const wav = encodeWavFloat({ channels, numFrames, sampleRate });
|
37
|
+
Files.save(wav, { suggestedName: "recording.wav" })
|
38
|
+
.then(() => console.debug("WAV saved"), EmptyExec);
|
39
|
+
}
|
40
|
+
});
|
41
|
+
}
|
42
|
+
}
|
package/dist/Wav.d.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"Wav.d.ts","sourceRoot":"","sources":["../src/Wav.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,GAAI,OAAO;IAClC,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAA;CACpB,GAAG,WAAW,KAAG,WA2CjB,CAAA"}
|
package/dist/Wav.js
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
import { Arrays } from "@opendaw/lib-std";
|
2
|
+
export const encodeWavFloat = (audio) => {
|
3
|
+
const MAGIC_RIFF = 0x46464952;
|
4
|
+
const MAGIC_WAVE = 0x45564157;
|
5
|
+
const MAGIC_FMT = 0x20746d66;
|
6
|
+
const MAGIC_DATA = 0x61746164;
|
7
|
+
const bytesPerChannel = Float32Array.BYTES_PER_ELEMENT;
|
8
|
+
const sampleRate = audio.sampleRate;
|
9
|
+
let numFrames;
|
10
|
+
let numberOfChannels;
|
11
|
+
let channels;
|
12
|
+
if (audio instanceof AudioBuffer) {
|
13
|
+
channels = Arrays.create(index => audio.getChannelData(index), audio.numberOfChannels);
|
14
|
+
numFrames = audio.length;
|
15
|
+
numberOfChannels = audio.numberOfChannels;
|
16
|
+
}
|
17
|
+
else {
|
18
|
+
channels = audio.channels;
|
19
|
+
numFrames = audio.numFrames;
|
20
|
+
numberOfChannels = audio.channels.length;
|
21
|
+
}
|
22
|
+
const size = 44 + numFrames * numberOfChannels * bytesPerChannel;
|
23
|
+
const buf = new ArrayBuffer(size);
|
24
|
+
const view = new DataView(buf);
|
25
|
+
view.setUint32(0, MAGIC_RIFF, true);
|
26
|
+
view.setUint32(4, size - 8, true);
|
27
|
+
view.setUint32(8, MAGIC_WAVE, true);
|
28
|
+
view.setUint32(12, MAGIC_FMT, true);
|
29
|
+
view.setUint32(16, 16, true); // chunk length
|
30
|
+
view.setUint16(20, 3, true); // compression
|
31
|
+
view.setUint16(22, numberOfChannels, true);
|
32
|
+
view.setUint32(24, sampleRate, true);
|
33
|
+
view.setUint32(28, sampleRate * numberOfChannels * bytesPerChannel, true);
|
34
|
+
view.setUint16(32, numberOfChannels * bytesPerChannel, true);
|
35
|
+
view.setUint16(34, 8 * bytesPerChannel, true);
|
36
|
+
view.setUint32(36, MAGIC_DATA, true);
|
37
|
+
view.setUint32(40, numberOfChannels * numFrames * bytesPerChannel, true);
|
38
|
+
let w = 44;
|
39
|
+
for (let i = 0; i < numFrames; ++i) {
|
40
|
+
for (let j = 0; j < numberOfChannels; ++j) {
|
41
|
+
view.setFloat32(w, channels[j][i], true);
|
42
|
+
w += bytesPerChannel;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
return view.buffer;
|
46
|
+
};
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { Func } from "@opendaw/lib-std";
|
2
|
+
export declare class WorkletFactory<W extends AudioWorkletNode> {
|
3
|
+
#private;
|
4
|
+
static boot<W extends AudioWorkletNode>(context: BaseAudioContext, moduleURL: string): Promise<WorkletFactory<W>>;
|
5
|
+
constructor(context: BaseAudioContext);
|
6
|
+
create(factory: Func<BaseAudioContext, W>): W;
|
7
|
+
}
|
8
|
+
//# sourceMappingURL=WorkletFactory.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"WorkletFactory.d.ts","sourceRoot":"","sources":["../src/WorkletFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAGrC,qBAAa,cAAc,CAAC,CAAC,SAAS,gBAAgB;;IAClD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,EACzB,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;gBAM1E,OAAO,EAAE,gBAAgB;IAErC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,GAAG,CAAC;CAChD"}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { Promises } from "@opendaw/lib-runtime";
|
2
|
+
export class WorkletFactory {
|
3
|
+
static boot(context, moduleURL) {
|
4
|
+
return Promises.retry(() => context.audioWorklet.addModule(moduleURL).then(() => new WorkletFactory(context)));
|
5
|
+
}
|
6
|
+
#context;
|
7
|
+
constructor(context) { this.#context = context; }
|
8
|
+
create(factory) { return factory(this.#context); }
|
9
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { int } from "@opendaw/lib-std";
|
2
|
+
import { ExportStemsConfiguration } from "@opendaw/studio-adapters";
|
3
|
+
import { WorkletFactory } from "./WorkletFactory";
|
4
|
+
import { EngineWorklet } from "./EngineWorklet";
|
5
|
+
import { MeterWorklet } from "./MeterWorklet";
|
6
|
+
import { RecordingWorklet } from "./RecordingWorklet";
|
7
|
+
import { Project } from "./Project";
|
8
|
+
export type WorkletUrls = {
|
9
|
+
meter: string;
|
10
|
+
engine: string;
|
11
|
+
recording: string;
|
12
|
+
};
|
13
|
+
export declare class Worklets {
|
14
|
+
#private;
|
15
|
+
static install(context: AudioContext, { engine, meter, recording }: WorkletUrls): Promise<Worklets>;
|
16
|
+
static get(context: AudioContext): Worklets;
|
17
|
+
constructor(engine: WorkletFactory<EngineWorklet>, meter: WorkletFactory<MeterWorklet>, recording: WorkletFactory<RecordingWorklet>);
|
18
|
+
createMeter(numberOfChannels: int): MeterWorklet;
|
19
|
+
createEngine(project: Project, exportConfiguration?: ExportStemsConfiguration): EngineWorklet;
|
20
|
+
createRecording(numberOfChannels: int, numChunks: int): RecordingWorklet;
|
21
|
+
}
|
22
|
+
//# sourceMappingURL=Worklets.d.ts.map
|
@@ -0,0 +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,EAAC,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,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;AAEjC,MAAM,MAAM,WAAW,GAAG;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,qBAAa,QAAQ;;WACJ,OAAO,CAAC,OAAO,EAAE,YAAY,EAAE,EAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IAYvG,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,QAAQ;gBAQ/B,MAAM,EAAE,cAAc,CAAC,aAAa,CAAC,EACrC,KAAK,EAAE,cAAc,CAAC,YAAY,CAAC,EACnC,SAAS,EAAE,cAAc,CAAC,gBAAgB,CAAC;IAMvD,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;CAG3E"}
|
package/dist/Worklets.js
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
import { asDefined } from "@opendaw/lib-std";
|
2
|
+
import { EngineWorklet } from "./EngineWorklet";
|
3
|
+
import { MeterWorklet } from "./MeterWorklet";
|
4
|
+
import { RecordingWorklet } from "./RecordingWorklet";
|
5
|
+
export class Worklets {
|
6
|
+
static async install(context, { engine, meter, recording }) {
|
7
|
+
return Promise.all([
|
8
|
+
EngineWorklet.bootFactory(context, engine),
|
9
|
+
MeterWorklet.bootFactory(context, meter),
|
10
|
+
RecordingWorklet.bootFactory(context, recording)
|
11
|
+
]).then(([engine, meter, recording]) => {
|
12
|
+
const worklets = new Worklets(engine, meter, recording);
|
13
|
+
this.#map.set(context, worklets);
|
14
|
+
return worklets;
|
15
|
+
});
|
16
|
+
}
|
17
|
+
static get(context) { return asDefined(this.#map.get(context), "Worklets not installed"); }
|
18
|
+
static #map = new WeakMap();
|
19
|
+
#meter;
|
20
|
+
#engine;
|
21
|
+
#recording;
|
22
|
+
constructor(engine, meter, recording) {
|
23
|
+
this.#meter = meter;
|
24
|
+
this.#engine = engine;
|
25
|
+
this.#recording = recording;
|
26
|
+
}
|
27
|
+
createMeter(numberOfChannels) {
|
28
|
+
return MeterWorklet.create(this.#meter, numberOfChannels);
|
29
|
+
}
|
30
|
+
createEngine(project, exportConfiguration) {
|
31
|
+
return this.#engine.create(context => new EngineWorklet(context, project, exportConfiguration));
|
32
|
+
}
|
33
|
+
createRecording(numberOfChannels, numChunks) {
|
34
|
+
return RecordingWorklet.create(this.#recording, numberOfChannels, numChunks);
|
35
|
+
}
|
36
|
+
}
|