@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.
Files changed (62) hide show
  1. package/dist/EffectBox.d.ts +2 -2
  2. package/dist/EffectBox.d.ts.map +1 -1
  3. package/dist/EffectFactories.d.ts +3 -0
  4. package/dist/EffectFactories.d.ts.map +1 -1
  5. package/dist/EffectFactories.js +30 -3
  6. package/dist/EffectFactory.d.ts +2 -7
  7. package/dist/EffectFactory.d.ts.map +1 -1
  8. package/dist/Engine.d.ts +3 -5
  9. package/dist/Engine.d.ts.map +1 -1
  10. package/dist/EngineFacade.d.ts +3 -5
  11. package/dist/EngineFacade.d.ts.map +1 -1
  12. package/dist/EngineFacade.js +10 -9
  13. package/dist/EngineWorklet.d.ts +2 -4
  14. package/dist/EngineWorklet.d.ts.map +1 -1
  15. package/dist/EngineWorklet.js +6 -18
  16. package/dist/RecordingWorklet.d.ts.map +1 -1
  17. package/dist/RecordingWorklet.js +7 -10
  18. package/dist/StudioPreferences.d.ts +21 -0
  19. package/dist/StudioPreferences.d.ts.map +1 -0
  20. package/dist/StudioPreferences.js +3 -0
  21. package/dist/StudioSettings.d.ts +24 -0
  22. package/dist/StudioSettings.d.ts.map +1 -0
  23. package/dist/StudioSettings.js +22 -0
  24. package/dist/WavFile.js +4 -3
  25. package/dist/capture/CaptureAudio.js +5 -5
  26. package/dist/dawproject/DawProjectExporter.test.js +1 -0
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -1
  30. package/dist/processors.js +35 -18
  31. package/dist/processors.js.map +4 -4
  32. package/dist/project/Project.d.ts.map +1 -1
  33. package/dist/project/Project.js +39 -18
  34. package/dist/project/ProjectMigration.d.ts.map +1 -1
  35. package/dist/project/ProjectMigration.js +41 -1
  36. package/dist/samples/DefaultSampleLoader.d.ts +5 -3
  37. package/dist/samples/DefaultSampleLoader.d.ts.map +1 -1
  38. package/dist/samples/DefaultSampleLoader.js +21 -82
  39. package/dist/samples/{DefaultSampleLoaderManager.d.ts → GlobalSampleLoaderManager.d.ts} +4 -3
  40. package/dist/samples/GlobalSampleLoaderManager.d.ts.map +1 -0
  41. package/dist/samples/GlobalSampleLoaderManager.js +146 -0
  42. package/dist/samples/OpenSampleAPI.d.ts +1 -2
  43. package/dist/samples/OpenSampleAPI.d.ts.map +1 -1
  44. package/dist/samples/OpenSampleAPI.js +22 -26
  45. package/dist/samples/SampleAPI.d.ts +1 -1
  46. package/dist/samples/SampleAPI.d.ts.map +1 -1
  47. package/dist/samples/SampleService.d.ts.map +1 -1
  48. package/dist/samples/SampleService.js +5 -7
  49. package/dist/samples/SampleStorage.d.ts +0 -1
  50. package/dist/samples/SampleStorage.d.ts.map +1 -1
  51. package/dist/samples/SampleStorage.js +0 -1
  52. package/dist/samples/index.d.ts +1 -1
  53. package/dist/samples/index.d.ts.map +1 -1
  54. package/dist/samples/index.js +1 -1
  55. package/dist/workers-main.js +1 -1
  56. package/dist/workers-main.js.map +3 -3
  57. package/package.json +15 -15
  58. package/dist/Preferences.d.ts +0 -32
  59. package/dist/Preferences.d.ts.map +0 -1
  60. package/dist/Preferences.js +0 -52
  61. package/dist/samples/DefaultSampleLoaderManager.d.ts.map +0 -1
  62. package/dist/samples/DefaultSampleLoaderManager.js +0 -35
@@ -1 +1 @@
1
- {"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"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"}
@@ -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 = Preferences.values["auto-create-output-compressor"];
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 engine = lifecycle.own(this.#env.audioWorklets.createEngine({ project: this, options }));
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
- engine.removeEventListener("error", handler);
101
- engine.removeEventListener("processorerror", handler);
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
- engine.addEventListener("error", handler);
107
- engine.addEventListener("processorerror", handler);
108
- engine.connect(engine.context.destination);
109
- this.engine.setWorklet(engine);
110
- return engine;
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
- console.debug("Project terminated");
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":"AAsBA,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;CAuPpF"}
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(manager: DefaultSampleLoaderManager, uuid: UUID.Bytes);
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,EAIH,QAAQ,EACR,MAAM,EAEN,YAAY,EAEZ,IAAI,EACP,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAC,KAAK,EAAc,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAC,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAExF,OAAO,EAAC,0BAA0B,EAAC,MAAM,8BAA8B,CAAA;AAEvE,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,qBAAa,mBAAoB,YAAW,YAAY;;gBAYxC,OAAO,EAAE,0BAA0B,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK;IAQjE,UAAU,IAAI,IAAI;IASlB,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,QAAQ,IAAI,MAAM;CAuErB"}
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 { ByteArrayInput, Notifier, Option, Progress, Terminable, UUID } from "@opendaw/lib-std";
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
- #version = 0;
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
- toString() { return `{MainThreadSampleLoader}`; }
42
- #setState(value) {
43
- this.#state = value;
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
- #get() {
47
- let version = this.#version;
48
- SampleStorage.get().load(this.#uuid).then(([data, peaks, meta]) => {
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
- async #fetch() {
68
- let version = this.#version;
69
- const [fetchProgress, peakProgress] = Progress.split(progress => this.#setState({
70
- type: "progress",
71
- progress: 0.1 + 0.9 * progress
72
- }), 2);
73
- const fetchResult = await Promises.tryCatch(this.#manager.fetch(this.#uuid, fetchProgress));
74
- if (this.#version !== version) {
75
- return;
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 DefaultSampleLoaderManager implements SampleLoaderManager, SampleProvider {
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=DefaultSampleLoaderManager.d.ts.map
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(context: AudioContext, uuid: UUID.Bytes, progress: Procedure<unitValue>): Promise<[AudioData, Sample]>;
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,EAMH,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;AAG1C,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,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS;IAStD,OAAO;IAGD,GAAG,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAKrC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAQtC,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAmC3G,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAoC/E,YAAY,IAAI,OAAO;CAC1B"}
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 { Arrays, asDefined, DefaultObservableValue, Lazy, panic, RuntimeNotifier, tryCatch, UUID } from "@opendaw/lib-std";
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 sample = await Promises.retry(() => network.limitFetch(url, OpenDAWHeaders)
36
- .then(x => x.json().then(x => Sample.parse(x))))
37
- .then(x => { if ("error" in x) {
38
- return panic(x.error);
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
- else {
41
- return x;
42
- } });
36
+ const sample = Sample.parse(json);
43
37
  return Object.freeze({ ...sample, origin: "openDAW" });
44
38
  }
45
- async load(context, uuid, progress) {
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 => context.decodeAudioData(arrayBuffer))
71
- .then(audioBuffer => ([OpenSampleAPI.fromAudioBuffer(audioBuffer), {
72
- uuid,
73
- bpm,
74
- name,
75
- duration: audioBuffer.duration,
76
- sample_rate: audioBuffer.sampleRate,
77
- origin: "openDAW"
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(context: AudioContext, uuid: UUID.Bytes, progress: Procedure<unitValue>): Promise<[AudioData, Sample]>;
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,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3G,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzE,YAAY,IAAI,OAAO,CAAA;CAC1B"}
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;cAqC5C,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;CAKpE"}
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"}