smplr 0.22.0 → 0.23.0

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/index.mjs CHANGED
@@ -25,6 +25,14 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
25
25
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
26
26
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
27
27
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
28
+ var __privateWrapper = (obj, member, setter, getter) => ({
29
+ set _(value) {
30
+ __privateSet(obj, member, value, setter);
31
+ },
32
+ get _() {
33
+ return __privateGet(obj, member, getter);
34
+ }
35
+ });
28
36
  var __async = (__this, __arguments, generator) => {
29
37
  return new Promise((resolve, reject) => {
30
38
  var fulfilled = (value) => {
@@ -878,11 +886,12 @@ var EMPTY_JSON = {
878
886
  function isSmplrJson(x) {
879
887
  return typeof x === "object" && x !== null && "groups" in x && Array.isArray(x.groups);
880
888
  }
881
- var _loadProgress, _buffers, _reversedBuffers, _defaults, _defaultVelocity, _aliases, _matcher, _voices2, _channel, _onLoadProgress, _onStart, _onEnded, _ccState, _disposed, _SmplrImpl_instances, assertNotDisposed_fn, getBuffer_fn, playNote_fn, normalizeNoteEvent_fn;
889
+ var _loadProgress, _loadToken, _buffers, _reversedBuffers, _defaults, _defaultVelocity, _aliases, _matcher, _voices2, _channel, _onLoadProgress, _onStart, _onEnded, _ccState, _disposed, _SmplrImpl_instances, assertNotDisposed_fn, getBuffer_fn, playNote_fn, normalizeNoteEvent_fn;
882
890
  var SmplrImpl = class {
883
891
  constructor(context, jsonOrOptions, maybeOptions) {
884
892
  __privateAdd(this, _SmplrImpl_instances);
885
893
  __privateAdd(this, _loadProgress, { loaded: 0, total: 0 });
894
+ __privateAdd(this, _loadToken, 0);
886
895
  __privateAdd(this, _buffers, /* @__PURE__ */ new Map());
887
896
  __privateAdd(this, _reversedBuffers, /* @__PURE__ */ new Map());
888
897
  __privateAdd(this, _defaults);
@@ -945,17 +954,18 @@ var SmplrImpl = class {
945
954
  this.ready = p;
946
955
  }
947
956
  /**
948
- * Load (or replace) the instrument descriptor. Creates a new RegionMatcher
949
- * and fetches all sample buffers. Pre-loaded buffers (e.g. base64-decoded)
950
- * can be passed via the `buffers` parameter — those skip the fetch step.
957
+ * Load (or replace) the instrument descriptor. All state (matcher, defaults,
958
+ * aliases, reversed-buffer cache, sample buffers) swaps atomically when the
959
+ * load resolves. Concurrent calls are serialized: only the latest call's
960
+ * result is committed; earlier in-flight calls resolve but do not mutate
961
+ * state.
951
962
  *
952
- * Returns a Promise that resolves when all samples are ready.
963
+ * Pre-loaded buffers (e.g. base64-decoded) can be passed via the `buffers`
964
+ * parameter — those skip the fetch step.
953
965
  */
954
966
  loadInstrument(json, buffers) {
955
967
  __privateMethod(this, _SmplrImpl_instances, assertNotDisposed_fn).call(this, "load an instrument");
956
- __privateSet(this, _defaults, json.defaults);
957
- __privateSet(this, _aliases, json.aliases ? new Map(Object.entries(json.aliases)) : void 0);
958
- __privateSet(this, _matcher, new RegionMatcher(json));
968
+ const token = ++__privateWrapper(this, _loadToken)._;
959
969
  return this.loader.load(json, {
960
970
  buffers,
961
971
  onProgress: (loaded, total) => {
@@ -964,6 +974,11 @@ var SmplrImpl = class {
964
974
  (_a = __privateGet(this, _onLoadProgress)) == null ? void 0 : _a.call(this, { loaded, total });
965
975
  }
966
976
  }).then((newBuffers) => {
977
+ if (token !== __privateGet(this, _loadToken)) return;
978
+ __privateSet(this, _defaults, json.defaults);
979
+ __privateSet(this, _aliases, json.aliases ? new Map(Object.entries(json.aliases)) : void 0);
980
+ __privateSet(this, _matcher, new RegionMatcher(json));
981
+ __privateSet(this, _reversedBuffers, /* @__PURE__ */ new Map());
967
982
  __privateSet(this, _buffers, newBuffers);
968
983
  });
969
984
  }
@@ -1050,6 +1065,7 @@ var SmplrImpl = class {
1050
1065
  }
1051
1066
  };
1052
1067
  _loadProgress = new WeakMap();
1068
+ _loadToken = new WeakMap();
1053
1069
  _buffers = new WeakMap();
1054
1070
  _reversedBuffers = new WeakMap();
1055
1071
  _defaults = new WeakMap();
@@ -1311,12 +1327,12 @@ var DrumMachine = Instrument(
1311
1327
  const instrumentPromise = isDrumMachineInstrument(config.instrument) ? Promise.resolve(config.instrument) : fetchDrumMachineInstrument(config.url, config.storage);
1312
1328
  const ready = instrumentPromise.then((inst) => {
1313
1329
  instrument = inst;
1314
- return smplr.loadInstrument(drumMachineToSmplrJson(inst));
1330
+ return smplr.loadInstrument(drumMachineToPreset(inst));
1315
1331
  });
1316
1332
  return { extras, ready };
1317
1333
  }
1318
1334
  );
1319
- function drumMachineToSmplrJson(instrument) {
1335
+ function drumMachineToPreset(instrument) {
1320
1336
  const aliases = {};
1321
1337
  const regions = [];
1322
1338
  const BASE_MIDI = 36;
@@ -2188,7 +2204,7 @@ var Sequencer = class {
2188
2204
  };
2189
2205
 
2190
2206
  // src/smplr/sfz-convert.ts
2191
- function sfzToSmplrJson(sfzText, options) {
2207
+ function sfzToPreset(sfzText, options) {
2192
2208
  var _a;
2193
2209
  const formats = (_a = options.formats) != null ? _a : ["ogg", "m4a"];
2194
2210
  const tokens = tokenize(resolveDefines(sfzText));
@@ -2498,7 +2514,7 @@ var ElectricPiano = Instrument(
2498
2514
  (sfzText) => {
2499
2515
  var _a;
2500
2516
  return smplr.loadInstrument(
2501
- sfzToSmplrJson(sfzText, {
2517
+ sfzToPreset(sfzText, {
2502
2518
  baseUrl: config.baseUrl,
2503
2519
  pathFromSampleName: config.pathFromSampleName,
2504
2520
  formats: (_a = options.formats) != null ? _a : ["ogg", "m4a"]
@@ -2533,7 +2549,7 @@ function loadVersilianInstrument(smplr, options) {
2533
2549
  const sampleBaseUrl = `${VCSL_BASE_URL}/${base}`;
2534
2550
  return fetch(sfzUrl).then((r) => r.text()).then(
2535
2551
  (sfzText) => smplr.loadInstrument(
2536
- sfzToSmplrJson(sfzText, {
2552
+ sfzToPreset(sfzText, {
2537
2553
  baseUrl: sampleBaseUrl,
2538
2554
  pathFromSampleName: (name) => name.replace(/\.wav$/i, ""),
2539
2555
  formats: ["ogg", "m4a"]
@@ -2638,7 +2654,7 @@ var Mellotron = Instrument(
2638
2654
  const baseUrl = `https://smpldsnds.github.io/archiveorg-mellotron/${instrumentName}/`;
2639
2655
  return fetch(baseUrl + "files.json").then((r) => r.json()).then(
2640
2656
  (names) => smplr.loadInstrument(
2641
- mellotronToSmplrJson(names, {
2657
+ mellotronToPreset(names, {
2642
2658
  instrument: instrumentName,
2643
2659
  variation: variation == null ? void 0 : variation[1]
2644
2660
  })
@@ -2646,7 +2662,7 @@ var Mellotron = Instrument(
2646
2662
  );
2647
2663
  }
2648
2664
  );
2649
- function mellotronToSmplrJson(sampleNames, config) {
2665
+ function mellotronToPreset(sampleNames, config) {
2650
2666
  var _a;
2651
2667
  const entries = [];
2652
2668
  for (const sampleName of sampleNames) {
@@ -2758,11 +2774,24 @@ _ready = new WeakMap();
2758
2774
  _output = new WeakMap();
2759
2775
 
2760
2776
  // src/sampler.ts
2777
+ function isSmplrPreset(x) {
2778
+ return typeof x === "object" && x !== null && "groups" in x && Array.isArray(x.groups);
2779
+ }
2761
2780
  var Sampler = Instrument(
2762
2781
  (ctx, options = {}, smplr) => {
2763
2782
  var _a, _b;
2764
2783
  const storage = (_a = options.storage) != null ? _a : HttpStorage;
2765
- return getSource(ctx, (_b = options.buffers) != null ? _b : {}).then((source) => buildSamplerBuffers(source, ctx, storage, options)).then(({ json, buffers }) => smplr.loadInstrument(json, buffers));
2784
+ const loadFromInput = (input) => {
2785
+ if (isSmplrPreset(input)) {
2786
+ return smplr.loadInstrument(input);
2787
+ }
2788
+ return getSource(ctx, input).then((source) => buildSamplerBuffers(source, ctx, storage, options)).then(({ json, buffers }) => smplr.loadInstrument(json, buffers));
2789
+ };
2790
+ const initialInput = "preset" in options && options.preset ? options.preset : (_b = options.buffers) != null ? _b : {};
2791
+ return {
2792
+ extras: { reload: loadFromInput },
2793
+ ready: loadFromInput(initialInput)
2794
+ };
2766
2795
  }
2767
2796
  );
2768
2797
  function getSource(ctx, raw) {
@@ -2776,7 +2805,7 @@ function getSource(ctx, raw) {
2776
2805
  }
2777
2806
  function buildSamplerBuffers(source, context, storage, options) {
2778
2807
  return __async(this, null, function* () {
2779
- const { json, urlMap, preloaded } = samplerToSmplrJson(source, options);
2808
+ const { json, urlMap, preloaded } = samplerToPreset(source, options);
2780
2809
  yield Promise.all(
2781
2810
  Object.entries(urlMap).map((_0) => __async(null, [_0], function* ([name, url]) {
2782
2811
  const buffer = yield loadAudioBuffer(context, url, storage);
@@ -2786,7 +2815,7 @@ function buildSamplerBuffers(source, context, storage, options) {
2786
2815
  return { json, buffers: preloaded };
2787
2816
  });
2788
2817
  }
2789
- function samplerToSmplrJson(source, options = {}) {
2818
+ function samplerToPreset(source, options = {}) {
2790
2819
  const keys = Object.keys(source);
2791
2820
  const preloaded = /* @__PURE__ */ new Map();
2792
2821
  const urlMap = {};
@@ -2885,7 +2914,7 @@ var Smolken = Instrument(
2885
2914
  const sfzUrl = getSmolkenUrl((_a = options.instrument) != null ? _a : "Arco");
2886
2915
  return fetch(sfzUrl).then((r) => r.text()).then(
2887
2916
  (sfzText) => smplr.loadInstrument(
2888
- sfzToSmplrJson(sfzText, {
2917
+ sfzToPreset(sfzText, {
2889
2918
  baseUrl: SMOLKEN_BASE_URL,
2890
2919
  pathFromSampleName: (name) => name.replace(/\\/g, "/").replace(/\.wav$/i, ""),
2891
2920
  formats: ["ogg", "m4a"]
@@ -3076,10 +3105,7 @@ var Soundfont = Instrument(
3076
3105
  gain.gain.value = config.extraGain;
3077
3106
  smplr.output.addInsert(gain);
3078
3107
  return loadSoundfontData(ctx, config).then(
3079
- ({ buffers, noteNames, loopData }) => smplr.loadInstrument(
3080
- soundfontToSmplrJson(noteNames, loopData),
3081
- buffers
3082
- )
3108
+ ({ buffers, noteNames, loopData }) => smplr.loadInstrument(soundfontToPreset(noteNames, loopData), buffers)
3083
3109
  );
3084
3110
  }
3085
3111
  );
@@ -3119,7 +3145,7 @@ function decodeSoundfontFile(context, config) {
3119
3145
  return { buffers, noteNames: [...buffers.keys()] };
3120
3146
  });
3121
3147
  }
3122
- function soundfontToSmplrJson(noteNames, loopData) {
3148
+ function soundfontToPreset(noteNames, loopData) {
3123
3149
  const entries = [];
3124
3150
  for (const noteName of noteNames) {
3125
3151
  const midi = toMidi(noteName);
@@ -3212,7 +3238,7 @@ function base64ToArrayBuffer(base64) {
3212
3238
  }
3213
3239
 
3214
3240
  // src/soundfont2.ts
3215
- function sf2InstrumentToSmplrJson(sf2Instrument, context) {
3241
+ function sf2InstrumentToPreset(sf2Instrument, context) {
3216
3242
  const buffers = /* @__PURE__ */ new Map();
3217
3243
  const regions = [];
3218
3244
  for (const zone of sf2Instrument.zones) {
@@ -3260,7 +3286,7 @@ var Soundfont2Sampler = Instrument(
3260
3286
  (inst) => inst.header.name === instrumentName
3261
3287
  );
3262
3288
  if (!sf2inst) return void 0;
3263
- const { json, buffers } = sf2InstrumentToSmplrJson(sf2inst, ctx);
3289
+ const { json, buffers } = sf2InstrumentToPreset(sf2inst, ctx);
3264
3290
  return baseLoadInstrument(json, buffers);
3265
3291
  }
3266
3292
  };
@@ -3292,9 +3318,9 @@ var DEFAULTS = {
3292
3318
  decayTime: 0.5
3293
3319
  };
3294
3320
  var SplendidGrandPiano = Instrument(
3295
- (ctx, options = {}, smplr) => smplr.loadInstrument(pianoToSmplrJson(__spreadValues(__spreadValues({}, DEFAULTS), options)))
3321
+ (ctx, options = {}, smplr) => smplr.loadInstrument(pianoToPreset(__spreadValues(__spreadValues({}, DEFAULTS), options)))
3296
3322
  );
3297
- function pianoToSmplrJson(options) {
3323
+ function pianoToPreset(options) {
3298
3324
  var _a;
3299
3325
  const { notesToLoad } = options;
3300
3326
  const layers = notesToLoad ? LAYERS.filter(
@@ -3690,7 +3716,7 @@ export {
3690
3716
  Versilian,
3691
3717
  audioBufferToWav,
3692
3718
  audioBufferToWav16,
3693
- drumMachineToSmplrJson,
3719
+ drumMachineToPreset,
3694
3720
  getDrumMachineNames,
3695
3721
  getElectricPianoNames,
3696
3722
  getMalletNames,
@@ -3700,12 +3726,12 @@ export {
3700
3726
  getSoundfontNames,
3701
3727
  getVersilianInstruments,
3702
3728
  loadVersilianInstrument,
3703
- mellotronToSmplrJson,
3704
- pianoToSmplrJson,
3729
+ mellotronToPreset,
3730
+ pianoToPreset,
3705
3731
  renderOffline,
3706
- samplerToSmplrJson,
3707
- sf2InstrumentToSmplrJson,
3708
- soundfontToSmplrJson,
3732
+ samplerToPreset,
3733
+ sf2InstrumentToPreset,
3734
+ soundfontToPreset,
3709
3735
  trimSilence
3710
3736
  };
3711
3737
  //# sourceMappingURL=index.mjs.map