@opendaw/studio-core 0.0.85 → 0.0.86
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/EffectBox.d.ts +2 -2
- package/dist/EffectBox.d.ts.map +1 -1
- package/dist/EffectFactories.d.ts +3 -0
- package/dist/EffectFactories.d.ts.map +1 -1
- package/dist/EffectFactories.js +30 -3
- package/dist/EffectFactory.d.ts +2 -7
- package/dist/EffectFactory.d.ts.map +1 -1
- package/dist/Engine.d.ts +3 -5
- package/dist/Engine.d.ts.map +1 -1
- package/dist/EngineFacade.d.ts +3 -5
- package/dist/EngineFacade.d.ts.map +1 -1
- package/dist/EngineFacade.js +10 -9
- package/dist/EngineWorklet.d.ts +2 -4
- package/dist/EngineWorklet.d.ts.map +1 -1
- package/dist/EngineWorklet.js +6 -18
- package/dist/RecordingWorklet.d.ts.map +1 -1
- package/dist/RecordingWorklet.js +7 -10
- package/dist/StudioPreferences.d.ts +21 -0
- package/dist/StudioPreferences.d.ts.map +1 -0
- package/dist/StudioPreferences.js +3 -0
- package/dist/StudioSettings.d.ts +24 -0
- package/dist/StudioSettings.d.ts.map +1 -0
- package/dist/StudioSettings.js +22 -0
- package/dist/WavFile.js +4 -3
- package/dist/capture/CaptureAudio.js +5 -5
- package/dist/dawproject/DawProjectExporter.test.js +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/processors.js +35 -18
- package/dist/processors.js.map +4 -4
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +39 -18
- package/dist/project/ProjectMigration.d.ts.map +1 -1
- package/dist/project/ProjectMigration.js +41 -1
- package/dist/samples/DefaultSampleLoader.d.ts +5 -3
- package/dist/samples/DefaultSampleLoader.d.ts.map +1 -1
- package/dist/samples/DefaultSampleLoader.js +21 -82
- package/dist/samples/{DefaultSampleLoaderManager.d.ts → GlobalSampleLoaderManager.d.ts} +4 -3
- package/dist/samples/GlobalSampleLoaderManager.d.ts.map +1 -0
- package/dist/samples/GlobalSampleLoaderManager.js +146 -0
- package/dist/samples/OpenSampleAPI.d.ts +1 -2
- package/dist/samples/OpenSampleAPI.d.ts.map +1 -1
- package/dist/samples/OpenSampleAPI.js +22 -26
- package/dist/samples/SampleAPI.d.ts +1 -1
- package/dist/samples/SampleAPI.d.ts.map +1 -1
- package/dist/samples/SampleService.d.ts.map +1 -1
- package/dist/samples/SampleService.js +5 -7
- package/dist/samples/SampleStorage.d.ts +0 -1
- package/dist/samples/SampleStorage.d.ts.map +1 -1
- package/dist/samples/SampleStorage.js +0 -1
- package/dist/samples/index.d.ts +1 -1
- package/dist/samples/index.d.ts.map +1 -1
- package/dist/samples/index.js +1 -1
- package/dist/workers-main.js +1 -1
- package/dist/workers-main.js.map +3 -3
- package/package.json +15 -15
- package/dist/Preferences.d.ts +0 -32
- package/dist/Preferences.d.ts.map +0 -1
- package/dist/Preferences.js +0 -52
- package/dist/samples/DefaultSampleLoaderManager.d.ts.map +0 -1
- package/dist/samples/DefaultSampleLoaderManager.js +0 -35
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,IAAI,EAEJ,SAAS,
|
|
1
|
+
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,IAAI,EAEJ,SAAS,EAGT,UAAU,EACV,eAAe,EACf,UAAU,EACV,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,UAAU,EAAE,QAAQ,EAA0B,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EACH,WAAW,EAGX,YAAY,EACZ,KAAK,EAEL,OAAO,EACP,WAAW,EAEX,gBAAgB,EACnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACH,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAEhB,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAElB,kBAAkB,EAElB,eAAe,EAClB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,qBAAqB,EAAE,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AAC7E,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AACvC,OAAO,EAAC,KAAK,EAAC,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAEvC,OAAO,EAAC,cAAc,EAAY,MAAM,YAAY,CAAA;AACpD,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAc,YAAY,EAAC,MAAM,SAAS,CAAA;AAEjD,OAAO,EAAC,QAAQ,EAAW,MAAM,kBAAkB,CAAA;AAInD,MAAM,MAAM,cAAc,GAAG;IAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,CAAA;CAAE,CAAA;AAExG,MAAM,MAAM,oBAAoB,GAAG;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAGD,qBAAa,OAAQ,YAAW,kBAAkB,EAAE,UAAU,EAAE,eAAe;;IAC3E,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO;IAYpE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO;WAIlD,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAOxF,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,GAAE,OAAc,GAAG,OAAO;IAWzG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAE1C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,kBAAkB,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAA;IAC5D,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAA;IAClC,QAAQ,CAAC,eAAe,EAAE,YAAY,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IAEjC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;IACxB,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAA;IACvC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAA;IAC/C,QAAQ,CAAC,sBAAsB,EAAE,sBAAsB,CAAA;IACvD,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAA;IAC/C,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,MAAM,eAAqB;IAEpC,OAAO;IA+CP,iBAAiB,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa;IAoBtF,cAAc,CAAC,OAAO,GAAE,OAAc;IAMtC,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI;IAMnC,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;IAC3C,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,GAAG,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI;IAC5D,KAAK,IAAI,UAAU;IAEnB,IAAI,GAAG,IAAI,UAAU,CAAmB;IACxC,IAAI,cAAc,IAAI,cAAc,CAAmE;IACvG,IAAI,kBAAkB,IAAI,kBAAkB,CAA2E;IACvH,IAAI,aAAa,IAAI,mBAAmB,CAAiC;IACzE,IAAI,gBAAgB,IAAI,sBAAsB,CAAoC;IAClF,IAAI,cAAc,IAAI,cAAc,CAAkD;IACtF,IAAI,cAAc,IAAI,OAAO,CAAe;IAC5C,IAAI,YAAY,IAAI,OAAO,CAAc;IACzC,IAAI,qBAAqB,IAAI,qBAAqB,CAAkD;IAEpG,IAAI,QAAQ,IAAI,eAAe,CAW9B;IAED,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAe9F,kBAAkB,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;IAM/C,gBAAgB,IAAI,IAAI;IAaxB,aAAa,IAAI,eAAe;IAEhC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO;IAIxC,OAAO,IAAI,OAAO;IAmBlB,SAAS,IAAI,IAAI;CAcpB"}
|
package/dist/project/Project.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Arrays, panic, safeExecute, Terminator } from "@opendaw/lib-std";
|
|
2
|
-
import { BoxEditing } from "@opendaw/lib-box";
|
|
3
|
-
import { AudioRegionBox } from "@opendaw/studio-boxes";
|
|
1
|
+
import { Arrays, panic, safeExecute, Terminator, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { BoxEditing, DeleteUpdate, NewUpdate } from "@opendaw/lib-box";
|
|
3
|
+
import { AudioFileBox, AudioRegionBox } from "@opendaw/studio-boxes";
|
|
4
4
|
import { BoxAdapters, ParameterFieldAdapters, ProjectSkeleton, RootBoxAdapter, TimelineBoxAdapter, UnionBoxTypes, UserEditingManager, VaryingTempoMap, VertexSelection } from "@opendaw/studio-adapters";
|
|
5
5
|
import { LiveStreamReceiver } from "@opendaw/lib-fusion";
|
|
6
6
|
import { Mixer } from "../Mixer";
|
|
@@ -10,14 +10,14 @@ import { CaptureDevices, Recording } from "../capture";
|
|
|
10
10
|
import { EngineFacade } from "../EngineFacade";
|
|
11
11
|
import { MidiDevices, MIDILearning } from "../midi";
|
|
12
12
|
import { ProjectValidation } from "./ProjectValidation";
|
|
13
|
-
import { Preferences } from "../Preferences";
|
|
14
13
|
import { TimeBase } from "@opendaw/lib-dsp";
|
|
15
14
|
import { MidiData } from "@opendaw/lib-midi";
|
|
15
|
+
import { StudioPreferences } from "../StudioPreferences";
|
|
16
16
|
// Main Entry Point for a Project
|
|
17
17
|
export class Project {
|
|
18
18
|
static new(env, options) {
|
|
19
19
|
const createDefaultUser = options?.noDefaultUser !== true;
|
|
20
|
-
const createOutputCompressor =
|
|
20
|
+
const createOutputCompressor = StudioPreferences.settings["auto-create-output-compressor"];
|
|
21
21
|
const { boxGraph, mandatoryBoxes } = ProjectSkeleton.empty({
|
|
22
22
|
createOutputCompressor,
|
|
23
23
|
createDefaultUser
|
|
@@ -46,6 +46,7 @@ export class Project {
|
|
|
46
46
|
return project;
|
|
47
47
|
}
|
|
48
48
|
#terminator = new Terminator();
|
|
49
|
+
#sampleRegistrations;
|
|
49
50
|
#env;
|
|
50
51
|
boxGraph;
|
|
51
52
|
rootBox;
|
|
@@ -84,30 +85,42 @@ export class Project {
|
|
|
84
85
|
this.midiLearning = this.#terminator.own(new MIDILearning(this));
|
|
85
86
|
this.captureDevices = this.#terminator.own(new CaptureDevices(this));
|
|
86
87
|
this.mixer = new Mixer(this.rootBoxAdapter.audioUnits);
|
|
87
|
-
// TODO We are probably doing that from the outside
|
|
88
|
-
if (this.userInterfaceBoxes.length === 1) {
|
|
89
|
-
this.follow(this.userInterfaceBoxes[0]);
|
|
90
|
-
}
|
|
91
88
|
console.debug(`Project was created on ${this.rootBoxAdapter.created.toString()}`);
|
|
89
|
+
this.#sampleRegistrations = UUID.newSet(({ uuid }) => uuid);
|
|
90
|
+
for (const box of this.boxGraph.boxes()) {
|
|
91
|
+
if (box instanceof AudioFileBox) {
|
|
92
|
+
this.#registerSample(box.address.uuid);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
this.#terminator.own(this.boxGraph.subscribeToAllUpdates({
|
|
96
|
+
onUpdate: (update) => {
|
|
97
|
+
if (update instanceof NewUpdate && update.name === AudioFileBox.ClassName) {
|
|
98
|
+
this.#registerSample(update.uuid);
|
|
99
|
+
}
|
|
100
|
+
else if (update instanceof DeleteUpdate && update.name === AudioFileBox.ClassName) {
|
|
101
|
+
this.#unregisterSample(update.uuid);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
92
105
|
}
|
|
93
106
|
startAudioWorklet(restart, options) {
|
|
94
107
|
console.debug(`start AudioWorklet`);
|
|
95
108
|
const lifecycle = this.#terminator.spawn();
|
|
96
|
-
const
|
|
109
|
+
const worklet = lifecycle.own(this.#env.audioWorklets.createEngine({ project: this, options }));
|
|
97
110
|
const handler = async (event) => {
|
|
98
111
|
console.warn(event);
|
|
99
112
|
// we will only accept the first error
|
|
100
|
-
|
|
101
|
-
|
|
113
|
+
worklet.removeEventListener("error", handler);
|
|
114
|
+
worklet.removeEventListener("processorerror", handler);
|
|
102
115
|
lifecycle.terminate();
|
|
103
116
|
await safeExecute(restart?.unload, event);
|
|
104
117
|
safeExecute(restart?.load, this.startAudioWorklet(restart));
|
|
105
118
|
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.engine.setWorklet(
|
|
110
|
-
return
|
|
119
|
+
worklet.addEventListener("error", handler);
|
|
120
|
+
worklet.addEventListener("processorerror", handler);
|
|
121
|
+
worklet.connect(worklet.context.destination);
|
|
122
|
+
this.engine.setWorklet(worklet);
|
|
123
|
+
return worklet;
|
|
111
124
|
}
|
|
112
125
|
startRecording(countIn = true) {
|
|
113
126
|
this.engine.assertWorklet();
|
|
@@ -200,7 +213,15 @@ export class Project {
|
|
|
200
213
|
}) ?? false);
|
|
201
214
|
}
|
|
202
215
|
terminate() {
|
|
203
|
-
|
|
216
|
+
this.#sampleRegistrations.forEach(({ terminable }) => terminable.terminate());
|
|
217
|
+
this.#sampleRegistrations.clear();
|
|
204
218
|
this.#terminator.terminate();
|
|
205
219
|
}
|
|
220
|
+
#registerSample(uuid) {
|
|
221
|
+
const terminable = this.sampleManager.register(uuid);
|
|
222
|
+
this.#sampleRegistrations.add({ uuid, terminable });
|
|
223
|
+
}
|
|
224
|
+
#unregisterSample(uuid) {
|
|
225
|
+
this.#sampleRegistrations.removeByKey(uuid).terminable.terminate();
|
|
226
|
+
}
|
|
206
227
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectMigration.d.ts","sourceRoot":"","sources":["../../src/project/ProjectMigration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProjectMigration.d.ts","sourceRoot":"","sources":["../../src/project/ProjectMigration.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAC,eAAe,EAAC,MAAM,0BAA0B,CAAA;AAIxD,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AASvC,qBAAa,gBAAgB;WACZ,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,EAAC,QAAQ,EAAE,cAAc,EAAC,EAAE,eAAe;CA8RpF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AudioFileBox, AudioPitchStretchBox, CaptureAudioBox, CaptureMidiBox, GrooveShuffleBox, MIDIOutputBox, ValueEventCollectionBox, ValueEventCurveBox } from "@opendaw/studio-boxes";
|
|
2
|
-
import { asDefined, asInstanceOf, clamp, Float, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { asDefined, asInstanceOf, clamp, Float, isDefined, UUID } from "@opendaw/lib-std";
|
|
3
3
|
import { AudioPlayback, AudioUnitType } from "@opendaw/studio-enums";
|
|
4
4
|
import { PPQN, TimeBase } from "@opendaw/lib-dsp";
|
|
5
5
|
import { AudioContentHelpers } from "./audio/AudioContentHelpers";
|
|
@@ -254,6 +254,46 @@ export class ProjectMigration {
|
|
|
254
254
|
box.version.setValue(2);
|
|
255
255
|
boxGraph.endTransaction();
|
|
256
256
|
}
|
|
257
|
+
},
|
|
258
|
+
visitDelayDeviceBox: (box) => {
|
|
259
|
+
// Version 0: old descending array (17 values)
|
|
260
|
+
// Version 1: new ascending array with off (21 values)
|
|
261
|
+
if (box.version.getValue() !== 0) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
// Old descending: 1/1, 1/2, 1/3, 1/4, 3/16, 1/6, 1/8, 3/32, 1/12, 1/16, 3/64, 1/24, 1/32, 1/48, 1/64, 1/96, 1/128
|
|
265
|
+
// New ascending: off, 1/128, 1/96, 1/64, 1/48, 1/32, 1/24, 3/64, 1/16, 1/12, 3/32, 1/8, 1/6, 3/16, 1/4, 5/16, 1/3, 3/8, 7/16, 1/2, 1/1
|
|
266
|
+
// Mapping: old[i] fraction -> find the same fraction in the new array
|
|
267
|
+
const oldToNewIndex = [20, 19, 16, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
|
|
268
|
+
const oldMaxIndex = 16;
|
|
269
|
+
const newMaxIndex = 20;
|
|
270
|
+
const oldIndex = box.delayMusical.getValue();
|
|
271
|
+
const newIndex = oldToNewIndex[Math.round(clamp(oldIndex, 0, oldMaxIndex))];
|
|
272
|
+
console.debug(`Migrate 'DelayDeviceBox' delay index from ${oldIndex} to ${newIndex}`);
|
|
273
|
+
boxGraph.beginTransaction();
|
|
274
|
+
box.delayMusical.setValue(newIndex);
|
|
275
|
+
box.delayMillis.setValue(0);
|
|
276
|
+
box.preSyncTimeLeft.setValue(0);
|
|
277
|
+
box.preMillisTimeLeft.setValue(0);
|
|
278
|
+
box.preSyncTimeRight.setValue(0);
|
|
279
|
+
box.preMillisTimeRight.setValue(0);
|
|
280
|
+
box.version.setValue(1);
|
|
281
|
+
// Migrate automation events targeting the delay field
|
|
282
|
+
// Automation stores normalized values in [0, 1] range
|
|
283
|
+
box.delayMusical.pointerHub.incoming().forEach(pointer => {
|
|
284
|
+
const eventBox = pointer.box.accept({
|
|
285
|
+
visitValueEventBox: (event) => event
|
|
286
|
+
});
|
|
287
|
+
if (isDefined(eventBox)) {
|
|
288
|
+
const oldNormalized = eventBox.value.getValue();
|
|
289
|
+
const oldEventIndex = Math.round(oldNormalized * oldMaxIndex);
|
|
290
|
+
const newEventIndex = oldToNewIndex[clamp(oldEventIndex, 0, oldMaxIndex)];
|
|
291
|
+
const newNormalized = newEventIndex / newMaxIndex;
|
|
292
|
+
console.debug(` Migrate automation: ${oldNormalized.toFixed(4)} (idx ${oldEventIndex}) -> ${newNormalized.toFixed(4)} (idx ${newEventIndex})`);
|
|
293
|
+
eventBox.value.setValue(newNormalized);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
boxGraph.endTransaction();
|
|
257
297
|
}
|
|
258
298
|
}));
|
|
259
299
|
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { Observer, Option, Subscription, UUID } from "@opendaw/lib-std";
|
|
2
2
|
import { Peaks } from "@opendaw/lib-fusion";
|
|
3
3
|
import { SampleLoader, SampleLoaderState, SampleMetaData } from "@opendaw/studio-adapters";
|
|
4
|
-
import { DefaultSampleLoaderManager } from "./DefaultSampleLoaderManager";
|
|
5
4
|
import { AudioData } from "@opendaw/lib-dsp";
|
|
6
5
|
export declare class DefaultSampleLoader implements SampleLoader {
|
|
7
6
|
#private;
|
|
8
|
-
constructor(
|
|
9
|
-
invalidate(): void;
|
|
7
|
+
constructor(uuid: UUID.Bytes);
|
|
10
8
|
subscribe(observer: Observer<SampleLoaderState>): Subscription;
|
|
11
9
|
get uuid(): UUID.Bytes;
|
|
12
10
|
get data(): Option<AudioData>;
|
|
13
11
|
get meta(): Option<SampleMetaData>;
|
|
14
12
|
get peaks(): Option<Peaks>;
|
|
15
13
|
get state(): SampleLoaderState;
|
|
14
|
+
setLoaded(data: AudioData, peaks: Peaks, meta: SampleMetaData): void;
|
|
15
|
+
setProgress(progress: number): void;
|
|
16
|
+
setError(reason: string): void;
|
|
17
|
+
invalidate(): void;
|
|
16
18
|
toString(): string;
|
|
17
19
|
}
|
|
18
20
|
//# sourceMappingURL=DefaultSampleLoader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultSampleLoader.d.ts","sourceRoot":"","sources":["../../src/samples/DefaultSampleLoader.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"DefaultSampleLoader.d.ts","sourceRoot":"","sources":["../../src/samples/DefaultSampleLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAc,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAC3F,OAAO,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAA;AACzC,OAAO,EAAC,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AACxF,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,qBAAa,mBAAoB,YAAW,YAAY;;gBASxC,IAAI,EAAE,IAAI,CAAC,KAAK;IAK5B,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,YAAY;IAQ9D,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,CAAoB;IAC1C,IAAI,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAoB;IACjD,IAAI,IAAI,IAAI,MAAM,CAAC,cAAc,CAAC,CAAoB;IACtD,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAqB;IAC/C,IAAI,KAAK,IAAI,iBAAiB,CAAqB;IAEnD,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI;IAQpE,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK9B,UAAU,IAAI,IAAI;IAQlB,QAAQ,IAAI,MAAM;CACrB"}
|
|
@@ -1,30 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Promises } from "@opendaw/lib-runtime";
|
|
3
|
-
import { SamplePeaks } from "@opendaw/lib-fusion";
|
|
4
|
-
import { Workers } from "../Workers";
|
|
5
|
-
import { SampleStorage } from "./SampleStorage";
|
|
1
|
+
import { Notifier, Option, Terminable, UUID } from "@opendaw/lib-std";
|
|
6
2
|
export class DefaultSampleLoader {
|
|
7
|
-
#manager;
|
|
8
3
|
#uuid;
|
|
9
4
|
#notifier;
|
|
10
5
|
#meta = Option.None;
|
|
11
6
|
#data = Option.None;
|
|
12
7
|
#peaks = Option.None;
|
|
13
8
|
#state = { type: "progress", progress: 0.0 };
|
|
14
|
-
|
|
15
|
-
constructor(manager, uuid) {
|
|
16
|
-
this.#manager = manager;
|
|
9
|
+
constructor(uuid) {
|
|
17
10
|
this.#uuid = uuid;
|
|
18
11
|
this.#notifier = new Notifier();
|
|
19
|
-
this.#get();
|
|
20
|
-
}
|
|
21
|
-
invalidate() {
|
|
22
|
-
this.#state = { type: "progress", progress: 0.0 };
|
|
23
|
-
this.#meta = Option.None;
|
|
24
|
-
this.#data = Option.None;
|
|
25
|
-
this.#peaks = Option.None;
|
|
26
|
-
this.#version++;
|
|
27
|
-
this.#get();
|
|
28
12
|
}
|
|
29
13
|
subscribe(observer) {
|
|
30
14
|
if (this.#state.type === "loaded" || this.#state.type === "error") {
|
|
@@ -38,72 +22,27 @@ export class DefaultSampleLoader {
|
|
|
38
22
|
get meta() { return this.#meta; }
|
|
39
23
|
get peaks() { return this.#peaks; }
|
|
40
24
|
get state() { return this.#state; }
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.#
|
|
25
|
+
setLoaded(data, peaks, meta) {
|
|
26
|
+
this.#data = Option.wrap(data);
|
|
27
|
+
this.#peaks = Option.wrap(peaks);
|
|
28
|
+
this.#meta = Option.wrap(meta);
|
|
29
|
+
this.#state = { type: "loaded" };
|
|
44
30
|
this.#notifier.notify(this.#state);
|
|
45
31
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (this.#version !== version) {
|
|
50
|
-
console.warn(`Ignore obsolete version: ${this.#version} / ${version}`);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
this.#data = Option.wrap(data);
|
|
54
|
-
this.#meta = Option.wrap(meta);
|
|
55
|
-
this.#peaks = Option.wrap(peaks);
|
|
56
|
-
this.#setState({ type: "loaded" });
|
|
57
|
-
}, (error) => {
|
|
58
|
-
if (error instanceof Error && error.message.startsWith("timeoout")) {
|
|
59
|
-
this.#setState({ type: "error", reason: error.message });
|
|
60
|
-
return console.warn(`Sample ${UUID.toString(this.#uuid)} timed out.`);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
return this.#fetch();
|
|
64
|
-
}
|
|
65
|
-
});
|
|
32
|
+
setProgress(progress) {
|
|
33
|
+
this.#state = { type: "progress", progress };
|
|
34
|
+
this.#notifier.notify(this.#state);
|
|
66
35
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (fetchResult.status === "rejected") {
|
|
78
|
-
const error = fetchResult.error;
|
|
79
|
-
console.warn(error);
|
|
80
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
81
|
-
this.#setState({ type: "error", reason });
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const [audio, meta] = fetchResult.value;
|
|
85
|
-
const shifts = SamplePeaks.findBestFit(audio.numberOfFrames);
|
|
86
|
-
const peaks = await Workers.Peak.generateAsync(peakProgress, shifts, audio.frames, audio.numberOfFrames, audio.numberOfChannels);
|
|
87
|
-
const storeResult = await Promises.tryCatch(SampleStorage.get().save({
|
|
88
|
-
uuid: this.#uuid,
|
|
89
|
-
audio: audio,
|
|
90
|
-
peaks: peaks,
|
|
91
|
-
meta: meta
|
|
92
|
-
}));
|
|
93
|
-
if (this.#version !== version) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (storeResult.status === "resolved") {
|
|
97
|
-
this.#data = Option.wrap(audio);
|
|
98
|
-
this.#meta = Option.wrap(meta);
|
|
99
|
-
this.#peaks = Option.wrap(SamplePeaks.from(new ByteArrayInput(peaks)));
|
|
100
|
-
this.#setState({ type: "loaded" });
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
const error = storeResult.error;
|
|
104
|
-
console.warn(error);
|
|
105
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
106
|
-
this.#setState({ type: "error", reason });
|
|
107
|
-
}
|
|
36
|
+
setError(reason) {
|
|
37
|
+
this.#state = { type: "error", reason };
|
|
38
|
+
this.#notifier.notify(this.#state);
|
|
39
|
+
}
|
|
40
|
+
invalidate() {
|
|
41
|
+
this.#state = { type: "progress", progress: 0.0 };
|
|
42
|
+
this.#meta = Option.None;
|
|
43
|
+
this.#data = Option.None;
|
|
44
|
+
this.#peaks = Option.None;
|
|
45
|
+
this.#notifier.notify(this.#state);
|
|
108
46
|
}
|
|
47
|
+
toString() { return `{DefaultSampleLoader ${UUID.toString(this.#uuid)}}`; }
|
|
109
48
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { Progress, UUID } from "@opendaw/lib-std";
|
|
1
|
+
import { Progress, Terminable, UUID } from "@opendaw/lib-std";
|
|
2
2
|
import { SampleProvider } from "./SampleProvider";
|
|
3
3
|
import { SampleLoader, SampleLoaderManager, SampleMetaData } from "@opendaw/studio-adapters";
|
|
4
4
|
import { AudioData } from "@opendaw/lib-dsp";
|
|
5
|
-
export declare class
|
|
5
|
+
export declare class GlobalSampleLoaderManager implements SampleLoaderManager, SampleProvider {
|
|
6
6
|
#private;
|
|
7
7
|
constructor(provider: SampleProvider);
|
|
8
8
|
fetch(uuid: UUID.Bytes, progress: Progress.Handler): Promise<[AudioData, SampleMetaData]>;
|
|
9
9
|
remove(uuid: UUID.Bytes): void;
|
|
10
10
|
invalidate(uuid: UUID.Bytes): void;
|
|
11
|
+
register(uuid: UUID.Bytes): Terminable;
|
|
11
12
|
record(loader: SampleLoader): void;
|
|
12
13
|
getOrCreate(uuid: UUID.Bytes): SampleLoader;
|
|
13
14
|
getAudioData(uuid: UUID.Bytes): Promise<AudioData>;
|
|
14
15
|
}
|
|
15
|
-
//# sourceMappingURL=
|
|
16
|
+
//# sourceMappingURL=GlobalSampleLoaderManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalSampleLoaderManager.d.ts","sourceRoot":"","sources":["../../src/samples/GlobalSampleLoaderManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,QAAQ,EAA2B,UAAU,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAEzG,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAC1F,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAuB1C,qBAAa,yBAA0B,YAAW,mBAAmB,EAAE,cAAc;;gBAOrE,QAAQ,EAAE,cAAc;IAQpC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAIzF,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI;IAO9B,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI;IAWlC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,UAAU;IAuBtC,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAIlC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,YAAY;IAQrC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC;CA8E3D"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { ByteArrayInput, Progress, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { DefaultSampleLoader } from "./DefaultSampleLoader";
|
|
3
|
+
import { SampleStorage } from "./SampleStorage";
|
|
4
|
+
import { SamplePeaks } from "@opendaw/lib-fusion";
|
|
5
|
+
import { Workers } from "../Workers";
|
|
6
|
+
import { Promises } from "@opendaw/lib-runtime";
|
|
7
|
+
export class GlobalSampleLoaderManager {
|
|
8
|
+
#provider;
|
|
9
|
+
#loaders;
|
|
10
|
+
#refCounts;
|
|
11
|
+
#cache;
|
|
12
|
+
#pending;
|
|
13
|
+
constructor(provider) {
|
|
14
|
+
this.#provider = provider;
|
|
15
|
+
this.#loaders = UUID.newSet(({ uuid }) => uuid);
|
|
16
|
+
this.#refCounts = UUID.newSet(({ uuid }) => uuid);
|
|
17
|
+
this.#cache = UUID.newSet(({ uuid }) => uuid);
|
|
18
|
+
this.#pending = UUID.newSet(({ uuid }) => uuid);
|
|
19
|
+
}
|
|
20
|
+
fetch(uuid, progress) {
|
|
21
|
+
return this.#provider.fetch(uuid, progress);
|
|
22
|
+
}
|
|
23
|
+
remove(uuid) {
|
|
24
|
+
this.#refCounts.removeByKeyIfExist(uuid);
|
|
25
|
+
this.#loaders.removeByKeyIfExist(uuid);
|
|
26
|
+
this.#cache.removeByKeyIfExist(uuid);
|
|
27
|
+
this.#pending.removeByKeyIfExist(uuid);
|
|
28
|
+
}
|
|
29
|
+
invalidate(uuid) {
|
|
30
|
+
this.#cache.removeByKey(uuid);
|
|
31
|
+
this.#pending.removeByKey(uuid);
|
|
32
|
+
this.#loaders.opt(uuid).ifSome(loader => {
|
|
33
|
+
loader.invalidate();
|
|
34
|
+
if (loader instanceof DefaultSampleLoader) {
|
|
35
|
+
this.#load(loader);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
register(uuid) {
|
|
40
|
+
const current = this.#refCounts.opt(uuid);
|
|
41
|
+
if (current.nonEmpty()) {
|
|
42
|
+
current.unwrap().count++;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this.#refCounts.add({ uuid, count: 1 });
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
terminate: () => {
|
|
49
|
+
const ref = this.#refCounts.opt(uuid);
|
|
50
|
+
if (ref.isEmpty()) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const { count } = ref.unwrap();
|
|
54
|
+
if (count <= 1) {
|
|
55
|
+
this.#refCounts.removeByKey(uuid);
|
|
56
|
+
this.#loaders.removeByKeyIfExist(uuid);
|
|
57
|
+
this.#cache.removeByKeyIfExist(uuid);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
ref.unwrap().count--;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
record(loader) {
|
|
66
|
+
this.#loaders.add(loader);
|
|
67
|
+
}
|
|
68
|
+
getOrCreate(uuid) {
|
|
69
|
+
return this.#loaders.getOrCreate(uuid, uuid => {
|
|
70
|
+
const loader = new DefaultSampleLoader(uuid);
|
|
71
|
+
this.#load(loader);
|
|
72
|
+
return loader;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async getAudioData(uuid) {
|
|
76
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
77
|
+
const loader = this.getOrCreate(uuid);
|
|
78
|
+
let subscription;
|
|
79
|
+
subscription = loader.subscribe(state => {
|
|
80
|
+
if (state.type === "error") {
|
|
81
|
+
queueMicrotask(() => subscription.terminate());
|
|
82
|
+
reject(new Error(state.reason));
|
|
83
|
+
}
|
|
84
|
+
else if (loader.data.nonEmpty()) {
|
|
85
|
+
queueMicrotask(() => subscription.terminate());
|
|
86
|
+
resolve(loader.data.unwrap());
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return promise;
|
|
90
|
+
}
|
|
91
|
+
#load(loader) {
|
|
92
|
+
const { uuid } = loader;
|
|
93
|
+
const cached = this.#cache.opt(uuid);
|
|
94
|
+
if (cached.nonEmpty()) {
|
|
95
|
+
const { data, peaks, meta } = cached.unwrap();
|
|
96
|
+
loader.setLoaded(data, peaks, meta);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const pending = this.#pending.opt(uuid);
|
|
100
|
+
if (pending.nonEmpty()) {
|
|
101
|
+
pending.unwrap().promise.then(() => {
|
|
102
|
+
const cached = this.#cache.opt(uuid);
|
|
103
|
+
if (cached.nonEmpty()) {
|
|
104
|
+
const { data, peaks, meta } = cached.unwrap();
|
|
105
|
+
loader.setLoaded(data, peaks, meta);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const promise = SampleStorage.get().load(uuid).then(([data, peaks, meta]) => {
|
|
111
|
+
this.#pending.removeByKey(uuid);
|
|
112
|
+
this.#cache.add({ uuid, data, peaks, meta });
|
|
113
|
+
loader.setLoaded(data, peaks, meta);
|
|
114
|
+
}, () => this.#fetchFromApi(loader).finally(() => this.#pending.removeByKey(uuid))).catch((error) => {
|
|
115
|
+
this.#pending.removeByKey(uuid);
|
|
116
|
+
console.warn("Unexpected error loading sample:", error);
|
|
117
|
+
loader.setError(error instanceof Error ? error.message : String(error));
|
|
118
|
+
});
|
|
119
|
+
this.#pending.add({ uuid, promise });
|
|
120
|
+
}
|
|
121
|
+
async #fetchFromApi(loader) {
|
|
122
|
+
const { uuid } = loader;
|
|
123
|
+
const [fetchProgress, peakProgress] = Progress.split(progress => loader.setProgress(0.1 + 0.9 * progress), 2);
|
|
124
|
+
const fetchResult = await Promises.tryCatch(this.#provider.fetch(uuid, fetchProgress));
|
|
125
|
+
if (fetchResult.status === "rejected") {
|
|
126
|
+
const error = fetchResult.error;
|
|
127
|
+
console.warn(error);
|
|
128
|
+
loader.setError(error instanceof Error ? error.message : String(error));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const [audio, meta] = fetchResult.value;
|
|
132
|
+
const shifts = SamplePeaks.findBestFit(audio.numberOfFrames);
|
|
133
|
+
const peaksBuffer = await Workers.Peak.generateAsync(peakProgress, shifts, audio.frames, audio.numberOfFrames, audio.numberOfChannels);
|
|
134
|
+
const storeResult = await Promises.tryCatch(SampleStorage.get().save({ uuid, audio, peaks: peaksBuffer, meta }));
|
|
135
|
+
if (storeResult.status === "resolved") {
|
|
136
|
+
const peaks = SamplePeaks.from(new ByteArrayInput(peaksBuffer));
|
|
137
|
+
this.#cache.add({ uuid, data: audio, peaks, meta });
|
|
138
|
+
loader.setLoaded(audio, peaks, meta);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const error = storeResult.error;
|
|
142
|
+
console.warn(error);
|
|
143
|
+
loader.setError(error instanceof Error ? error.message : String(error));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -6,11 +6,10 @@ export declare class OpenSampleAPI implements SampleAPI {
|
|
|
6
6
|
static readonly ApiRoot = "https://api.opendaw.studio/samples";
|
|
7
7
|
static readonly FileRoot = "https://assets.opendaw.studio/samples";
|
|
8
8
|
static get(): OpenSampleAPI;
|
|
9
|
-
static fromAudioBuffer(buffer: AudioBuffer): AudioData;
|
|
10
9
|
private constructor();
|
|
11
10
|
all(): Promise<ReadonlyArray<Sample>>;
|
|
12
11
|
get(uuid: UUID.Bytes): Promise<Sample>;
|
|
13
|
-
load(
|
|
12
|
+
load(uuid: UUID.Bytes, progress: Procedure<unitValue>): Promise<[AudioData, Sample]>;
|
|
14
13
|
upload(arrayBuffer: ArrayBuffer, metaData: SampleMetaData): Promise<void>;
|
|
15
14
|
allowsUpload(): boolean;
|
|
16
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenSampleAPI.d.ts","sourceRoot":"","sources":["../../src/samples/OpenSampleAPI.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"OpenSampleAPI.d.ts","sourceRoot":"","sources":["../../src/samples/OpenSampleAPI.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,SAAS,EAGT,SAAS,EACT,IAAI,EACP,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAC,MAAM,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,SAAS,EAAC,MAAM,sBAAsB,CAAA;AAG9C,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAI1C,qBAAa,aAAc,YAAW,SAAS;IAC3C,MAAM,CAAC,QAAQ,CAAC,OAAO,wCAAuC;IAC9D,MAAM,CAAC,QAAQ,CAAC,QAAQ,2CAA0C;IAGlE,MAAM,CAAC,GAAG,IAAI,aAAa;IAE3B,OAAO;IAGD,GAAG,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAKrC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IActC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAqCpF,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAoC/E,YAAY,IAAI,OAAO;CAC1B"}
|
|
@@ -7,24 +7,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
10
|
+
import { asDefined, DefaultObservableValue, Lazy, panic, RuntimeNotifier, tryCatch, UUID } from "@opendaw/lib-std";
|
|
11
11
|
import { network, Promises } from "@opendaw/lib-runtime";
|
|
12
12
|
import { Sample } from "@opendaw/studio-adapters";
|
|
13
13
|
import { base64Credentials, OpenDAWHeaders } from "../OpenDAWHeaders";
|
|
14
14
|
import { z } from "zod";
|
|
15
|
+
import { WavFile } from "../WavFile";
|
|
15
16
|
// Standard openDAW samples (considered to be non-removable)
|
|
16
17
|
export class OpenSampleAPI {
|
|
17
18
|
static ApiRoot = "https://api.opendaw.studio/samples";
|
|
18
19
|
static FileRoot = "https://assets.opendaw.studio/samples";
|
|
19
20
|
static get() { return new OpenSampleAPI(); }
|
|
20
|
-
static fromAudioBuffer(buffer) {
|
|
21
|
-
return {
|
|
22
|
-
frames: Arrays.create(channel => buffer.getChannelData(channel), buffer.numberOfChannels),
|
|
23
|
-
sampleRate: buffer.sampleRate,
|
|
24
|
-
numberOfFrames: buffer.length,
|
|
25
|
-
numberOfChannels: buffer.numberOfChannels
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
21
|
constructor() { }
|
|
29
22
|
async all() {
|
|
30
23
|
return network.defaultFetch(`${OpenSampleAPI.ApiRoot}/list.php`, OpenDAWHeaders)
|
|
@@ -32,17 +25,18 @@ export class OpenSampleAPI {
|
|
|
32
25
|
}
|
|
33
26
|
async get(uuid) {
|
|
34
27
|
const url = `${OpenSampleAPI.ApiRoot}/get.php?uuid=${UUID.toString(uuid)}`;
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
const response = await Promises.retry(() => network.limitFetch(url, OpenDAWHeaders));
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
return panic(`Sample not found: ${UUID.toString(uuid)}`);
|
|
31
|
+
}
|
|
32
|
+
const json = await response.json();
|
|
33
|
+
if ("error" in json) {
|
|
34
|
+
return panic(json.error);
|
|
39
35
|
}
|
|
40
|
-
|
|
41
|
-
return x;
|
|
42
|
-
} });
|
|
36
|
+
const sample = Sample.parse(json);
|
|
43
37
|
return Object.freeze({ ...sample, origin: "openDAW" });
|
|
44
38
|
}
|
|
45
|
-
async load(
|
|
39
|
+
async load(uuid, progress) {
|
|
46
40
|
console.debug(`load ${UUID.toString(uuid)}`);
|
|
47
41
|
return this.get(uuid)
|
|
48
42
|
.then(({ uuid, name, bpm }) => Promises.retry(() => network
|
|
@@ -67,15 +61,17 @@ export class OpenSampleAPI {
|
|
|
67
61
|
reader.read().then(nextChunk, reject);
|
|
68
62
|
});
|
|
69
63
|
})
|
|
70
|
-
.then(arrayBuffer =>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
64
|
+
.then(arrayBuffer => {
|
|
65
|
+
const audioData = WavFile.decodeFloats(arrayBuffer);
|
|
66
|
+
return [audioData, {
|
|
67
|
+
uuid,
|
|
68
|
+
bpm,
|
|
69
|
+
name,
|
|
70
|
+
duration: audioData.numberOfFrames / audioData.sampleRate,
|
|
71
|
+
sample_rate: audioData.sampleRate,
|
|
72
|
+
origin: "openDAW"
|
|
73
|
+
}];
|
|
74
|
+
}));
|
|
79
75
|
}
|
|
80
76
|
async upload(arrayBuffer, metaData) {
|
|
81
77
|
const progress = new DefaultObservableValue(0.0);
|
|
@@ -4,7 +4,7 @@ import { AudioData } from "@opendaw/lib-dsp";
|
|
|
4
4
|
export interface SampleAPI {
|
|
5
5
|
all(): Promise<ReadonlyArray<Sample>>;
|
|
6
6
|
get(uuid: UUID.Bytes): Promise<Sample>;
|
|
7
|
-
load(
|
|
7
|
+
load(uuid: UUID.Bytes, progress: Procedure<unitValue>): Promise<[AudioData, Sample]>;
|
|
8
8
|
upload(arrayBuffer: ArrayBuffer, metaData: SampleMetaData): Promise<void>;
|
|
9
9
|
allowsUpload(): boolean;
|
|
10
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SampleAPI.d.ts","sourceRoot":"","sources":["../../src/samples/SampleAPI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,MAAM,WAAW,SAAS;IACtB,GAAG,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IACrC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACtC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"SampleAPI.d.ts","sourceRoot":"","sources":["../../src/samples/SampleAPI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,MAAM,WAAW,SAAS;IACtB,GAAG,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;IACrC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACtC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IACpF,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzE,YAAY,IAAI,OAAO,CAAA;CAC1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SampleService.d.ts","sourceRoot":"","sources":["../../src/samples/SampleService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAe,SAAS,EAAiB,MAAM,kBAAkB,CAAA;AACtF,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAKpC,OAAO,EAAC,MAAM,EAAiB,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAM5C,qBAAa,aAAc,SAAQ,YAAY,CAAC,MAAM,CAAC;IAMvC,QAAQ,CAAC,YAAY,EAAE,YAAY;IAL/C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAY;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAW;IAClD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAe;IACrD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAiC;gBAEnE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC;IAItE,UAAU,CAAC,EAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,eAAgC,EAAC,EACzD,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"SampleService.d.ts","sourceRoot":"","sources":["../../src/samples/SampleService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAe,SAAS,EAAiB,MAAM,kBAAkB,CAAA;AACtF,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAKpC,OAAO,EAAC,MAAM,EAAiB,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAM5C,qBAAa,aAAc,SAAQ,YAAY,CAAC,MAAM,CAAC;IAMvC,QAAQ,CAAC,YAAY,EAAE,YAAY;IAL/C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAY;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAW;IAClD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAe;IACrD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAiC;gBAEnE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC;IAItE,UAAU,CAAC,EAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,eAAgC,EAAC,EACzD,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;cAmC5C,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;CAKpE"}
|