smplr 0.25.0 → 0.26.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/README.md CHANGED
@@ -71,7 +71,7 @@ Samples are stored at https://github.com/smpldsnds and there is no need to downl
71
71
 
72
72
  #### Using a package manager
73
73
 
74
- Use npm or your favourite package manager to install the library to use it in your project:
74
+ Install with npm or your favourite package manager:
75
75
 
76
76
  ```
77
77
  npm i smplr
@@ -105,29 +105,27 @@ The package needs to be served as a URL from a service like [unpkg](https://unpk
105
105
 
106
106
  `smplr` ships eleven instruments out of the box. Pick one and jump to its section in the [Instrument reference](#instrument-reference) for setup details.
107
107
 
108
- | Instrument | Description | Names helper |
109
- | ------------------------------------------- | ----------------------------------------- | ----------------------------- |
110
- | [`Sampler`](#sampler) | Your own buffers or SFZ-style preset | — |
111
- | [`Soundfont`](#soundfont) | General MIDI soundfonts | `getSoundfontNames()` |
112
- | [`SplendidGrandPiano`](#splendidgrandpiano) | Sampled Steinway grand, 4 velocity layers | — |
113
- | [`ElectricPiano`](#electric-piano) | CP80, PianetT, Wurlitzer, TX81Z | `getElectricPianoNames()` |
114
- | [`DrumMachine`](#drum-machines) | Classic drum machines (TR-808, …) | `getDrumMachineNames()` |
115
- | [`DrumAbuse`](#drumabuse) | ~210 machines (Synthabuse collection) | `getDrumAbuseMachineNames()` |
116
- | [`Mallet`](#mallets) | VCSL mallets | `getMalletNames()` |
117
- | [`Mellotron`](#mellotron) | Mellotron archive samples | `getMellotronNames()` |
118
- | [`Smolken`](#smolken-double-bass) | Smolken double bass (Arco/Pizz/Switched) | `getSmolkenNames()` |
119
- | [`Versilian`](#versilian) | VCSL multi-instrument (partial support) | `getVersilianInstruments()` * |
120
- | [`Soundfont2`](#soundfont2) | Reads .sf2 files directly | — |
108
+ | Instrument | Description | Names helper |
109
+ | ------------------------------------------- | ----------------------------------------- | ---------------------------- |
110
+ | [`Sampler`](#sampler) | Your own buffers or SFZ-style preset | — |
111
+ | [`Soundfont`](#soundfont) | General MIDI soundfonts | `getSoundfontNames()` |
112
+ | [`SplendidGrandPiano`](#splendidgrandpiano) | Sampled Steinway grand, 4 velocity layers | — |
113
+ | [`ElectricPiano`](#electric-piano) | CP80, PianetT, Wurlitzer, TX81Z | `getElectricPianoNames()` |
114
+ | [`DrumMachine`](#drum-machines) | Classic drum machines (TR-808, …) | `getDrumMachineNames()` |
115
+ | [`DrumAbuse`](#drumabuse) | ~210 machines (Synthabuse collection) | `getDrumAbuseMachineNames()` |
116
+ | [`Mallet`](#mallets) | VCSL mallets | `getMalletNames()` |
117
+ | [`Mellotron`](#mellotron) | Mellotron archive samples | `getMellotronNames()` |
118
+ | [`Smolken`](#smolken-double-bass) | Smolken double bass (Arco/Pizz/Switched) | `getSmolkenNames()` |
119
+ | [`Versilian`](#versilian) | VCSL multi-instrument (partial support) | `getVersilianInstruments()` |
120
+ | [`Soundfont2`](#soundfont2) | Reads .sf2 files directly | — |
121
121
 
122
- `*` `getVersilianInstruments` is async because the catalog is fetched from the network on first call (cached thereafter).
122
+ Each names helper returns strings to pass as the factory's `instrument` option. `getVersilianInstruments` is async (the catalog is fetched once and cached).
123
123
 
124
- Each names helper returns the strings you can pass to the corresponding factory's `instrument` option.
125
-
126
- If none of the bundled instruments fits your use case, you can author your own — see [Defining your own instrument](#defining-your-own-instrument).
124
+ To build your own instrument, see [Defining your own instrument](#defining-your-own-instrument).
127
125
 
128
126
  ## Using an instrument
129
127
 
130
- Every smplr instrument follows the same usage pattern. This section covers what's shared across all of them; for instrument-specific options, see the [Instrument reference](#instrument-reference).
128
+ The shared API below applies to every instrument. Instrument-specific options live in the [Instrument reference](#instrument-reference).
131
129
 
132
130
  ### Create and load
133
131
 
@@ -191,13 +189,13 @@ All instruments share some configuration options, passed as the second argument
191
189
 
192
190
  #### Start and stop notes
193
191
 
194
- The `start` function accepts a bunch of options:
192
+ The `start` function accepts these options:
195
193
 
196
194
  ```js
197
195
  piano.start({ note: "C4", velocity: 80, time: 5, duration: 1 });
198
196
  ```
199
197
 
200
- The `velocity` is a number between 0 and 127 the represents at which velocity the key is pressed. The bigger the number, louder the sound. But `velocity` not only controls the loudness. In some instruments, it also affects the timbre.
198
+ `velocity` (0127) represents how hard the key is pressed: louder at higher values, and on some instruments it also changes timbre.
201
199
 
202
200
  The `start` function returns a `stop` function for the given note:
203
201
 
@@ -224,9 +222,9 @@ piano.stop(60); // stop the note(s) started with `note: 60`
224
222
 
225
223
  #### Schedule notes
226
224
 
227
- You can schedule notes using `time` and `duration` properties. Both are measured in seconds. Time is the number of seconds since the AudioContext was created, like in `audioContext.currentTime`
225
+ Schedule notes via the `time` and `duration` properties (both in seconds). `time` is measured against `audioContext.currentTime`.
228
226
 
229
- For example, next example plays a C major arpeggio, one note per second:
227
+ This plays a C major arpeggio, one note per second:
230
228
 
231
229
  ```js
232
230
  const now = context.currentTime;
@@ -318,9 +316,7 @@ piano.output.setEffectMix("reverb", 0.5);
318
316
 
319
317
  ### Events
320
318
 
321
- Two events are supported `onStart` and `onEnded`. Both callbacks will receive as parameter started note.
322
-
323
- Events can be configured globally:
319
+ Two events are available: `onStart` and `onEnded`. Both callbacks receive the started note as a parameter, and can be configured globally:
324
320
 
325
321
  ```js
326
322
  const context = new AudioContext();
@@ -396,7 +392,7 @@ const context = new StandardizedAudioContext() as unknown as AudioContext;
396
392
  const marimba = Soundfont(context, { instrument: "marimba" });
397
393
  ```
398
394
 
399
- In case you need to use the `Reverb` module (or any other module that needs `AudioWorkletNode`) you need to enforce to use the one from `standardized-audio-context` package. Here is how:
395
+ If you use `Reverb` (or anything else that needs `AudioWorkletNode`), force the `standardized-audio-context` version:
400
396
 
401
397
  ```ts
402
398
  import {
@@ -488,13 +484,13 @@ seq.clearTracks(); // remove every track
488
484
 
489
485
  `addTrack`'s third argument accepts:
490
486
 
491
- | Field | Type | Description |
492
- | ---------- | ------------------------------------------- | --------------------------------------------------------------------- |
493
- | `id` | `string` | Stable id for `setTrackVolume` / `muteTrack` / `soloTrack`. |
494
- | `humanize` | `{ timingMs?: number; velocity?: number }` | Per-track humanize. Overrides the sequencer-level setting when set. |
495
- | `volume` | `number` | Multiplicative velocity scalar (default 1). `0.5` halves velocities. |
496
- | `muted` | `boolean` | When true, this track does not dispatch notes. |
497
- | `solo` | `boolean` | When true, only soloed tracks play. |
487
+ | Field | Type | Description |
488
+ | ---------- | ------------------------------------------ | -------------------------------------------------------------------- |
489
+ | `id` | `string` | Stable id for `setTrackVolume` / `muteTrack` / `soloTrack`. |
490
+ | `humanize` | `{ timingMs?: number; velocity?: number }` | Per-track humanize. Overrides the sequencer-level setting when set. |
491
+ | `volume` | `number` | Multiplicative velocity scalar (default 1). `0.5` halves velocities. |
492
+ | `muted` | `boolean` | When true, this track does not dispatch notes. |
493
+ | `solo` | `boolean` | When true, only soloed tracks play. |
498
494
 
499
495
  After `setPatterns` is called (see [Pattern chain](#pattern-chain-song-mode)), `addTrack` / `removeTrack` / `clearTracks` throw — the chain is owned by the patterns array.
500
496
 
@@ -663,22 +659,28 @@ seq.addTrack(piano, notes, { humanize: { timingMs: 0, velocity: 0 } });
663
659
 
664
660
  #### SequencerNote fields
665
661
 
666
- | Field | Type | Description |
667
- | ---------------------- | ------------------- | ---------------------------------------------------------------------------- |
668
- | `note` | `string \| number` | Note name or MIDI number. |
669
- | `at` | `string \| number` | Musical position (ticks or `"bar:beat[.frac][:ticks]"` / `"4n"` / `"1m"`). |
670
- | `duration` | `string \| number?` | Duration; omit for a one-shot trigger. |
671
- | `velocity` | `number?` | Velocity 0–127. Default 100. |
672
- | `id` | `string \| number?` | Used as `noteId` in `noteOn` / `noteOff` events. Default: array index. |
662
+ | Field | Type | Description |
663
+ | ---------------------- | ------------------- | ----------------------------------------------------------------------------- |
664
+ | `note` | `string \| number` | Note name or MIDI number. |
665
+ | `at` | `string \| number` | Musical position (ticks or `"bar:beat[.frac][:ticks]"` / `"4n"` / `"1m"`). |
666
+ | `duration` | `string \| number?` | Duration; omit for a one-shot trigger. |
667
+ | `velocity` | `number?` | Velocity 0–127. Default 100. |
668
+ | `id` | `string \| number?` | Used as `noteId` in `noteOn` / `noteOff` events. Default: array index. |
673
669
  | `chance` | `number?` | Probability 0–100 that this note fires on each pass. Re-rolled on every loop. |
674
- | `ratchet` | `number?` | Expand into N sub-notes over `duration` (requires `duration`). |
675
- | `ratchetVelocityDecay` | `number?` | Per-step velocity decay; each sub-note scaled by `(1 - decay)^i`. |
670
+ | `ratchet` | `number?` | Expand into N sub-notes over `duration` (requires `duration`). |
671
+ | `ratchetVelocityDecay` | `number?` | Per-step velocity decay; each sub-note scaled by `(1 - decay)^i`. |
676
672
 
677
673
  Example:
678
674
 
679
675
  ```js
680
676
  seq.addTrack(drums, [
681
- { note: "hat", at: "1:4", duration: "8n", ratchet: 4, ratchetVelocityDecay: 0.2 },
677
+ {
678
+ note: "hat",
679
+ at: "1:4",
680
+ duration: "8n",
681
+ ratchet: 4,
682
+ ratchetVelocityDecay: 0.2,
683
+ },
682
684
  { note: "snare", at: "1:2", chance: 50 }, // fires 50% of the time
683
685
  ]);
684
686
  ```
@@ -697,7 +699,7 @@ seq.setPatterns([
697
699
  ]);
698
700
 
699
701
  seq.chainOrder = [0, 1, 2, 1, 2]; // intro, verse, chorus, verse, chorus
700
- seq.loop = true; // loop the whole chain
702
+ seq.loop = true; // loop the whole chain
701
703
  seq.start();
702
704
 
703
705
  seq.on("patternChange", (idx) => ui.highlightPattern(idx));
@@ -796,7 +798,7 @@ Detailed configuration for each bundled instrument. For the shared API (load, pl
796
798
 
797
799
  ### Sampler
798
800
 
799
- An audio buffer sampler. Pass a `buffers` object with the files to be load:
801
+ An audio buffer sampler. Pass a `buffers` map of name URL:
800
802
 
801
803
  #### Buffers mode
802
804
 
@@ -816,7 +818,7 @@ And then use the name of the buffer as note name:
816
818
  sampler.start({ note: "kick" });
817
819
  ```
818
820
 
819
- #### Advanced mode
821
+ #### Preset mode
820
822
 
821
823
  For advanced use cases (per-region pitch/velocity/round-robin, SFZ-like multi-sample instruments, runtime swaps), pass a `SmplrPreset` directly:
822
824
 
@@ -843,7 +845,7 @@ sampler.start({ note: 60 });
843
845
  await sampler.reload(kitB);
844
846
  ```
845
847
 
846
- The full `SmplrPreset` schema is documented in [SMPLR_PRESET.md](./SMPLR_PRESET.md). Note: `buffers` and `preset` are mutually exclusive on construction — pass exactly one.
848
+ The full `SmplrPreset` schema is documented in [PRESET_SCHEMA.md](./PRESET_SCHEMA.md). Note: `buffers` and `preset` are mutually exclusive on construction — pass exactly one.
847
849
 
848
850
  `sampler.reload(input)` accepts either shape (flat buffers record or full `SmplrPreset`), regardless of which mode was used at construction.
849
851
 
@@ -1032,10 +1034,10 @@ await drums.load;
1032
1034
  drums.start({ note: "kick" });
1033
1035
 
1034
1036
  // Samples are grouped by instrument name, like DrumMachine:
1035
- drums.getGroupNames(); // => ["kick", "snare", "hi-hat", ...]
1037
+ drums.getGroupNames(); // => ["kick", "snare", "hi-hat", ...]
1036
1038
  drums.getSampleNamesForGroup("kick"); // => ["kick/1", "kick/2", ...]
1037
- drums.start({ note: "kick" }); // first sample in the group
1038
- drums.start({ note: "kick/1" }); // a specific sample
1039
+ drums.start({ note: "kick" }); // first sample in the group
1040
+ drums.start({ note: "kick/1" }); // a specific sample
1039
1041
  ```
1040
1042
 
1041
1043
  If a machine has more than one sample set, pass `set` to pick a specific one. Omit to load the first set.
@@ -1057,8 +1059,8 @@ import {
1057
1059
  getDrumAbuseMachinesForPack,
1058
1060
  } from "smplr";
1059
1061
 
1060
- getDrumAbusePackNames(); // => ["vol1", "vol2", "vol3", "vol4", "vol5"]
1061
- getDrumAbuseMachinesForPack("vol1"); // => machine ids in vol1
1062
+ getDrumAbusePackNames(); // => ["vol1", "vol2", "vol3", "vol4", "vol5"]
1063
+ getDrumAbuseMachinesForPack("vol1"); // => machine ids in vol1
1062
1064
 
1063
1065
  const drums = DrumAbuse(new AudioContext(), {
1064
1066
  source: { kind: "pack", pack: "vol1", instrument: "bass-drum" },
@@ -1079,7 +1081,7 @@ const doubleBass = await Smolken(context, { instrument: "Arco" }).load;
1079
1081
 
1080
1082
  ### Versilian
1081
1083
 
1082
- Versilian is a sample capable of using the [Versilian Community Sample Library](https://github.com/sgossner/VCSL).
1084
+ Plays instruments from the [Versilian Community Sample Library](https://github.com/sgossner/VCSL).
1083
1085
 
1084
1086
  ⚠️ Not all features are implemented. Some instruments may sound incorrect ⚠️
1085
1087
 
@@ -1116,8 +1118,6 @@ sampler.load.then(() => {
1116
1118
  });
1117
1119
  ```
1118
1120
 
1119
- Still limited support. API may vary.
1120
-
1121
1121
  ## Defining your own instrument
1122
1122
 
1123
1123
  If none of the bundled instruments fits your use case, you can author your own with the `Instrument` builder and the `Smplr` interface.
package/dist/index.d.mts CHANGED
@@ -208,68 +208,90 @@ type VoiceParams = {
208
208
  reverse?: boolean;
209
209
  };
210
210
 
211
+ /** Options accepted by `SampleLoader(context, options)`. */
212
+ type SampleLoaderOptions = {
213
+ /** Custom storage backend (e.g. `CacheStorage` for offline). Defaults to `HttpStorage`. */
214
+ storage?: Storage;
215
+ };
216
+ /** Options accepted by `loader.load(json, options)`. */
217
+ type SampleLoaderLoadOptions = {
218
+ /** Pre-decoded buffers keyed by sample name — skip fetch for these. */
219
+ buffers?: Map<string, AudioBuffer>;
220
+ /** Called once per sample (including cache hits) with cumulative progress. */
221
+ onProgress?: (loaded: number, total: number) => void;
222
+ };
223
+ type SampleLoaderFactory = {
224
+ (context: BaseAudioContext, options?: SampleLoaderOptions): SampleLoader;
225
+ /** @deprecated Call as a function: `SampleLoader(...)` instead of `new SampleLoader(...)`. */
226
+ new (context: BaseAudioContext, options?: SampleLoaderOptions): SampleLoader;
227
+ };
211
228
  /**
212
- * Loads and caches AudioBuffers for all samples referenced in a SmplrPreset.
213
- *
214
- * The cache is keyed by resolved URL, so the same audio file is never fetched
215
- * or decoded twice. Multiple Smplr instances can share one SampleLoader by
216
- * passing it via SmplrOptions.loader.
229
+ * Loads and decodes AudioBuffers for the samples referenced by a {@link SmplrPreset}.
230
+ * Used internally by every smplr instrument; pass an instance via
231
+ * {@link SmplrOptions.loader} to share buffer caching across multiple instruments.
217
232
  */
218
- declare class SampleLoaderImpl {
219
- #private;
220
- constructor(context: BaseAudioContext, options?: {
221
- storage?: Storage;
222
- });
233
+ interface SampleLoader {
223
234
  /**
224
- * Load all samples referenced in `json`. Returns a Map of sample name →
225
- * AudioBuffer. Progress is reported via `onProgress` callback or via
226
- * options object.
235
+ * Load all samples referenced by `json`. Returns a Map keyed by sample
236
+ * name (`region.sample`), values are decoded `AudioBuffer`s. Failed
237
+ * samples are silently omitted (callers handle absence at lookup time).
227
238
  *
228
- * - `buffers` in options: pre-loaded buffers skips fetch for these names.
229
- * - All samples load in parallel. Failed samples are silently omitted.
239
+ * Internally cached by resolved URL, so repeated calls with the same
240
+ * baseUrl/format/path do not re-fetch.
241
+ *
242
+ * @param json The preset describing samples to load.
243
+ * @param options
244
+ * - `buffers`: pre-decoded buffers keyed by sample name — skip fetch for these.
245
+ * - `onProgress`: called with `(loaded, total)` per sample (including cache hits).
246
+ */
247
+ load(json: SmplrPreset, options?: SampleLoaderLoadOptions): Promise<Map<string, AudioBuffer>>;
248
+ /**
249
+ * @deprecated Pass `{ onProgress }` instead. The bare-callback form is kept
250
+ * for compatibility; the options form is the canonical 1.x signature.
230
251
  */
231
- load(json: SmplrPreset, onProgressOrOptions?: ((loaded: number, total: number) => void) | {
232
- buffers?: Map<string, AudioBuffer>;
233
- onProgress?: (loaded: number, total: number) => void;
234
- }): Promise<Map<string, AudioBuffer>>;
252
+ load(json: SmplrPreset, onProgress: (loaded: number, total: number) => void): Promise<Map<string, AudioBuffer>>;
235
253
  }
236
- declare const SampleLoader: Constructable<[context: BaseAudioContext, options?: {
237
- storage?: Storage;
238
- } | undefined], SampleLoaderImpl>;
239
- type SampleLoader = ReturnType<typeof SampleLoader>;
254
+ declare const SampleLoader: SampleLoaderFactory;
240
255
 
256
+ /** Options accepted by `Scheduler(context, options)`. */
257
+ type SchedulerOptions = {
258
+ /**
259
+ * How far ahead of `currentTime` events are dispatched synchronously.
260
+ * Defaults to 200ms.
261
+ */
262
+ lookaheadMs?: number;
263
+ /**
264
+ * How often the queue is polled for events ready to dispatch.
265
+ * Defaults to 50ms.
266
+ */
267
+ intervalMs?: number;
268
+ };
269
+ type SchedulerFactory = {
270
+ (context: BaseAudioContext, options?: SchedulerOptions): Scheduler;
271
+ /** @deprecated Call as a function: `Scheduler(...)` instead of `new Scheduler(...)`. */
272
+ new (context: BaseAudioContext, options?: SchedulerOptions): Scheduler;
273
+ };
241
274
  /**
242
- * Standalone scheduler. Dispatches NoteEvents immediately when they fall within the
243
- * lookahead window, or queues them for future dispatch via a self-managing interval.
244
- *
245
- * Multiple Smplr instances can share a single Scheduler for coordinated timing.
275
+ * Schedules note events for future dispatch. Used internally by every smplr
276
+ * instrument; pass an instance via {@link SmplrOptions.scheduler} to share one
277
+ * scheduler across multiple instruments.
246
278
  */
247
- declare class SchedulerImpl {
248
- #private;
249
- constructor(context: BaseAudioContext, options?: {
250
- lookaheadMs?: number;
251
- intervalMs?: number;
252
- });
279
+ interface Scheduler {
253
280
  /**
254
- * Schedule a callback for a NoteEvent.
281
+ * Dispatch `callback` at `event.time`. If `event.time` is within the
282
+ * scheduler's lookahead window (or omitted), the callback fires synchronously
283
+ * and the returned {@link StopFn} is a no-op. Otherwise the event is queued.
255
284
  *
256
- * - If the event's time falls within the lookahead window (or has no time), the
257
- * callback is called synchronously and a no-op StopFn is returned.
258
- * - Otherwise the event is queued, the interval is started if needed, and a StopFn
259
- * is returned that removes the event from the queue before it is dispatched.
285
+ * The returned function removes the event from the queue before dispatch.
260
286
  */
261
287
  schedule(event: NoteEvent, callback: (event: NoteEvent) => void): StopFn;
262
288
  /**
263
- * Clear all queued (not-yet-dispatched) events and stop the interval.
264
- * Does not affect voices that are already playing.
289
+ * Clear all queued (not-yet-dispatched) events and stop the polling
290
+ * interval. Does not affect voices already playing.
265
291
  */
266
292
  stop(): void;
267
293
  }
268
- declare const Scheduler: Constructable<[context: BaseAudioContext, options?: {
269
- lookaheadMs?: number;
270
- intervalMs?: number;
271
- } | undefined], SchedulerImpl>;
272
- type Scheduler = ReturnType<typeof Scheduler>;
294
+ declare const Scheduler: SchedulerFactory;
273
295
 
274
296
  type SmplrOptions = {
275
297
  /** Custom storage backend for sample fetching (e.g. CacheStorage). */
@@ -1273,4 +1295,4 @@ declare const LAYERS: ({
1273
1295
  cutoff?: undefined;
1274
1296
  })[];
1275
1297
 
1276
- export { type AddTrackOptions, CacheStorage, DRUM_ABUSE_PACKS, DrumAbuse, type DrumAbuseConfig, type DrumAbuseExtras, type DrumAbuseOptions, type DrumAbusePackId, type DrumAbuseSource, DrumMachine, type DrumMachineOptions, ElectricPiano, type ElectricPianoOptions, HttpStorage, Instrument, LAYERS, type LoadProgress, Mallet, Mellotron, type MellotronConfig, type MellotronOptions, NAME_TO_PATH, type NoteEvent, type PatternInput, type PlaybackParams, type RenderOfflineOptions, RenderResult, Reverb, SampleLoader, Sampler, type SamplerConfig, type SamplerReloadInput, Scheduler, Sequencer, type SequencerInstrument, type SequencerNote, type SequencerNoteEvent, type SequencerOptions, Smolken, type SmolkenConfig, type SmolkenOptions, type Smplr, type SmplrGroup, type SmplrOptions, type SmplrPlugin, type SmplrPreset, type SmplrRegion, type SmplrSamples, Soundfont, Soundfont2, type Soundfont2Options, Soundfont2Sampler, type SoundfontOptions, SplendidGrandPiano, type SplendidGrandPianoConfig, type StopFn, type StopTarget, type Storage, type StorageResponse, type TimeSignature, Versilian, type VersilianConfig, type VersilianOptions, type VoiceParams, audioBufferToWav, audioBufferToWav16, drumAbuseSampleUrl, drumMachineToPreset, getDrumAbuseMachineNames, getDrumAbuseMachinePack, getDrumAbuseMachinesForPack, getDrumAbusePackNames, getDrumMachineNames, getElectricPianoNames, getMalletNames, getMellotronNames, getSmolkenNames, getSoundfontKits, getSoundfontNames, getVersilianInstruments, loadVersilianInstrument, mellotronToPreset, pianoToPreset, renderOffline, samplerToPreset, sf2InstrumentToPreset, soundfontToPreset, trimSilence };
1298
+ export { type AddTrackOptions, CacheStorage, DRUM_ABUSE_PACKS, DrumAbuse, type DrumAbuseConfig, type DrumAbuseExtras, type DrumAbuseOptions, type DrumAbusePackId, type DrumAbuseSource, DrumMachine, type DrumMachineOptions, ElectricPiano, type ElectricPianoOptions, HttpStorage, Instrument, LAYERS, type LoadProgress, Mallet, Mellotron, type MellotronConfig, type MellotronOptions, NAME_TO_PATH, type NoteEvent, type PatternInput, type PlaybackParams, type RenderOfflineOptions, RenderResult, Reverb, SampleLoader, type SampleLoaderLoadOptions, type SampleLoaderOptions, Sampler, type SamplerConfig, type SamplerReloadInput, Scheduler, type SchedulerOptions, Sequencer, type SequencerInstrument, type SequencerNote, type SequencerNoteEvent, type SequencerOptions, Smolken, type SmolkenConfig, type SmolkenOptions, type Smplr, type SmplrGroup, type SmplrOptions, type SmplrPlugin, type SmplrPreset, type SmplrRegion, type SmplrSamples, Soundfont, Soundfont2, type Soundfont2Options, Soundfont2Sampler, type SoundfontOptions, SplendidGrandPiano, type SplendidGrandPianoConfig, type StopFn, type StopTarget, type Storage, type StorageResponse, type TimeSignature, Versilian, type VersilianConfig, type VersilianOptions, type VoiceParams, audioBufferToWav, audioBufferToWav16, drumAbuseSampleUrl, drumMachineToPreset, getDrumAbuseMachineNames, getDrumAbuseMachinePack, getDrumAbuseMachinesForPack, getDrumAbusePackNames, getDrumMachineNames, getElectricPianoNames, getMalletNames, getMellotronNames, getSmolkenNames, getSoundfontKits, getSoundfontNames, getVersilianInstruments, loadVersilianInstrument, mellotronToPreset, pianoToPreset, renderOffline, samplerToPreset, sf2InstrumentToPreset, soundfontToPreset, trimSilence };
package/dist/index.d.ts CHANGED
@@ -208,68 +208,90 @@ type VoiceParams = {
208
208
  reverse?: boolean;
209
209
  };
210
210
 
211
+ /** Options accepted by `SampleLoader(context, options)`. */
212
+ type SampleLoaderOptions = {
213
+ /** Custom storage backend (e.g. `CacheStorage` for offline). Defaults to `HttpStorage`. */
214
+ storage?: Storage;
215
+ };
216
+ /** Options accepted by `loader.load(json, options)`. */
217
+ type SampleLoaderLoadOptions = {
218
+ /** Pre-decoded buffers keyed by sample name — skip fetch for these. */
219
+ buffers?: Map<string, AudioBuffer>;
220
+ /** Called once per sample (including cache hits) with cumulative progress. */
221
+ onProgress?: (loaded: number, total: number) => void;
222
+ };
223
+ type SampleLoaderFactory = {
224
+ (context: BaseAudioContext, options?: SampleLoaderOptions): SampleLoader;
225
+ /** @deprecated Call as a function: `SampleLoader(...)` instead of `new SampleLoader(...)`. */
226
+ new (context: BaseAudioContext, options?: SampleLoaderOptions): SampleLoader;
227
+ };
211
228
  /**
212
- * Loads and caches AudioBuffers for all samples referenced in a SmplrPreset.
213
- *
214
- * The cache is keyed by resolved URL, so the same audio file is never fetched
215
- * or decoded twice. Multiple Smplr instances can share one SampleLoader by
216
- * passing it via SmplrOptions.loader.
229
+ * Loads and decodes AudioBuffers for the samples referenced by a {@link SmplrPreset}.
230
+ * Used internally by every smplr instrument; pass an instance via
231
+ * {@link SmplrOptions.loader} to share buffer caching across multiple instruments.
217
232
  */
218
- declare class SampleLoaderImpl {
219
- #private;
220
- constructor(context: BaseAudioContext, options?: {
221
- storage?: Storage;
222
- });
233
+ interface SampleLoader {
223
234
  /**
224
- * Load all samples referenced in `json`. Returns a Map of sample name →
225
- * AudioBuffer. Progress is reported via `onProgress` callback or via
226
- * options object.
235
+ * Load all samples referenced by `json`. Returns a Map keyed by sample
236
+ * name (`region.sample`), values are decoded `AudioBuffer`s. Failed
237
+ * samples are silently omitted (callers handle absence at lookup time).
227
238
  *
228
- * - `buffers` in options: pre-loaded buffers skips fetch for these names.
229
- * - All samples load in parallel. Failed samples are silently omitted.
239
+ * Internally cached by resolved URL, so repeated calls with the same
240
+ * baseUrl/format/path do not re-fetch.
241
+ *
242
+ * @param json The preset describing samples to load.
243
+ * @param options
244
+ * - `buffers`: pre-decoded buffers keyed by sample name — skip fetch for these.
245
+ * - `onProgress`: called with `(loaded, total)` per sample (including cache hits).
246
+ */
247
+ load(json: SmplrPreset, options?: SampleLoaderLoadOptions): Promise<Map<string, AudioBuffer>>;
248
+ /**
249
+ * @deprecated Pass `{ onProgress }` instead. The bare-callback form is kept
250
+ * for compatibility; the options form is the canonical 1.x signature.
230
251
  */
231
- load(json: SmplrPreset, onProgressOrOptions?: ((loaded: number, total: number) => void) | {
232
- buffers?: Map<string, AudioBuffer>;
233
- onProgress?: (loaded: number, total: number) => void;
234
- }): Promise<Map<string, AudioBuffer>>;
252
+ load(json: SmplrPreset, onProgress: (loaded: number, total: number) => void): Promise<Map<string, AudioBuffer>>;
235
253
  }
236
- declare const SampleLoader: Constructable<[context: BaseAudioContext, options?: {
237
- storage?: Storage;
238
- } | undefined], SampleLoaderImpl>;
239
- type SampleLoader = ReturnType<typeof SampleLoader>;
254
+ declare const SampleLoader: SampleLoaderFactory;
240
255
 
256
+ /** Options accepted by `Scheduler(context, options)`. */
257
+ type SchedulerOptions = {
258
+ /**
259
+ * How far ahead of `currentTime` events are dispatched synchronously.
260
+ * Defaults to 200ms.
261
+ */
262
+ lookaheadMs?: number;
263
+ /**
264
+ * How often the queue is polled for events ready to dispatch.
265
+ * Defaults to 50ms.
266
+ */
267
+ intervalMs?: number;
268
+ };
269
+ type SchedulerFactory = {
270
+ (context: BaseAudioContext, options?: SchedulerOptions): Scheduler;
271
+ /** @deprecated Call as a function: `Scheduler(...)` instead of `new Scheduler(...)`. */
272
+ new (context: BaseAudioContext, options?: SchedulerOptions): Scheduler;
273
+ };
241
274
  /**
242
- * Standalone scheduler. Dispatches NoteEvents immediately when they fall within the
243
- * lookahead window, or queues them for future dispatch via a self-managing interval.
244
- *
245
- * Multiple Smplr instances can share a single Scheduler for coordinated timing.
275
+ * Schedules note events for future dispatch. Used internally by every smplr
276
+ * instrument; pass an instance via {@link SmplrOptions.scheduler} to share one
277
+ * scheduler across multiple instruments.
246
278
  */
247
- declare class SchedulerImpl {
248
- #private;
249
- constructor(context: BaseAudioContext, options?: {
250
- lookaheadMs?: number;
251
- intervalMs?: number;
252
- });
279
+ interface Scheduler {
253
280
  /**
254
- * Schedule a callback for a NoteEvent.
281
+ * Dispatch `callback` at `event.time`. If `event.time` is within the
282
+ * scheduler's lookahead window (or omitted), the callback fires synchronously
283
+ * and the returned {@link StopFn} is a no-op. Otherwise the event is queued.
255
284
  *
256
- * - If the event's time falls within the lookahead window (or has no time), the
257
- * callback is called synchronously and a no-op StopFn is returned.
258
- * - Otherwise the event is queued, the interval is started if needed, and a StopFn
259
- * is returned that removes the event from the queue before it is dispatched.
285
+ * The returned function removes the event from the queue before dispatch.
260
286
  */
261
287
  schedule(event: NoteEvent, callback: (event: NoteEvent) => void): StopFn;
262
288
  /**
263
- * Clear all queued (not-yet-dispatched) events and stop the interval.
264
- * Does not affect voices that are already playing.
289
+ * Clear all queued (not-yet-dispatched) events and stop the polling
290
+ * interval. Does not affect voices already playing.
265
291
  */
266
292
  stop(): void;
267
293
  }
268
- declare const Scheduler: Constructable<[context: BaseAudioContext, options?: {
269
- lookaheadMs?: number;
270
- intervalMs?: number;
271
- } | undefined], SchedulerImpl>;
272
- type Scheduler = ReturnType<typeof Scheduler>;
294
+ declare const Scheduler: SchedulerFactory;
273
295
 
274
296
  type SmplrOptions = {
275
297
  /** Custom storage backend for sample fetching (e.g. CacheStorage). */
@@ -1273,4 +1295,4 @@ declare const LAYERS: ({
1273
1295
  cutoff?: undefined;
1274
1296
  })[];
1275
1297
 
1276
- export { type AddTrackOptions, CacheStorage, DRUM_ABUSE_PACKS, DrumAbuse, type DrumAbuseConfig, type DrumAbuseExtras, type DrumAbuseOptions, type DrumAbusePackId, type DrumAbuseSource, DrumMachine, type DrumMachineOptions, ElectricPiano, type ElectricPianoOptions, HttpStorage, Instrument, LAYERS, type LoadProgress, Mallet, Mellotron, type MellotronConfig, type MellotronOptions, NAME_TO_PATH, type NoteEvent, type PatternInput, type PlaybackParams, type RenderOfflineOptions, RenderResult, Reverb, SampleLoader, Sampler, type SamplerConfig, type SamplerReloadInput, Scheduler, Sequencer, type SequencerInstrument, type SequencerNote, type SequencerNoteEvent, type SequencerOptions, Smolken, type SmolkenConfig, type SmolkenOptions, type Smplr, type SmplrGroup, type SmplrOptions, type SmplrPlugin, type SmplrPreset, type SmplrRegion, type SmplrSamples, Soundfont, Soundfont2, type Soundfont2Options, Soundfont2Sampler, type SoundfontOptions, SplendidGrandPiano, type SplendidGrandPianoConfig, type StopFn, type StopTarget, type Storage, type StorageResponse, type TimeSignature, Versilian, type VersilianConfig, type VersilianOptions, type VoiceParams, audioBufferToWav, audioBufferToWav16, drumAbuseSampleUrl, drumMachineToPreset, getDrumAbuseMachineNames, getDrumAbuseMachinePack, getDrumAbuseMachinesForPack, getDrumAbusePackNames, getDrumMachineNames, getElectricPianoNames, getMalletNames, getMellotronNames, getSmolkenNames, getSoundfontKits, getSoundfontNames, getVersilianInstruments, loadVersilianInstrument, mellotronToPreset, pianoToPreset, renderOffline, samplerToPreset, sf2InstrumentToPreset, soundfontToPreset, trimSilence };
1298
+ export { type AddTrackOptions, CacheStorage, DRUM_ABUSE_PACKS, DrumAbuse, type DrumAbuseConfig, type DrumAbuseExtras, type DrumAbuseOptions, type DrumAbusePackId, type DrumAbuseSource, DrumMachine, type DrumMachineOptions, ElectricPiano, type ElectricPianoOptions, HttpStorage, Instrument, LAYERS, type LoadProgress, Mallet, Mellotron, type MellotronConfig, type MellotronOptions, NAME_TO_PATH, type NoteEvent, type PatternInput, type PlaybackParams, type RenderOfflineOptions, RenderResult, Reverb, SampleLoader, type SampleLoaderLoadOptions, type SampleLoaderOptions, Sampler, type SamplerConfig, type SamplerReloadInput, Scheduler, type SchedulerOptions, Sequencer, type SequencerInstrument, type SequencerNote, type SequencerNoteEvent, type SequencerOptions, Smolken, type SmolkenConfig, type SmolkenOptions, type Smplr, type SmplrGroup, type SmplrOptions, type SmplrPlugin, type SmplrPreset, type SmplrRegion, type SmplrSamples, Soundfont, Soundfont2, type Soundfont2Options, Soundfont2Sampler, type SoundfontOptions, SplendidGrandPiano, type SplendidGrandPianoConfig, type StopFn, type StopTarget, type Storage, type StorageResponse, type TimeSignature, Versilian, type VersilianConfig, type VersilianOptions, type VoiceParams, audioBufferToWav, audioBufferToWav16, drumAbuseSampleUrl, drumMachineToPreset, getDrumAbuseMachineNames, getDrumAbuseMachinePack, getDrumAbuseMachinesForPack, getDrumAbusePackNames, getDrumMachineNames, getElectricPianoNames, getMalletNames, getMellotronNames, getSmolkenNames, getSoundfontKits, getSoundfontNames, getVersilianInstruments, loadVersilianInstrument, mellotronToPreset, pianoToPreset, renderOffline, samplerToPreset, sf2InstrumentToPreset, soundfontToPreset, trimSilence };