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 +56 -56
- package/dist/index.d.mts +68 -46
- package/dist/index.d.ts +68 -46
- package/dist/index.js +23 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +23 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/smplr/as-constructable.ts","../src/storage.ts","../src/smplr/connect.ts","../src/smplr/signals.ts","../src/smplr/volume.ts","../src/smplr/channel.ts","../src/smplr/midi.ts","../src/smplr/params.ts","../src/smplr/region-matcher.ts","../src/smplr/load-audio.ts","../src/smplr/sample-loader.ts","../src/smplr/sorted-queue.ts","../src/smplr/scheduler.ts","../src/smplr/voice.ts","../src/smplr/voice-manager.ts","../src/smplr/smplr.ts","../src/smplr/instrument.ts","../src/drum-machine/dm-instrument.ts","../src/drum-machine/drum-machine.ts","../src/drum-abuse/index.ts","../src/offline/wav-encoder.ts","../src/offline/render-result.ts","../src/offline/trim-silence.ts","../src/offline/render-offline.ts","../src/sequencer/time-parser.ts","../src/sequencer/transport-clock.ts","../src/sequencer/sequencer.ts","../src/smplr/sfz-convert.ts","../src/tremolo.ts","../src/electric-piano.ts","../src/versilian.ts","../src/mallet.ts","../src/smplr/utils.ts","../src/mellotron.ts","../src/reverb/processor.min.ts","../src/reverb/reverb.ts","../src/sampler.ts","../src/smolken.ts","../src/soundfont/soundfont-instrument.ts","../src/soundfont/soundfont-loops.ts","../src/soundfont/soundfont.ts","../src/soundfont2.ts","../src/splendid-grand-piano.ts"],"sourcesContent":["export * from \"./drum-machine/drum-machine\";\nexport * from \"./drum-abuse\";\nexport * from \"./offline\";\nexport * from \"./smplr\";\nexport * from \"./sequencer\";\nexport * from \"./electric-piano\";\nexport * from \"./mallet\";\nexport * from \"./mellotron\";\nexport * from \"./reverb/reverb\";\nexport * from \"./sampler\";\nexport * from \"./smolken\";\nexport * from \"./soundfont/soundfont\";\nexport * from \"./soundfont2\";\nexport * from \"./splendid-grand-piano\";\nexport * from \"./storage\";\nexport * from \"./versilian\";\n","/**\n * Wrap a class so it is callable both as `X(...)` (preferred) and as\n * `new X(...)` (kept for compatibility with pre-1.0 examples). Returns\n * a value with both call and construct signatures.\n *\n * Used by the auxiliary exports (`Sequencer`, `Reverb`, `CacheStorage`,\n * `Scheduler`, `SampleLoader`) to match the dual signature already shipped\n * by `InstrumentFactory`. Instrument factories themselves use the richer\n * `Instrument()` builder instead, which owns option-splitting and the\n * ready-promise lifecycle.\n */\nexport type Constructable<A extends unknown[], R> = {\n (...args: A): R;\n /** @deprecated Call as a function: `X(...)` instead of `new X(...)`. */\n new (...args: A): R;\n};\n\nexport function asConstructable<A extends unknown[], R>(\n Klass: new (...args: A) => R,\n): Constructable<A, R> {\n // Must be a regular function declaration (not an arrow): arrow functions\n // are not constructible, so `new asConstructable(X)()` would throw.\n // When invoked via `new`, the function returns an object, which the JS\n // spec uses in place of the freshly-allocated `this`.\n function factory(...args: A): R {\n return new Klass(...args);\n }\n return factory as unknown as Constructable<A, R>;\n}\n","import { asConstructable } from \"./smplr/as-constructable\";\n\nexport type StorageResponse = {\n readonly status: number;\n arrayBuffer(): Promise<ArrayBuffer>;\n json(): Promise<any>;\n text(): Promise<string>;\n};\n\nexport type Storage = {\n fetch: (url: string) => Promise<StorageResponse>;\n};\n\nexport const HttpStorage: Storage = {\n fetch(url) {\n return fetch(url);\n },\n};\n\nclass CacheStorageImpl implements Storage {\n #cache: Promise<Cache>;\n\n constructor(name = \"smplr\") {\n if (typeof window === \"undefined\" || !(\"caches\" in window)) {\n this.#cache = Promise.reject(\"CacheStorage not supported\");\n // Attach a no-op handler so node doesn't surface this as an unhandled\n // rejection in environments where `fetch()` is never called.\n this.#cache.catch(() => {});\n } else {\n this.#cache = caches.open(name);\n }\n }\n\n async fetch(url: string): Promise<StorageResponse> {\n const request = new Request(url);\n try {\n return await this.#tryFromCache(request);\n } catch (err) {\n const response = await fetch(request);\n await this.#saveResponse(request, response);\n return response;\n }\n }\n\n async #tryFromCache(request: Request): Promise<StorageResponse> {\n const cache = await this.#cache;\n const response = await cache.match(request);\n if (response) return response;\n else throw Error(\"Not found\");\n }\n\n async #saveResponse(request: Request, response: Response) {\n try {\n const cache = await this.#cache;\n await cache.put(request, response.clone());\n } catch (err) {}\n }\n}\n\nexport const CacheStorage = asConstructable(CacheStorageImpl);\nexport type CacheStorage = ReturnType<typeof CacheStorage>;\n","export type AudioInsert = {\n input: AudioNode;\n output: AudioNode;\n};\n\nexport function connectSerial(nodes: (AudioNode | AudioInsert | undefined)[]) {\n const _nodes = nodes.filter((x): x is AudioNode | AudioInsert => !!x);\n _nodes.reduce((a, b) => {\n const left = \"output\" in a ? a.output : a;\n const right = \"input\" in b ? b.input : b;\n left.connect(right);\n return b;\n });\n\n return () => {\n _nodes.reduce((a, b) => {\n const left = \"output\" in a ? a.output : a;\n const right = \"input\" in b ? b.input : b;\n left.disconnect(right);\n return b;\n });\n };\n}\n\nexport function connectAudioBus(\n node: AudioNode,\n destination: AudioNode,\n gain: number,\n) {\n const mix = node.context.createGain();\n mix.gain.value = gain;\n node.connect(mix);\n mix.connect(destination);\n\n return () => {\n node.disconnect(mix);\n mix.disconnect(destination);\n };\n}\n","/**\n * A function to unsubscribe from an event or control\n */\nexport type Unsubscribe = () => void;\n/**\n * A function that listener to event or control changes\n */\nexport type Listener<T> = (value: T) => void;\n/**\n * A function to subscribe an trigger or control events\n */\nexport type Subscribe<T> = (listener: Listener<T>) => Unsubscribe;\n\n/**\n * A trigger is a subscribable event\n */\nexport type Trigger<T> = {\n subscribe: Subscribe<T>;\n trigger: (event: T) => void;\n};\n\n/**\n * A control is a subscribable value\n */\nexport type Control<T> = {\n subscribe: Subscribe<T>;\n set: (value: T) => void;\n get: () => T;\n};\n\n/**\n * Create a control signal\n * @param initialValue\n * @returns Control\n */\nexport function createControl<T>(initialValue: T): Control<T> {\n let current = initialValue;\n const listeners = new Set<Listener<T>>();\n\n function subscribe(listener: Listener<T>) {\n listeners.add(listener);\n listener(current);\n return () => {\n listeners.delete(listener);\n };\n }\n\n function set(value: T) {\n current = value;\n listeners.forEach((listener) => listener(current));\n }\n\n function get(): T {\n return current;\n }\n return { subscribe, set, get };\n}\n\nexport function createTrigger<T>(): Trigger<T> {\n const listeners = new Set<Listener<T>>();\n\n function subscribe(listener: Listener<T>) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n }\n\n function trigger(value: T) {\n listeners.forEach((listener) => listener(value));\n }\n\n return { subscribe, trigger };\n}\n\nexport function unsubscribeAll(unsubscribe: Array<Unsubscribe | undefined>) {\n let done = false;\n return () => {\n if (done) return;\n done = true;\n unsubscribe.forEach((cb) => cb?.());\n };\n}\n","/// This is how the MIDI association converts midi velocity [0..127] into gain [0..1]\n/// @see https://www.midi.org/specifications/file-format-specifications/dls-downloadable-sounds/dls-level-1\nexport function midiVelToGain(vel: number) {\n return (vel * vel) / 16129; // 16129 = 127 * 127\n}\n\nexport function dbToGain(decibels: number) {\n return Math.pow(10, decibels / 20);\n}\n","import { AudioInsert, connectSerial } from \"./connect\";\nimport { Control, createControl } from \"./signals\";\nimport { midiVelToGain } from \"./volume\";\n\nexport type ChannelConfig = {\n destination: AudioNode;\n volume: number;\n volumeToGain: (volume: number) => number;\n pan?: number;\n};\n\nexport type OutputChannel = Omit<Channel, \"input\">;\n\ntype Send = {\n name: string;\n mix: GainNode;\n disconnect: () => void;\n};\n\n/**\n * An output channel with audio effects\n * @private\n */\nexport class Channel {\n /** @deprecated Use `output.volume = n` instead. */\n public readonly setVolume: (vol: number) => void;\n public readonly input: AudioNode;\n\n #volume: GainNode;\n #panner: StereoPannerNode;\n #sends?: Send[];\n #inserts?: (AudioNode | AudioInsert)[];\n #disconnect: () => void;\n #unsubscribe: () => void;\n #config: Readonly<ChannelConfig>;\n #volumeControl: Control<number>;\n #disconnected = false;\n\n constructor(\n public readonly context: BaseAudioContext,\n options?: Partial<ChannelConfig>,\n ) {\n this.#config = {\n destination: options?.destination ?? context.destination,\n volume: options?.volume ?? 100,\n volumeToGain: options?.volumeToGain ?? midiVelToGain,\n pan: options?.pan ?? 0,\n };\n\n this.input = context.createGain();\n this.#volume = context.createGain();\n this.#panner = context.createStereoPanner();\n this.#panner.pan.value = this.#config.pan!;\n\n this.#disconnect = connectSerial([\n this.input,\n this.#volume,\n this.#panner,\n this.#config.destination,\n ]);\n\n const volume = createControl(this.#config.volume);\n this.#volumeControl = volume;\n this.setVolume = volume.set;\n this.#unsubscribe = volume.subscribe((volume) => {\n this.#volume.gain.value = this.#config.volumeToGain(volume);\n });\n }\n\n get volume(): number {\n return this.#volumeControl.get();\n }\n\n set volume(value: number) {\n this.#volumeControl.set(value);\n }\n\n get pan(): number {\n return this.#panner.pan.value;\n }\n\n set pan(value: number) {\n this.#panner.pan.value = value;\n }\n\n addInsert(effect: AudioNode | AudioInsert) {\n if (this.#disconnected) {\n throw Error(\"Can't add insert to disconnected channel\");\n }\n this.#inserts ??= [];\n this.#inserts.push(effect);\n this.#disconnect();\n this.#disconnect = connectSerial([\n this.input,\n ...this.#inserts,\n this.#volume,\n this.#panner,\n this.#config.destination,\n ]);\n }\n\n addEffect(\n name: string,\n effect: AudioNode | { input: AudioNode },\n mixValue: number,\n ) {\n if (this.#disconnected) {\n throw Error(\"Can't add effect to disconnected channel\");\n }\n const mix = this.context.createGain();\n mix.gain.value = mixValue;\n const input = \"input\" in effect ? effect.input : effect;\n const disconnect = connectSerial([this.#volume, mix, input]);\n\n this.#sends ??= [];\n this.#sends.push({ name, mix, disconnect });\n }\n\n setEffectMix(name: string, mix: number) {\n if (this.#disconnected) {\n throw Error(\"Can't send effect to disconnected channel\");\n }\n\n const send = this.#sends?.find((send) => send.name === name);\n if (send) {\n send.mix.gain.value = mix;\n } else {\n console.warn(\"Send bus not found: \" + name);\n }\n }\n\n /** @deprecated Use `setEffectMix(name, mix)` instead. */\n sendEffect(name: string, mix: number) {\n this.setEffectMix(name, mix);\n }\n\n disconnect() {\n if (this.#disconnected) return;\n this.#disconnected = true;\n this.#disconnect();\n this.#unsubscribe();\n this.#sends?.forEach((send) => send.disconnect());\n this.#sends = undefined;\n }\n}\n","function noteNameToMidi(note: string): number | undefined {\n const REGEX = /^([a-gA-G]?)(#{1,}|b{1,}|)(-?\\d+)$/;\n const m = REGEX.exec(note);\n if (!m) return;\n const letter = m[1].toUpperCase();\n if (!letter) return;\n\n const acc = m[2];\n const alt = acc[0] === \"b\" ? -acc.length : acc.length;\n const oct = m[3] ? +m[3] : 4;\n\n const step = (letter.charCodeAt(0) + 3) % 7;\n return [0, 2, 4, 5, 7, 9, 11][step] + alt + 12 * (oct + 1);\n}\n\n/** @internal Not part of the public 1.0 API surface. */\nexport function toMidi(note: string | number | undefined): number | undefined {\n return note === undefined\n ? undefined\n : typeof note === \"number\"\n ? note\n : noteNameToMidi(note);\n}\n\n/** @internal Not part of the public 1.0 API surface. */\nexport function findNearestMidi(\n midi: number,\n isAvailable: Record<string | number, unknown>,\n): [number, number] {\n let i = 0;\n while (isAvailable[midi + i] === undefined && i < 128) {\n if (i > 0) i = -i;\n else i = -i + 1;\n }\n\n return i === 127 ? [midi, 0] : [midi + i, -i * 100];\n}\n","import { PlaybackParams, SmplrGroup, SmplrRegion, VoiceParams } from \"./types\";\n\n/**\n * Hardcoded defaults — the baseline when nothing else is specified.\n */\nexport const PARAM_DEFAULTS: Required<PlaybackParams> = {\n volume: 0,\n tune: 0,\n detune: 0,\n ampRelease: 0.3,\n ampAttack: 0,\n lpfCutoffHz: 20000,\n offset: 0,\n loop: false,\n loopStart: 0,\n loopEnd: 0,\n reverse: false,\n};\n\nconst PLAYBACK_KEYS = Object.keys(PARAM_DEFAULTS) as (keyof PlaybackParams)[];\n\n/**\n * Extract only PlaybackParams fields from a group or region object,\n * ignoring structural fields like keyRange, velRange, regions, etc.\n */\nfunction pickPlaybackParams(obj: PlaybackParams): PlaybackParams {\n const result: PlaybackParams = {};\n for (const key of PLAYBACK_KEYS) {\n const value = obj[key];\n if (value !== undefined) (result as Record<string, unknown>)[key] = value;\n }\n return result;\n}\n\n/**\n * Per-note overrides that can be passed via NoteEvent at play time.\n */\nexport type NoteOverrides = {\n detune?: number;\n lpfCutoffHz?: number;\n loop?: boolean;\n ampRelease?: number;\n reverse?: boolean;\n};\n\n/**\n * Resolve the final VoiceParams for one matched region by merging four levels:\n *\n * PARAM_DEFAULTS → json.defaults → group → region → noteOverrides\n *\n * Detune is computed in cents:\n * (playedMidi - region.pitch + tune) * 100 + detune + noteOverrides.detune\n *\n * @param defaults Global defaults from SmplrPreset.defaults\n * @param group The matched SmplrGroup\n * @param region The matched SmplrRegion\n * @param midi The played MIDI note number\n * @param velocity The played velocity (0-127)\n * @param overrides Per-note overrides from the NoteEvent\n */\nexport function resolveParams(\n defaults: PlaybackParams | undefined,\n group: SmplrGroup,\n region: SmplrRegion,\n midi: number,\n velocity: number,\n overrides?: NoteOverrides,\n): VoiceParams {\n // Merge: hardcoded defaults → json.defaults → group → region\n const merged: Required<PlaybackParams> = {\n ...PARAM_DEFAULTS,\n ...defaults,\n ...pickPlaybackParams(group),\n ...pickPlaybackParams(region),\n };\n\n // Determine sample root pitch:\n // - region.pitch is the authoritative root MIDI note of the sample\n // - if absent, fall back to region.key (which sets both keyRange and pitch)\n // - if neither, assume the sample is tuned to the played note (no pitch shift)\n const pitch = region.pitch ?? region.key ?? midi;\n const semitones = midi - pitch;\n\n // Detune in cents: pitch transpose + tune offset (in semitones) + fine detune (cents)\n let detune = (semitones + merged.tune) * 100 + merged.detune;\n\n // Apply note-level overrides\n if (overrides?.detune !== undefined) detune += overrides.detune;\n\n return {\n detune,\n velocity,\n volume: merged.volume,\n ampRelease: overrides?.ampRelease ?? merged.ampRelease,\n ampAttack: merged.ampAttack,\n lpfCutoffHz: overrides?.lpfCutoffHz ?? merged.lpfCutoffHz,\n offset: merged.offset,\n loop: overrides?.loop ?? merged.loop,\n loopStart: merged.loopStart,\n loopEnd: merged.loopEnd,\n ampVelCurve: region.ampVelCurve,\n loopAuto: region.loopAuto,\n reverse: overrides?.reverse,\n };\n}\n","import { SmplrGroup, SmplrPreset, SmplrRegion } from \"./types\";\n\n/**\n * A region that matched a note event. Carries resolved identity fields and references\n * to the original group/region objects so Smplr can call resolveParams().\n */\nexport type MatchedRegion = {\n sample: string; // buffer key\n pitch: number; // root MIDI pitch of the sample (used for detune calculation)\n group?: number; // exclusive group number (for VoiceManager)\n offBy?: number; // stop voices in this group before playing\n groupRef: SmplrGroup; // original group, passed to resolveParams()\n regionRef: SmplrRegion; // original region, passed to resolveParams()\n};\n\n// ---------------------------------------------------------------------------\n// Pre-processed internal types — built once in the constructor\n// ---------------------------------------------------------------------------\n\ntype ProcessedRegion = {\n keyLow: number;\n keyHigh: number;\n pitch: number | undefined; // undefined → use played MIDI note as pitch\n velLow: number;\n velHigh: number;\n ccRange?: Record<string, [number, number]>;\n seqPosition: number; // 1-based\n group?: number;\n offBy?: number;\n sample: string;\n ref: SmplrRegion;\n};\n\ntype ProcessedGroup = {\n keyLow: number;\n keyHigh: number;\n velLow: number;\n velHigh: number;\n ccRange?: Record<string, [number, number]>;\n seqLength?: number;\n group?: number;\n offBy?: number;\n regions: ProcessedRegion[];\n ref: SmplrGroup;\n};\n\n// ---------------------------------------------------------------------------\n// Pre-processing helpers\n// ---------------------------------------------------------------------------\n\nfunction processRegion(region: SmplrRegion): ProcessedRegion {\n let keyLow: number;\n let keyHigh: number;\n let pitch: number | undefined;\n\n if (region.key !== undefined) {\n // Shorthand: key sets both the trigger range and the root pitch\n keyLow = keyHigh = region.key;\n pitch = region.key;\n } else if (region.keyRange) {\n [keyLow, keyHigh] = region.keyRange;\n pitch = region.pitch; // may be undefined — resolved at match time\n } else {\n // No key constraint — region matches all MIDI notes\n keyLow = 0;\n keyHigh = 127;\n pitch = region.pitch;\n }\n\n return {\n keyLow,\n keyHigh,\n pitch,\n velLow: region.velRange?.[0] ?? 0,\n velHigh: region.velRange?.[1] ?? 127,\n ccRange: region.ccRange,\n seqPosition: region.seqPosition ?? 1,\n group: region.group,\n offBy: region.offBy,\n sample: region.sample,\n ref: region,\n };\n}\n\nfunction processGroup(group: SmplrGroup): ProcessedGroup {\n return {\n keyLow: group.keyRange?.[0] ?? 0,\n keyHigh: group.keyRange?.[1] ?? 127,\n velLow: group.velRange?.[0] ?? 0,\n velHigh: group.velRange?.[1] ?? 127,\n ccRange: group.ccRange,\n seqLength: group.seqLength,\n group: group.group,\n offBy: group.offBy,\n regions: group.regions.map(processRegion),\n ref: group,\n };\n}\n\n// ---------------------------------------------------------------------------\n// CC matching helper\n// ---------------------------------------------------------------------------\n\nfunction matchesCc(\n ccState: Map<number, number>,\n ccRange?: Record<string, [number, number]>,\n): boolean {\n if (!ccRange) return true;\n for (const [ccStr, [low, high]] of Object.entries(ccRange)) {\n const cc = parseInt(ccStr, 10);\n const value = ccState.get(cc) ?? 0; // default: 0 (pedal up, etc.)\n if (value < low || value > high) return false;\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// RegionMatcher\n// ---------------------------------------------------------------------------\n\nexport class RegionMatcher {\n #groups: ProcessedGroup[];\n #seqCounters: Map<number, number>; // groupIndex → call count\n\n constructor(json: SmplrPreset) {\n this.#groups = json.groups.map(processGroup);\n this.#seqCounters = new Map();\n }\n\n /**\n * Match a note event against all groups and regions.\n *\n * For each group that passes key/vel/cc filters:\n * - Check each region's key/vel/cc filters\n * - Apply round-robin seqPosition filter if group.seqLength is set\n * - Advance the per-group round-robin counter (always, when group matched)\n *\n * Returns all matched regions with resolved pitch, group, offBy.\n */\n match(\n midi: number,\n velocity: number,\n ccState: Map<number, number>,\n ): MatchedRegion[] {\n const results: MatchedRegion[] = [];\n\n for (let gi = 0; gi < this.#groups.length; gi++) {\n const group = this.#groups[gi];\n\n // Group-level filters\n if (midi < group.keyLow || midi > group.keyHigh) continue;\n if (velocity < group.velLow || velocity > group.velHigh) continue;\n if (!matchesCc(ccState, group.ccRange)) continue;\n\n const counter = this.#seqCounters.get(gi) ?? 0;\n\n for (const region of group.regions) {\n // Region-level filters\n if (midi < region.keyLow || midi > region.keyHigh) continue;\n if (velocity < region.velLow || velocity > region.velHigh) continue;\n if (!matchesCc(ccState, region.ccRange)) continue;\n\n // Round-robin filter: only allow the region whose seqPosition matches\n // the current counter for this group\n if (group.seqLength !== undefined) {\n const seqPos = region.seqPosition - 1; // to 0-based\n if (counter % group.seqLength !== seqPos) continue;\n }\n\n results.push({\n sample: region.sample,\n // If no pitch is pre-resolved (no key or pitch on region), fall back to\n // the played note so resolveParams computes 0 semitones of transpose\n pitch: region.pitch ?? midi,\n group: region.group ?? group.group,\n offBy: region.offBy ?? group.offBy,\n groupRef: group.ref,\n regionRef: region.ref,\n });\n }\n\n // Advance per-group round-robin counter whenever the group matched,\n // regardless of whether a region's seqPosition filter passed.\n if (group.seqLength !== undefined) {\n this.#seqCounters.set(gi, counter + 1);\n }\n }\n\n return results;\n }\n}\n","import { Storage } from \"../storage\";\n\nexport type AudioBuffers = Record<string | number, AudioBuffer | undefined>;\n\n/**\n * A function that downloads audio into a AudioBuffers\n */\nexport type AudioBuffersLoader = (\n context: BaseAudioContext,\n buffers: AudioBuffers,\n) => Promise<void>;\n\nexport async function loadAudioBuffer(\n context: BaseAudioContext,\n url: string,\n storage: Storage,\n): Promise<AudioBuffer | undefined> {\n url = url\n .replace(/#/g, \"%23\")\n .replace(/ /g, \"%20\")\n .replace(/([^:]\\/)\\/+/g, \"$1\");\n const response = await storage.fetch(url);\n if (response.status !== 200) {\n console.warn(\n \"Error loading buffer. Invalid status: \",\n response.status,\n url,\n );\n return;\n }\n try {\n const audioData = await response.arrayBuffer();\n const buffer = await context.decodeAudioData(audioData);\n return buffer;\n } catch (error) {\n console.warn(\"Error loading buffer\", error, url);\n }\n}\n\n// Safari reports it can play OGG but decodeAudioData fails on many samples\nfunction isSafari(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const ua = navigator.userAgent;\n return (\n ua.includes(\"Safari\") && !ua.includes(\"Chrome\") && !ua.includes(\"Chromium\")\n );\n}\n\nexport function findFirstSupportedFormat(formats: string[]): string | null {\n if (typeof document === \"undefined\") return null;\n\n // Safari's decodeAudioData fails on OGG even though canPlayType returns \"maybe\"\n // Skip OGG entirely on Safari and use the fallback format (mp3/m4a)\n const skipOgg = isSafari();\n\n const audio = document.createElement(\"audio\");\n for (let i = 0; i < formats.length; i++) {\n const format = formats[i];\n if (skipOgg && format === \"ogg\") {\n continue;\n }\n const canPlay = audio.canPlayType(`audio/${format}`);\n if (canPlay === \"probably\" || canPlay === \"maybe\") {\n return format;\n }\n // check Safari for aac format\n if (format === \"m4a\") {\n const canPlay = audio.canPlayType(`audio/aac`);\n if (canPlay === \"probably\" || canPlay === \"maybe\") {\n return format;\n }\n }\n }\n return null;\n}\n\nexport function getPreferredAudioExtension() {\n const format = findFirstSupportedFormat([\"ogg\", \"m4a\"]) ?? \"ogg\";\n return \".\" + format;\n}\n","import { asConstructable } from \"./as-constructable\";\nimport { findFirstSupportedFormat, loadAudioBuffer } from \"./load-audio\";\nimport { HttpStorage, Storage } from \"../storage\";\nimport { SmplrPreset } from \"./types\";\n\n/**\n * Loads and caches AudioBuffers for all samples referenced in a SmplrPreset.\n *\n * The cache is keyed by resolved URL, so the same audio file is never fetched\n * or decoded twice. Multiple Smplr instances can share one SampleLoader by\n * passing it via SmplrOptions.loader.\n */\nclass SampleLoaderImpl {\n #context: BaseAudioContext;\n #storage: Storage;\n #cache: Map<string, AudioBuffer> = new Map();\n\n constructor(context: BaseAudioContext, options?: { storage?: Storage }) {\n this.#context = context;\n this.#storage = options?.storage ?? HttpStorage;\n }\n\n /**\n * Load all samples referenced in `json`. Returns a Map of sample name →\n * AudioBuffer. Progress is reported via `onProgress` callback or via\n * options object.\n *\n * - `buffers` in options: pre-loaded buffers — skips fetch for these names.\n * - All samples load in parallel. Failed samples are silently omitted.\n */\n async load(\n json: SmplrPreset,\n onProgressOrOptions?:\n | ((loaded: number, total: number) => void)\n | {\n buffers?: Map<string, AudioBuffer>;\n onProgress?: (loaded: number, total: number) => void;\n },\n ): Promise<Map<string, AudioBuffer>> {\n // Normalise the second argument: support legacy callback or new options object\n const preloaded =\n typeof onProgressOrOptions === \"object\"\n ? onProgressOrOptions.buffers\n : undefined;\n const onProgress =\n typeof onProgressOrOptions === \"function\"\n ? onProgressOrOptions\n : onProgressOrOptions?.onProgress;\n\n const format =\n findFirstSupportedFormat(json.samples.formats) ??\n json.samples.formats[0] ??\n \"ogg\";\n\n const base = json.samples.baseUrl.replace(/\\/$/, \"\");\n const names = collectSampleNames(json);\n const total = names.length;\n let loaded = 0;\n\n const result = new Map<string, AudioBuffer>();\n\n await Promise.all(\n names.map(async (name) => {\n // 1. Check pre-loaded buffers first — no fetch needed\n const pre = preloaded?.get(name);\n if (pre) {\n result.set(name, pre);\n loaded++;\n onProgress?.(loaded, total);\n return;\n }\n\n // 2. Build URL and check internal cache\n const path = json.samples.map?.[name] ?? name;\n const url = `${base}/${path}.${format}`;\n\n let buffer = this.#cache.get(url);\n\n if (!buffer) {\n const fetched = await loadAudioBuffer(\n this.#context,\n url,\n this.#storage,\n );\n if (fetched) {\n buffer = fetched;\n this.#cache.set(url, buffer);\n }\n }\n\n if (buffer) result.set(name, buffer);\n\n loaded++;\n onProgress?.(loaded, total);\n }),\n );\n\n return result;\n }\n}\n\n/** Collect all unique region.sample names across all groups. */\nfunction collectSampleNames(json: SmplrPreset): string[] {\n const seen = new Set<string>();\n for (const group of json.groups) {\n for (const region of group.regions) {\n seen.add(region.sample);\n }\n }\n return [...seen];\n}\n\nexport const SampleLoader = asConstructable(SampleLoaderImpl);\nexport type SampleLoader = ReturnType<typeof SampleLoader>;\n","/**\n * A sorted items that uses binary search to insert items in sorted order.\n * @private\n */\nexport class SortedQueue<T> {\n #items: T[] = [];\n constructor(public readonly compare: (a: T, b: T) => number) {}\n\n push(item: T) {\n const len = this.#items.length;\n\n let left = 0;\n let right = len - 1;\n let index = len;\n\n while (left <= right) {\n const mid = Math.floor((left + right) / 2);\n if (this.compare(item, this.#items[mid]) < 0) {\n index = mid;\n right = mid - 1;\n } else {\n left = mid + 1;\n }\n }\n\n this.#items.splice(index, 0, item);\n }\n\n pop() {\n return this.#items.shift();\n }\n\n peek(): T | undefined {\n return this.#items[0];\n }\n\n removeAll(predicate: (item: T) => boolean) {\n const len = this.#items.length;\n this.#items = this.#items.filter((item) => !predicate(item));\n return this.#items.length !== len;\n }\n\n clear() {\n this.#items = [];\n }\n\n size() {\n return this.#items.length;\n }\n}\n","import { asConstructable } from \"./as-constructable\";\nimport { SortedQueue } from \"./sorted-queue\";\nimport { NoteEvent, StopFn } from \"./types\";\n\nconst LOOKAHEAD_MS_DEFAULT = 200;\nconst INTERVAL_MS_DEFAULT = 50;\n\ntype QueueItem = {\n time: number;\n event: NoteEvent;\n callback: (event: NoteEvent) => void;\n};\n\n/**\n * Standalone scheduler. Dispatches NoteEvents immediately when they fall within the\n * lookahead window, or queues them for future dispatch via a self-managing interval.\n *\n * Multiple Smplr instances can share a single Scheduler for coordinated timing.\n */\nclass SchedulerImpl {\n #context: BaseAudioContext;\n #lookaheadSec: number;\n #intervalMs: number;\n #queue: SortedQueue<QueueItem>;\n #intervalId: ReturnType<typeof setInterval> | undefined;\n\n constructor(\n context: BaseAudioContext,\n options?: { lookaheadMs?: number; intervalMs?: number },\n ) {\n this.#context = context;\n this.#lookaheadSec = (options?.lookaheadMs ?? LOOKAHEAD_MS_DEFAULT) / 1000;\n this.#intervalMs = options?.intervalMs ?? INTERVAL_MS_DEFAULT;\n this.#queue = new SortedQueue<QueueItem>((a, b) => a.time - b.time);\n }\n\n /**\n * Schedule a callback for a NoteEvent.\n *\n * - If the event's time falls within the lookahead window (or has no time), the\n * callback is called synchronously and a no-op StopFn is returned.\n * - Otherwise the event is queued, the interval is started if needed, and a StopFn\n * is returned that removes the event from the queue before it is dispatched.\n */\n schedule(event: NoteEvent, callback: (event: NoteEvent) => void): StopFn {\n const now = this.#context.currentTime;\n const time = getEventTime(event) ?? now;\n\n if (time <= now + this.#lookaheadSec) {\n callback(event);\n return noOp;\n }\n\n const item: QueueItem = { time, event, callback };\n this.#queue.push(item);\n this.#ensureRunning();\n\n return () => {\n this.#queue.removeAll((q) => q === item);\n };\n }\n\n /**\n * Clear all queued (not-yet-dispatched) events and stop the interval.\n * Does not affect voices that are already playing.\n */\n stop(): void {\n this.#queue.clear();\n if (this.#intervalId !== undefined) {\n clearInterval(this.#intervalId);\n this.#intervalId = undefined;\n }\n }\n\n #ensureRunning(): void {\n if (this.#intervalId !== undefined) return;\n\n this.#intervalId = setInterval(() => {\n const dispatchBefore = this.#context.currentTime + this.#lookaheadSec;\n\n while (\n this.#queue.size() > 0 &&\n this.#queue.peek()!.time <= dispatchBefore\n ) {\n const item = this.#queue.pop()!;\n item.callback(item.event);\n }\n\n // Self-terminate when the queue is empty\n if (this.#queue.size() === 0) {\n clearInterval(this.#intervalId);\n this.#intervalId = undefined;\n }\n }, this.#intervalMs);\n }\n}\n\nfunction getEventTime(event: NoteEvent): number | undefined {\n return typeof event === \"object\" ? event.time : undefined;\n}\n\nconst noOp: StopFn = () => {};\n\nexport const Scheduler = asConstructable(SchedulerImpl);\nexport type Scheduler = ReturnType<typeof Scheduler>;\n","import { dbToGain, midiVelToGain } from \"./volume\";\nimport { VoiceParams } from \"./types\";\n\nexport class Voice {\n readonly stopId: string | number;\n readonly group: number | undefined;\n\n #context: BaseAudioContext;\n #source: AudioBufferSourceNode;\n #envelope: GainNode;\n #startAt: number;\n #ampRelease: number;\n #state: \"playing\" | \"stopping\" | \"stopped\" = \"playing\";\n #endedCallbacks: (() => void)[] = [];\n\n constructor(\n context: BaseAudioContext,\n buffer: AudioBuffer,\n params: VoiceParams,\n destination: AudioNode,\n stopId: string | number,\n group?: number,\n startTime?: number,\n ) {\n this.#context = context;\n this.stopId = stopId;\n this.group = group;\n this.#ampRelease = params.ampRelease;\n\n // --- Build audio graph ---\n\n const source = context.createBufferSource();\n source.buffer = buffer;\n\n // Detune — Safari workaround: source.detune may not exist\n const cents = params.detune;\n if (source.detune) {\n source.detune.value = cents;\n } else {\n source.playbackRate.value = Math.pow(2, cents / 1200);\n }\n\n // Looping\n if (params.loopAuto) {\n source.loop = true;\n source.loopStart = buffer.duration * params.loopAuto.startRatio;\n source.loopEnd = buffer.duration * params.loopAuto.endRatio;\n } else if (params.loop) {\n source.loop = true;\n source.loopStart = params.loopStart;\n source.loopEnd = params.loopEnd || buffer.duration;\n }\n\n // LPF — only inserted when cutoff is meaningfully below Nyquist\n let lpf: BiquadFilterNode | undefined;\n if (params.lpfCutoffHz < 20000) {\n lpf = context.createBiquadFilter();\n lpf.type = \"lowpass\";\n lpf.frequency.value = params.lpfCutoffHz;\n }\n\n // Velocity gain × dB volume\n const gain = context.createGain();\n gain.gain.value = midiVelToGain(params.velocity) * dbToGain(params.volume);\n\n // Release envelope\n const envelope = context.createGain();\n envelope.gain.value = 1.0;\n\n // Wire: source → [lpf] → gain → envelope → destination\n if (lpf) {\n source.connect(lpf);\n lpf.connect(gain);\n } else {\n source.connect(gain);\n }\n gain.connect(envelope);\n envelope.connect(destination);\n\n // Start\n const startAt = startTime ?? context.currentTime;\n this.#startAt = startAt;\n\n // Offset: VoiceParams.offset is in sample frames; source.start() takes seconds.\n // When playing in reverse (buffer is already reversed), mirror the offset so\n // offset=N from the start of the original buffer maps to (length-N) in the reversed one.\n let offsetSec = 0;\n if (params.offset > 0) {\n offsetSec = params.reverse\n ? (buffer.length - params.offset) / buffer.sampleRate\n : params.offset / buffer.sampleRate;\n }\n source.start(startAt, offsetSec);\n\n this.#source = source;\n this.#envelope = envelope;\n\n // Cleanup when the source naturally ends or is stopped\n source.onended = () => {\n this.#state = \"stopped\";\n envelope.disconnect();\n gain.disconnect();\n lpf?.disconnect();\n source.disconnect();\n for (const cb of this.#endedCallbacks) cb();\n this.#endedCallbacks = [];\n };\n }\n\n /**\n * Stop the voice, applying a release envelope if time is after the start time.\n * Idempotent — subsequent calls after the first are ignored.\n */\n stop(time?: number): void {\n if (this.#state !== \"playing\") return;\n this.#state = \"stopping\";\n\n const t = time ?? this.#context.currentTime;\n\n if (t <= this.#startAt) {\n // Stop at or before start: cancel the note entirely\n this.#source.stop(t);\n } else {\n // Apply release envelope then stop the source\n const stopAt = t + this.#ampRelease;\n this.#envelope.gain.cancelScheduledValues(t);\n this.#envelope.gain.setValueAtTime(1.0, t);\n this.#envelope.gain.linearRampToValueAtTime(0, stopAt);\n this.#source.stop(stopAt);\n }\n }\n\n /**\n * Register a callback to be called when the source node fires its onended event.\n * If the voice has already stopped, the callback is invoked immediately.\n */\n onEnded(cb: () => void): void {\n if (this.#state === \"stopped\") {\n cb();\n } else {\n this.#endedCallbacks.push(cb);\n }\n }\n\n get isActive(): boolean {\n return this.#state !== \"stopped\";\n }\n}\n","import { Voice } from \"./voice\";\n\n/**\n * Tracks active Voice instances and provides O(1) stop operations via Maps.\n *\n * Replaces the old broadcast-stop pattern (O(n) signal to all voices)\n * with direct Set lookups keyed by stopId and group number.\n */\nexport class VoiceManager {\n #voices: Set<Voice> = new Set();\n #byStopId: Map<string | number, Set<Voice>> = new Map();\n #byGroup: Map<number, Set<Voice>> = new Map();\n\n /**\n * Register a voice. Indexes it by stopId and group, then auto-removes it\n * when the voice fires its onEnded callback.\n */\n add(voice: Voice): void {\n this.#voices.add(voice);\n\n // Index by stopId\n getOrCreate(this.#byStopId, voice.stopId).add(voice);\n\n // Index by group (only if the voice belongs to an exclusive group)\n if (voice.group !== undefined) {\n getOrCreate(this.#byGroup, voice.group).add(voice);\n }\n\n // Auto-remove when the voice's source node fires onended\n voice.onEnded(() => this.#remove(voice));\n }\n\n /** Stop all active voices. */\n stopAll(time?: number): void {\n // Snapshot before iterating — stop() may synchronously trigger onEnded\n // which removes voices from the set while we're iterating.\n for (const voice of [...this.#voices]) {\n voice.stop(time);\n }\n }\n\n /** Stop all voices whose stopId matches. */\n stopById(stopId: string | number, time?: number): void {\n const voices = this.#byStopId.get(stopId);\n if (!voices) return;\n for (const voice of [...voices]) {\n voice.stop(time);\n }\n }\n\n /** Stop all voices that belong to an exclusive group number. */\n stopGroup(group: number, time?: number): void {\n const voices = this.#byGroup.get(group);\n if (!voices) return;\n for (const voice of [...voices]) {\n voice.stop(time);\n }\n }\n\n /** Number of voices currently tracked (includes stopping voices not yet ended). */\n get activeCount(): number {\n return this.#voices.size;\n }\n\n #remove(voice: Voice): void {\n this.#voices.delete(voice);\n this.#byStopId.get(voice.stopId)?.delete(voice);\n if (voice.group !== undefined) {\n this.#byGroup.get(voice.group)?.delete(voice);\n }\n }\n}\n\nfunction getOrCreate<K, V>(map: Map<K, Set<V>>, key: K): Set<V> {\n let set = map.get(key);\n if (!set) {\n set = new Set();\n map.set(key, set);\n }\n return set;\n}\n","import { Channel, OutputChannel } from \"./channel\";\nimport type { Smplr } from \"./instrument\";\nimport { toMidi } from \"./midi\";\nimport { Storage } from \"../storage\";\nimport { resolveParams } from \"./params\";\nimport { RegionMatcher } from \"./region-matcher\";\nimport { SampleLoader } from \"./sample-loader\";\nimport { Scheduler } from \"./scheduler\";\nimport {\n LoadProgress,\n NoteEvent,\n PlaybackParams,\n SmplrPreset,\n StopFn,\n StopTarget,\n} from \"./types\";\nimport { Voice } from \"./voice\";\nimport { VoiceManager } from \"./voice-manager\";\n\nexport type SmplrOptions = {\n /** Custom storage backend for sample fetching (e.g. CacheStorage). */\n storage?: Storage;\n /** Destination audio node. Defaults to context.destination. */\n destination?: AudioNode;\n /** Master volume (0–127 MIDI scale). Defaults to 100. */\n volume?: number;\n /** Custom volume-to-gain mapping function. Defaults to midiVelToGain. */\n volumeToGain?: (volume: number) => number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). Defaults to 0. */\n pan?: number;\n /** Default note velocity when not specified in NoteEvent (0–127). Defaults to 100. */\n velocity?: number;\n /** Shared SampleLoader instance. If omitted, a private one is created. */\n loader?: SampleLoader;\n /** Shared Scheduler instance. If omitted, a private one is created. */\n scheduler?: Scheduler;\n /** Called after each buffer is loaded (or served from cache). */\n onLoadProgress?: (progress: LoadProgress) => void;\n /** Called when a note is dispatched to the audio engine (slightly before playback). */\n onStart?: (event: NoteEvent) => void;\n /** Called when each voice's audio node ends. */\n onEnded?: (event: NoteEvent) => void;\n};\n\n/**\n * Fully resolved note event, normalized from the public NoteEvent union type.\n * Used internally after normalization in start().\n */\ntype NormalizedNoteEvent = {\n note: string | number;\n midi: number;\n velocity: number;\n time?: number;\n duration?: number | null;\n detune?: number;\n lpfCutoffHz?: number;\n loop?: boolean;\n ampRelease?: number;\n reverse?: boolean;\n stopId: string | number;\n onStart?: (event: NoteEvent) => void;\n onEnded?: (event: NoteEvent) => void;\n};\n\nfunction compose<T>(\n a: ((e: T) => void) | undefined,\n b: ((e: T) => void) | undefined,\n): ((e: T) => void) | undefined {\n if (a && b)\n return (e) => {\n a(e);\n b(e);\n };\n return a ?? b;\n}\n\n/** Empty RegionMatcher used before loadInstrument() is called. */\nconst EMPTY_JSON: SmplrPreset = {\n samples: { baseUrl: \"\", formats: [] },\n groups: [],\n};\n\n/**\n * Detect whether an argument is a SmplrPreset descriptor.\n * SmplrPreset always has a `groups` array; SmplrOptions does not.\n */\nfunction isSmplrJson(x: unknown): x is SmplrPreset {\n return (\n typeof x === \"object\" &&\n x !== null &&\n \"groups\" in x &&\n Array.isArray((x as SmplrPreset).groups)\n );\n}\n\n/**\n * Internal smplr implementation. Loads samples described by a SmplrPreset\n * descriptor, matches notes to regions, and plays them through a Channel.\n *\n * Not exported from the package barrel — third-party plugins receive an\n * instance typed as {@link PluginSmplr} via the {@link Instrument} builder.\n *\n * Pattern A — json provided at construction:\n * `new SmplrImpl(context, json, options?)`\n *\n * Pattern B — json loaded later via loadInstrument():\n * `new SmplrImpl(context, options?)` then `smplr.loadInstrument(json)`\n */\nexport class SmplrImpl implements Smplr {\n /** The AudioContext (or OfflineAudioContext) passed to the constructor. */\n readonly context: BaseAudioContext;\n /** Shared SampleLoader. Read-only on the public surface; injectable via SmplrOptions.loader. */\n readonly loader: SampleLoader;\n /** Shared Scheduler. Read-only on the public surface; injectable via SmplrOptions.scheduler. */\n readonly scheduler: Scheduler;\n\n /**\n * Resolves when the instrument is ready to play. For Pattern A this tracks\n * the constructor-time load; for Pattern B it starts resolved and may be\n * replaced by the {@link Instrument} builder via {@link _setReady}.\n */\n ready: Promise<void>;\n\n #loadProgress: LoadProgress = { loaded: 0, total: 0 };\n #loadToken = 0;\n #buffers: Map<string, AudioBuffer> = new Map();\n #reversedBuffers: Map<string, AudioBuffer> = new Map();\n #defaults: PlaybackParams | undefined;\n #defaultVelocity: number;\n #aliases: Map<string, number> | undefined;\n #matcher: RegionMatcher;\n #voices: VoiceManager;\n #channel: Channel;\n #onLoadProgress: ((progress: LoadProgress) => void) | undefined;\n #onStart: ((event: NoteEvent) => void) | undefined;\n #onEnded: ((event: NoteEvent) => void) | undefined;\n #ccState: Map<number, number> = new Map();\n #disposed = false;\n\n #assertNotDisposed(action: string): void {\n if (this.#disposed) {\n throw Error(`Cannot ${action} on a disposed Smplr instance.`);\n }\n }\n\n constructor(\n context: BaseAudioContext,\n json: SmplrPreset,\n options?: SmplrOptions,\n );\n constructor(context: BaseAudioContext, options?: SmplrOptions);\n constructor(\n context: BaseAudioContext,\n jsonOrOptions?: SmplrPreset | SmplrOptions,\n maybeOptions?: SmplrOptions,\n ) {\n const json = isSmplrJson(jsonOrOptions) ? jsonOrOptions : undefined;\n const options = isSmplrJson(jsonOrOptions)\n ? maybeOptions\n : (jsonOrOptions as SmplrOptions | undefined);\n\n this.context = context;\n this.#defaults = json?.defaults;\n this.#defaultVelocity = options?.velocity ?? 100;\n this.#onLoadProgress = options?.onLoadProgress;\n this.#onStart = options?.onStart;\n this.#onEnded = options?.onEnded;\n\n if (json?.aliases) {\n this.#aliases = new Map(Object.entries(json.aliases));\n }\n\n // 1. Output channel — volume, routing, effects\n this.#channel = new Channel(context, {\n destination: options?.destination,\n volume: options?.volume,\n volumeToGain: options?.volumeToGain,\n pan: options?.pan,\n });\n\n // 2. Scheduler — shared or private\n this.scheduler = options?.scheduler ?? Scheduler(context);\n\n // 3. Region matcher — pre-processes groups/regions once\n this.#matcher = new RegionMatcher(json ?? EMPTY_JSON);\n\n // 4. Voice manager — tracks active voices for stop operations\n this.#voices = new VoiceManager();\n\n // 5. Sample loader — shared or private\n this.loader =\n options?.loader ?? SampleLoader(context, { storage: options?.storage });\n\n if (json) {\n // Pattern A: load immediately\n this.ready = this.loader\n .load(json, (loaded, total) => {\n this.#loadProgress = { loaded, total };\n this.#onLoadProgress?.({ loaded, total });\n })\n .then((buffers) => {\n this.#buffers = buffers;\n });\n } else {\n // Pattern B: resolve immediately; caller will call loadInstrument()\n this.ready = Promise.resolve();\n }\n }\n\n /**\n * @deprecated Use {@link ready} instead. Returns a Promise that resolves\n * to this instance for compatibility with `const x = await new X(ctx).load`.\n */\n get load(): Promise<this> {\n return this.ready.then(() => this);\n }\n\n /**\n * @internal — only the {@link Instrument} builder should call this. Replaces\n * the `ready` promise after plugin setup completes.\n */\n _setReady(p: Promise<void>): void {\n this.ready = p;\n }\n\n /**\n * Load (or replace) the instrument descriptor. All state (matcher, defaults,\n * aliases, reversed-buffer cache, sample buffers) swaps atomically when the\n * load resolves. Concurrent calls are serialized: only the latest call's\n * result is committed; earlier in-flight calls resolve but do not mutate\n * state.\n *\n * Pre-loaded buffers (e.g. base64-decoded) can be passed via the `buffers`\n * parameter — those skip the fetch step.\n */\n loadInstrument(\n json: SmplrPreset,\n buffers?: Map<string, AudioBuffer>,\n ): Promise<void> {\n this.#assertNotDisposed(\"load an instrument\");\n const token = ++this.#loadToken;\n\n return this.loader\n .load(json, {\n buffers,\n onProgress: (loaded, total) => {\n this.#loadProgress = { loaded, total };\n this.#onLoadProgress?.({ loaded, total });\n },\n })\n .then((newBuffers) => {\n if (token !== this.#loadToken) return;\n this.#defaults = json.defaults;\n this.#aliases = json.aliases\n ? new Map(Object.entries(json.aliases))\n : undefined;\n this.#matcher = new RegionMatcher(json);\n this.#reversedBuffers = new Map();\n this.#buffers = newBuffers;\n });\n }\n\n /** Current loading progress snapshot. `total` is known before loading starts. */\n get loadProgress(): LoadProgress {\n return this.#loadProgress;\n }\n\n /** The output channel — use to add effects, adjust volume, or route audio. */\n get output(): OutputChannel {\n return this.#channel;\n }\n\n /**\n * Set a MIDI CC value. Affects region matching for groups/regions that have\n * ccRange constraints (e.g. CC64 sustain pedal).\n */\n setCC(cc: number, value: number): void {\n this.#assertNotDisposed(\"set CC\");\n this.#ccState.set(cc, value);\n }\n\n /**\n * Read the latest value set via {@link setCC}. Returns `0` for any CC that\n * has not been set (matches MIDI's \"undefined controller defaults to 0\"\n * convention).\n */\n getCC(cc: number): number {\n this.#assertNotDisposed(\"read CC\");\n return this.#ccState.get(cc) ?? 0;\n }\n\n /**\n * Set the cents detune applied to every future note. Mutates the instrument's\n * playback defaults in place; takes effect on notes scheduled after the call.\n * In-flight notes are unaffected.\n */\n setDetune(cents: number): void {\n this.#assertNotDisposed(\"set detune\");\n if (!this.#defaults) this.#defaults = {};\n this.#defaults.detune = cents;\n }\n\n /**\n * Set whether every future note plays its sample reversed. The reversed-buffer\n * cache is populated lazily on demand; no cache invalidation is needed in\n * either direction.\n */\n setReverse(reverse: boolean): void {\n this.#assertNotDisposed(\"set reverse\");\n if (!this.#defaults) this.#defaults = {};\n this.#defaults.reverse = reverse;\n }\n\n /**\n * Start playing a note. Returns a StopFn that cancels the note if it hasn't\n * played yet, or stops the resulting voices if it has.\n */\n start(event: NoteEvent): StopFn {\n this.#assertNotDisposed(\"start a note\");\n const normalized = this.#normalizeNoteEvent(event);\n\n const schedulerStop = this.scheduler.schedule(\n normalized as NoteEvent,\n (e) => this.#playNote(e as NormalizedNoteEvent),\n );\n\n return (time?: number) => {\n schedulerStop(); // cancel from queue if not yet dispatched\n this.#voices.stopById(normalized.stopId, time); // stop if already playing\n };\n }\n\n /**\n * Stop voices.\n *\n * - No argument → stop all active voices\n * - String or number → stop all voices with that stopId\n * - `{ stopId }` → stop voices with that stopId, optionally at a future time\n * - `{ time }` (no stopId) → stop all voices at a future time\n */\n stop(target?: StopTarget): void {\n this.#assertNotDisposed(\"stop voices\");\n if (target === undefined) {\n this.#voices.stopAll();\n } else if (typeof target === \"string\" || typeof target === \"number\") {\n this.#voices.stopById(target);\n } else {\n if (target.stopId !== undefined) {\n this.#voices.stopById(target.stopId, target.time);\n } else {\n this.#voices.stopAll(target.time);\n }\n }\n }\n\n /**\n * Stop all voices, dispose the output channel, and stop the scheduler.\n * The instance must not be used after this call — subsequent\n * `start`/`stop`/`setCC`/`getCC`/`loadInstrument` calls throw.\n * Subsequent `dispose()` calls are no-ops.\n */\n dispose(): void {\n if (this.#disposed) return;\n this.#disposed = true;\n this.#voices.stopAll();\n this.#channel.disconnect();\n this.scheduler.stop();\n }\n\n /** @deprecated Use {@link dispose} instead. */\n disconnect(): void {\n this.dispose();\n }\n\n #getBuffer(sample: string, reverse: boolean): AudioBuffer | undefined {\n if (!reverse) return this.#buffers.get(sample);\n const cached = this.#reversedBuffers.get(sample);\n if (cached) return cached;\n const original = this.#buffers.get(sample);\n if (!original) return undefined;\n const reversed = this.context.createBuffer(\n original.numberOfChannels,\n original.length,\n original.sampleRate,\n );\n for (let ch = 0; ch < original.numberOfChannels; ch++) {\n const data = original.getChannelData(ch).slice().reverse();\n reversed.copyToChannel(data, ch);\n }\n this.#reversedBuffers.set(sample, reversed);\n return reversed;\n }\n\n #playNote(event: NormalizedNoteEvent): void {\n const {\n midi,\n velocity,\n time,\n stopId,\n duration,\n detune,\n lpfCutoffHz,\n loop,\n ampRelease,\n reverse,\n onStart,\n onEnded,\n } = event;\n\n const matches = this.#matcher.match(midi, velocity, this.#ccState);\n\n // Stop exclusive groups before starting new voices\n for (const match of matches) {\n if (match.offBy !== undefined) {\n this.#voices.stopGroup(match.offBy, time);\n }\n }\n\n // Create a voice for each matched region\n let voiceStarted = false;\n const effectiveReverse = reverse ?? this.#defaults?.reverse ?? false;\n for (const match of matches) {\n const buffer = this.#getBuffer(match.sample, effectiveReverse);\n if (!buffer) continue;\n\n const params = resolveParams(\n this.#defaults,\n match.groupRef,\n match.regionRef,\n midi,\n velocity,\n { detune, lpfCutoffHz, loop, ampRelease, reverse },\n );\n\n const voice = new Voice(\n this.context,\n buffer,\n params,\n this.#channel.input,\n stopId,\n match.group,\n time,\n );\n\n this.#voices.add(voice);\n\n // onStart fires once on the first matched voice\n if (!voiceStarted) {\n onStart?.(event);\n voiceStarted = true;\n }\n\n // onEnded fires once per voice when its audio node ends\n if (onEnded) {\n voice.onEnded(() => onEnded(event));\n }\n\n // Auto-stop for duration — schedule directly on the audio timeline\n // so it works in both real-time and offline (OfflineAudioContext) contexts.\n if (duration != null) {\n const startT = time ?? this.context.currentTime;\n const releaseAt = startT + duration;\n voice.stop(releaseAt);\n }\n }\n }\n\n #normalizeNoteEvent(event: NoteEvent): NormalizedNoteEvent {\n if (typeof event === \"string\" || typeof event === \"number\") {\n const midi = toMidi(event) ?? this.#aliases?.get(String(event)) ?? 0;\n return {\n note: event,\n midi,\n velocity: this.#defaultVelocity,\n stopId: event,\n onStart: this.#onStart,\n onEnded: this.#onEnded,\n };\n }\n const midi =\n toMidi(event.note) ?? this.#aliases?.get(String(event.note)) ?? 0;\n return {\n ...event,\n midi,\n velocity: event.velocity ?? this.#defaultVelocity,\n stopId: event.stopId ?? event.note,\n onStart: compose(this.#onStart, event.onStart),\n onEnded: compose(this.#onEnded, event.onEnded),\n };\n }\n}\n","import type { OutputChannel } from \"./channel\";\nimport type { SampleLoader } from \"./sample-loader\";\nimport type { Scheduler } from \"./scheduler\";\nimport { SmplrImpl, type SmplrOptions } from \"./smplr\";\nimport type {\n LoadProgress,\n NoteEvent,\n SmplrPreset,\n StopFn,\n StopTarget,\n} from \"./types\";\n\n/**\n * Public Smplr interface — the type plugin authors, helper functions, and\n * users program against. Mirrors the surface of the underlying SmplrImpl\n * class, minus internal helpers.\n *\n * `loadInstrument` is intentionally *not* on this interface — it's the\n * plugin-side API, exposed via {@link PluginSmplr} to plugin bodies only.\n */\nexport interface Smplr {\n readonly context: BaseAudioContext;\n\n /** Resolves when the instrument is ready to play. Preferred over `load`. */\n readonly ready: Promise<void>;\n\n /**\n * @deprecated Use `ready` instead. Returns a Promise that resolves to the\n * instrument for compatibility with `const x = await new X(ctx).load`.\n */\n readonly load: Promise<Smplr>;\n\n readonly output: OutputChannel;\n\n /** Shared with other instruments via SmplrOptions.loader. */\n readonly loader: SampleLoader;\n\n /** Shared with other instruments via SmplrOptions.scheduler. */\n readonly scheduler: Scheduler;\n\n readonly loadProgress: LoadProgress;\n\n start(event: NoteEvent): StopFn;\n stop(target?: StopTarget): void;\n setCC(cc: number, value: number): void;\n\n /**\n * Read the latest value set via `setCC`. Returns `0` for any CC that has\n * not been set (matches MIDI's \"undefined controller defaults to 0\" convention).\n */\n getCC(cc: number): number;\n\n /**\n * Set the cents detune applied to every future note. Mutates the instrument's\n * playback defaults in place; takes effect on notes scheduled after the call.\n * In-flight notes are unaffected.\n */\n setDetune(cents: number): void;\n\n /**\n * Set whether every future note plays its sample reversed. Mutates the\n * instrument's playback defaults in place. The reversed-buffer cache is\n * populated lazily on demand; no cache invalidation is needed in either\n * direction.\n */\n setReverse(reverse: boolean): void;\n\n /**\n * Stop all voices, dispose the output channel, and stop the scheduler.\n * The instance must not be used after this call — subsequent `start`/`stop`/\n * `setCC`/`getCC`/`setControlValue`/`loadInstrument` calls throw. Subsequent\n * `dispose()` calls are no-ops.\n */\n dispose(): void;\n\n /** @deprecated Use `dispose()` instead. */\n disconnect(): void;\n}\n\n/**\n * Plugin-facing widening of {@link Smplr} that exposes `loadInstrument` —\n * the primary plugin → smplr API for wiring an async-loaded JSON.\n *\n * This interface is *not* exported from the package barrel. Plugin authors\n * receive it as the third argument to their {@link SmplrPlugin}.\n */\nexport interface PluginSmplr extends Smplr {\n /**\n * Replace the current instrument JSON and re-fetch buffers. Pre-decoded\n * buffers (e.g. base64-decoded from a soundfont) can be passed via the\n * `buffers` parameter.\n *\n * Resolves when all samples are ready.\n */\n loadInstrument(\n json: SmplrPreset,\n buffers?: Map<string, AudioBuffer>,\n ): Promise<void>;\n}\n\n/**\n * Permitted return shapes for an {@link SmplrPlugin}:\n *\n * - `void` — sync plugin, no async load, no extras\n * - `Promise<void>` — async load, no extras\n * - `{ extras: E; ready: Promise<void> }` — sync extras + async load\n * - `{ ready: Promise<void> }` — async load, no extras (explicit form)\n *\n * Extras keys are merged onto the smplr instance via `Object.assign` and\n * may shadow base {@link Smplr} methods (e.g. DrumMachine overrides `start`\n * to inject `stopId: sample.note`). For sync extras with no async load,\n * use `{ extras, ready: Promise.resolve() }`.\n */\nexport type SmplrPluginResult<E extends object> =\n | void\n | Promise<void>\n | { extras: E; ready: Promise<void> }\n | { ready: Promise<void> };\n\n/**\n * Plugin signature. Receives the audio context, the user options (with\n * SmplrOptions keys already stripped by the {@link Instrument} builder),\n * and a {@link PluginSmplr} the plugin can wire up.\n */\nexport type SmplrPlugin<O, E extends object = {}> = (\n ctx: BaseAudioContext,\n options: O,\n smplr: PluginSmplr,\n) => SmplrPluginResult<E>;\n\n/**\n * The dual call/construct factory produced by {@link Instrument}. Callable\n * without `new` (preferred) or with `new` (kept for compatibility with\n * pre-1.0 examples).\n */\n/**\n * The full instance type produced by an {@link InstrumentFactory} — a Smplr\n * with its plugin extras, plus a `load` Promise refined to resolve back to\n * the same intersection (so `await x.load` preserves the extras shape).\n */\nexport type InstrumentInstance<E extends object = {}> = Smplr &\n E & { readonly load: Promise<Smplr & E> };\n\nexport type InstrumentFactory<O, E extends object = {}> = {\n (\n ctx: BaseAudioContext,\n options?: O & Partial<SmplrOptions>,\n ): InstrumentInstance<E>;\n\n /**\n * @deprecated Call as a function: `MyInstrument(ctx, opts)` instead of\n * `new MyInstrument(...)`. Kept for compatibility with pre-1.0 examples.\n */\n new (\n ctx: BaseAudioContext,\n options?: O & Partial<SmplrOptions>,\n ): InstrumentInstance<E>;\n};\n\nconst SMPLR_OPTION_KEYS = [\n \"storage\",\n \"destination\",\n \"volume\",\n \"volumeToGain\",\n \"pan\",\n \"velocity\",\n \"loader\",\n \"scheduler\",\n \"onLoadProgress\",\n \"onStart\",\n \"onEnded\",\n] as const;\n\nfunction splitOptions<O>(options: O & Partial<SmplrOptions>): {\n smplrOpts: SmplrOptions;\n pluginOpts: O;\n} {\n // SmplrOptions keys are *copied*, not moved — plugins may also depend on\n // them (e.g. Sampler uses `storage` to fetch URL-loaded buffers in addition\n // to SmplrImpl using it for its internal SampleLoader).\n const src = (options ?? {}) as Record<string, unknown>;\n const smplrOpts: Record<string, unknown> = {};\n for (const key of SMPLR_OPTION_KEYS) {\n if (key in src) smplrOpts[key] = src[key];\n }\n return { smplrOpts: smplrOpts as SmplrOptions, pluginOpts: options as O };\n}\n\nfunction isPromise(x: unknown): x is Promise<unknown> {\n return (\n typeof x === \"object\" &&\n x !== null &&\n typeof (x as { then?: unknown }).then === \"function\"\n );\n}\n\n/**\n * Merge each own property of `extras` onto `target`, preserving property\n * descriptors (so getters stay live). `Object.assign` would *invoke* each\n * getter and copy the result as a data property — that snapshot would lose\n * the closure-captured state plugins use for extras like\n * `Soundfont2Sampler.instrumentNames`.\n */\nfunction mergeExtras(target: object, extras: object): void {\n for (const key of Object.getOwnPropertyNames(extras)) {\n const desc = Object.getOwnPropertyDescriptor(extras, key);\n if (desc) Object.defineProperty(target, key, desc);\n }\n}\n\n/**\n * Builder for smplr instruments. Wraps a plugin function into a dual\n * call/construct factory that produces ready-to-play {@link Smplr} instances\n * augmented with plugin extras.\n *\n * ```ts\n * type MyOptions = { instrument: string };\n *\n * export const MyInstrument = Instrument<MyOptions>((ctx, options, smplr) => {\n * return smplr.loadInstrument(fetchJson(options.instrument));\n * });\n *\n * const inst = MyInstrument(ctx, { instrument: \"piano\", volume: 80 });\n * await inst.ready;\n * inst.start(\"C4\");\n * ```\n */\nexport function Instrument<O, E extends object = {}>(\n plugin: SmplrPlugin<O, E>,\n): InstrumentFactory<O, E> {\n function factory(\n ctx: BaseAudioContext,\n options?: O & Partial<SmplrOptions>,\n ): InstrumentInstance<E> {\n const { smplrOpts, pluginOpts } = splitOptions(\n (options ?? {}) as O & Partial<SmplrOptions>,\n );\n const smplr = new SmplrImpl(ctx, smplrOpts);\n const result: unknown = plugin(ctx, pluginOpts, smplr);\n\n let readyPromise: Promise<void> = Promise.resolve();\n\n if (result != null) {\n if (isPromise(result)) {\n readyPromise = result as Promise<void>;\n } else if (typeof result === \"object\") {\n const maybe = result as { extras?: object; ready?: Promise<void> };\n if (maybe.extras) mergeExtras(smplr, maybe.extras);\n if (isPromise(maybe.ready)) readyPromise = maybe.ready;\n }\n }\n\n smplr._setReady(readyPromise);\n return smplr as unknown as InstrumentInstance<E>;\n }\n\n return factory as unknown as InstrumentFactory<O, E>;\n}\n","import { Storage } from \"../storage\";\n\nexport function isDrumMachineInstrument(\n instrument: any,\n): instrument is DrumMachineInstrument {\n return (\n typeof instrument === \"object\" &&\n typeof instrument.baseUrl === \"string\" &&\n typeof instrument.name === \"string\" &&\n Array.isArray(instrument.samples) &&\n Array.isArray(instrument.groupNames) &&\n typeof instrument.nameToSampleName === \"object\" &&\n typeof instrument.sampleGroupVariations === \"object\"\n );\n}\n\nexport type DrumMachineInstrument = {\n baseUrl: string;\n name: string;\n samples: string[];\n groupNames: string[];\n nameToSampleName: Record<string, string | undefined>;\n sampleGroupVariations: Record<string, string[]>;\n};\nexport const EMPTY_INSTRUMENT: DrumMachineInstrument = {\n baseUrl: \"\",\n name: \"\",\n samples: [],\n groupNames: [],\n nameToSampleName: {},\n sampleGroupVariations: {},\n};\n\nexport async function fetchDrumMachineInstrument(\n url: string,\n storage: Storage,\n): Promise<DrumMachineInstrument> {\n const res = await storage.fetch(url);\n const json = await res.json();\n // need to fix json\n json.baseUrl = url.replace(\"/dm.json\", \"\");\n json.groupNames = [];\n json.nameToSampleName = {};\n json.sampleGroupVariations = {};\n for (const sample of json.samples) {\n json.nameToSampleName[sample] = sample;\n const separator = sample.indexOf(\"/\") !== -1 ? \"/\" : \"-\";\n const [base, variation] = sample.split(separator);\n if (!json.groupNames.includes(base)) {\n json.groupNames.push(base);\n }\n json.nameToSampleName[base] ??= sample;\n json.sampleGroupVariations[base] ??= [];\n if (variation) {\n json.sampleGroupVariations[base].push(`${base}${separator}${variation}`);\n }\n }\n\n return json;\n}\n","import { HttpStorage, Storage } from \"../storage\";\nimport { Instrument } from \"../smplr\";\nimport {\n LoadProgress,\n NoteEvent,\n SmplrGroup,\n SmplrPreset,\n StopFn,\n} from \"../smplr/types\";\nimport {\n DrumMachineInstrument,\n EMPTY_INSTRUMENT,\n fetchDrumMachineInstrument,\n isDrumMachineInstrument,\n} from \"./dm-instrument\";\n\nexport function getDrumMachineNames() {\n return Object.keys(INSTRUMENTS);\n}\n\nconst INSTRUMENTS: Record<string, string> = {\n \"TR-808\": \"https://smpldsnds.github.io/drum-machines/TR-808/dm.json\",\n \"Casio-RZ1\": \"https://smpldsnds.github.io/drum-machines/Casio-RZ1/dm.json\",\n \"LM-2\": \"https://smpldsnds.github.io/drum-machines/LM-2/dm.json\",\n \"MFB-512\": \"https://smpldsnds.github.io/drum-machines/MFB-512/dm.json\",\n \"Roland CR-8000\":\n \"https://smpldsnds.github.io/drum-machines/Roland-CR-8000/dm.json\",\n};\n\ntype DrumMachineConfig = {\n instrument: string | DrumMachineInstrument;\n url: string;\n storage: Storage;\n};\n\nexport type DrumMachineOptions = Partial<\n DrumMachineConfig & {\n destination?: AudioNode;\n volume?: number;\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nfunction getConfig(options?: DrumMachineOptions): DrumMachineConfig {\n const config = {\n instrument: options?.instrument ?? \"TR-808\",\n storage: options?.storage ?? HttpStorage,\n url: options?.url ?? \"\",\n };\n if (typeof config.instrument === \"string\") {\n config.url ||= INSTRUMENTS[config.instrument];\n if (!config.url)\n throw new Error(\"Invalid instrument: \" + config.instrument);\n } else if (!isDrumMachineInstrument(config.instrument)) {\n throw new Error(\"Invalid instrument: \" + config.instrument);\n }\n\n return config;\n}\n\ntype DrumMachineExtras = {\n getSampleNames(): string[];\n getGroupNames(): string[];\n getSampleNamesForGroup(groupName: string): string[];\n start(event: NoteEvent): StopFn;\n};\n\nexport const DrumMachine = Instrument(\n (ctx: BaseAudioContext, options: DrumMachineOptions = {}, smplr) => {\n const config = getConfig(options);\n\n // Mutable closure state — extras read this; the load promise populates it.\n let instrument: DrumMachineInstrument = EMPTY_INSTRUMENT;\n\n // Capture the base `start` *before* Object.assign(smplr, extras) shadows\n // it — otherwise the override below would recurse into itself.\n const baseStart = smplr.start.bind(smplr);\n\n const extras: DrumMachineExtras = {\n getSampleNames: () => instrument.samples.slice(),\n getGroupNames: () => instrument.groupNames.slice(),\n getSampleNamesForGroup: (groupName) =>\n instrument.sampleGroupVariations[groupName] ?? [],\n\n // Override start() to inject stopId so re-triggering the same drum\n // cuts the previous voice (one-shot-per-drum semantic).\n start: (sample) => {\n const s = typeof sample === \"object\" ? sample : { note: sample };\n return baseStart({\n ...s,\n stopId:\n (s as { stopId?: string | number; note: string | number }).stopId ??\n s.note,\n });\n },\n };\n\n const instrumentPromise = isDrumMachineInstrument(config.instrument)\n ? Promise.resolve(config.instrument)\n : fetchDrumMachineInstrument(config.url, config.storage);\n\n const ready = instrumentPromise.then((inst) => {\n instrument = inst;\n return smplr.loadInstrument(drumMachineToPreset(inst));\n });\n\n return { extras, ready };\n },\n);\n\n/** Instance type returned by the {@link DrumMachine} factory. */\nexport type DrumMachine = ReturnType<typeof DrumMachine>;\n\n// ---------------------------------------------------------------------------\n// drumMachineToPreset — pure converter function\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a DrumMachineInstrument to a SmplrPreset descriptor.\n *\n * Each sample gets a sequential MIDI number starting at 36 (GM drum map base).\n * Aliases are created for both the full sample name (\"kick/1\") and the group\n * name (\"kick\") so both forms work with Smplr.start({ note: \"kick\" }).\n */\nexport function drumMachineToPreset(\n instrument: DrumMachineInstrument,\n): SmplrPreset {\n const aliases: Record<string, number> = {};\n const regions: SmplrGroup[\"regions\"] = [];\n\n const BASE_MIDI = 36;\n\n instrument.samples.forEach((sampleName, i) => {\n const midi = BASE_MIDI + i;\n\n // Full sample name alias: \"kick/1\" → midi\n aliases[sampleName] = midi;\n\n regions.push({\n sample: sampleName,\n keyRange: [midi, midi],\n pitch: midi,\n });\n });\n\n // Group name aliases: \"kick\" → first sample MIDI\n for (const [groupName, firstSample] of Object.entries(\n instrument.nameToSampleName,\n )) {\n if (firstSample) {\n const idx = instrument.samples.indexOf(firstSample);\n if (idx >= 0) {\n aliases[groupName] = BASE_MIDI + idx;\n }\n }\n }\n\n return {\n samples: {\n baseUrl: instrument.baseUrl,\n formats: [\"ogg\", \"m4a\"],\n },\n groups: [{ regions }],\n aliases,\n };\n}\n","// DrumAbuse — smplr instrument for the Synthabuse drum-machine sample collection.\n//\nimport { HttpStorage, type Storage } from \"../storage\";\nimport { Instrument } from \"../smplr\";\nimport type {\n LoadProgress,\n NoteEvent,\n SmplrPreset,\n StopFn,\n} from \"../smplr/types\";\n\nconst DEFAULT_BASE_URL = \"https://smpldsnds.github.io\";\nconst MIDI_BASE = 36;\n\nexport const DRUM_ABUSE_PACKS = [\n \"vol1\",\n \"vol2\",\n \"vol3\",\n \"vol4\",\n \"vol5\",\n] as const;\nexport type DrumAbusePackId = (typeof DRUM_ABUSE_PACKS)[number];\n\nconst MACHINES_BY_PACK: Record<DrumAbusePackId, readonly string[]> = {\n vol1: [\n \"4-inthefloor-percussioncombo\",\n \"ace-tone-rhythm-ace-fr-1\",\n \"ace-tone-rhythm-ace-fr-7l\",\n \"ace-tone-rhythm-ace-fr6\",\n \"ace-tone-rhythm-king\",\n \"ace-tone-rhythm-master\",\n \"antonelli-2377\",\n \"arp-axxe\",\n \"conn-min-o-matic\",\n \"eko-compu-rhythm\",\n \"eko-ritmo-12\",\n \"eko-ritmo-20\",\n \"elgam-carousel\",\n \"emu-modular\",\n \"farfisa-pro\",\n \"farfisa-rhythm-10\",\n \"farfisa-rhythm-maker-16\",\n \"gibson-maestro-g-2\",\n \"gibson-maestro-rhythm-jester\",\n \"gibson-maestro-rhythm-king-mrk-1\",\n \"gulbransen-organ\",\n \"hammond-rhythm\",\n \"hammond-rhythm-ii\",\n \"hohner-automatic-rhythm-player\",\n \"jen-sx-1000\",\n \"kay-r-8\",\n \"keio-checkmate\",\n \"kent-k-200\",\n \"kent-rhythm-master\",\n \"korg-kr-33\",\n \"korg-krz\",\n \"korg-minipops-series\",\n \"korg-s-3\",\n \"korg-univox-micro-rhythmer-12\",\n \"korg-univox-sr-120\",\n \"korg-univox-sr-95\",\n \"luxor-passat\",\n \"moog-modular-55\",\n \"roland-arr\",\n \"roland-edp-1\",\n \"roland-sh-3a\",\n \"roland-system-100\",\n \"roland-tr-1-prototype\",\n \"roland-tr-33\",\n \"roland-tr-41-prototype\",\n \"roland-tr-66\",\n \"roland-tr-77\",\n \"seeburg-rhythm-prince\",\n \"seeburg-select-a-rhythm\",\n \"solton-disco-64\",\n \"sonor-mini-mammut-module\",\n \"video-tech-rythmic-10\",\n \"vox-percussion-king\",\n \"whippany-melo-sonic-350\",\n \"wurlitzer-swinging-rhythm\",\n \"yamaha-cs-15d\",\n \"yamaha-cs-5\",\n \"yamaha-cs-6\",\n \"yamaha-ps-1\",\n \"yamaha-ps-2\",\n \"yamaha-ps-3\",\n ],\n vol2: [\n \"bontempi-hf222\",\n \"boss-dr-55\",\n \"casio-mt-18\",\n \"casio-pt-30\",\n \"casio-vl-1\",\n \"chaser-computer-drum-pr-80\",\n \"crb-rhythmboy-480\",\n \"eko-musicbox-12\",\n \"electro-harmonix-drm-15\",\n \"electro-harmonix-drm-16\",\n \"electro-harmonix-spacedrum\",\n \"elka-drumstar-80\",\n \"elka-x-1000\",\n \"emu-e-drum\",\n \"gem-drum-15\",\n \"hammond-autovari-64\",\n \"hohner-rhythm-80k\",\n \"korg-kpr-77\",\n \"korg-kr-55\",\n \"korg-kr-mini\",\n \"korg-monopoly\",\n \"korg-ms-10\",\n \"korg-trident\",\n \"linn-lm-1\",\n \"monacor-rhythmical-choice\",\n \"mti-auto-orchestra-ao-1\",\n \"multi-moog\",\n \"mxr-185\",\n \"new-england-digital-synclavier\",\n \"oberheim-dmx\",\n \"pearl-drum-x\",\n \"pollard-syndrum-178\",\n \"roland-cr-1000\",\n \"roland-cr-68\",\n \"roland-cr-78\",\n \"roland-cr-80\",\n \"roland-cr-8000\",\n \"roland-dr-55\",\n \"roland-jupiter-8\",\n \"roland-pb-300-rhythm-plus\",\n \"roland-rhy-33\",\n \"roland-rhy-55\",\n \"roland-sh-09\",\n \"roland-tr-55\",\n \"roland-tr-606\",\n \"roland-tr-808\",\n \"simmons-drum\",\n \"simmons-sds-1\",\n \"simmons-sds-5\",\n \"solton-programmer-24\",\n \"star-instruments-synare-3\",\n \"star-instruments-synare-ps-1\",\n \"visco-space-drum\",\n \"watford-electronics-rhythm-generator\",\n \"yamaha-cs-40m\",\n \"yamaha-mr-10\",\n \"yamaha-ps-55\",\n ],\n vol3: [\n \"amdek-pck-100\",\n \"austin-arb-6\",\n \"bme-rattlesnake-parametric-percussion-system\",\n \"boss-dr-110\",\n \"casio-mt-100\",\n \"coron-drumsynce-ds-7\",\n \"coron-rds\",\n \"denon-crb-90\",\n \"drumfire-df-2000\",\n \"drumfire-df-500\",\n \"electro-harmonix-drm-32\",\n \"emu-drumulator\",\n \"kay-drm-1\",\n \"korg-ddm-110\",\n \"korg-ddm-220\",\n \"korg-poly-800\",\n \"linn-linndrum-lm-1-vinyl\",\n \"linn-lm-2\",\n \"mattel-electronics-synsonics-drm\",\n \"mattel-electronics-synsonics-pro\",\n \"panasonic-rd-9844\",\n \"pearl-drx-1\",\n \"roland-ddr-30\",\n \"roland-mc-202\",\n \"roland-rhy-77\",\n \"roland-tr-909\",\n \"rsf-dd-30\",\n \"sakata-dpm-48\",\n \"sequential-circuits-drumtraks\",\n \"simmons-clap-trap\",\n \"simmons-sds-200\",\n \"simmons-sds-400\",\n \"soundmaster-sm-8\",\n \"soundmaster-sr-88\",\n \"tama-ts-206\",\n \"tama-ts-305\",\n \"wersi-wm-24\",\n \"yamaha-dx7\",\n ],\n vol4: [\n \"atlantex-mpc-1\",\n \"boss-hc-2\",\n \"boss-pc-2\",\n \"casio-ct-310\",\n \"casio-mt-500\",\n \"casio-mt-800\",\n \"casio-pt-68\",\n \"casio-pt-82\",\n \"casio-sk-1\",\n \"dr-b-hm-digital-drums\",\n \"emu-sp-12\",\n \"ensoniq-mirage\",\n \"hing-hon-ek-001\",\n \"kawai-acr-20\",\n \"kawai-sx-240\",\n \"klone-dual-percussion-synthesiser\",\n \"korg-ddd-1\",\n \"korg-pss-50\",\n \"kurzweil-electrodrum-prototype\",\n \"linn-9000\",\n \"linn-linndrum-lm-2-vinyl\",\n \"nasta-hitstix-2\",\n \"oberheim-dx\",\n \"pearl-sc-40\",\n \"rhodes-polaris\",\n \"roland-juno-106\",\n \"roland-super-quartet-mks-7\",\n \"roland-tr-707\",\n \"roland-tr-727\",\n \"siel-mdp-40\",\n \"simmons-sds-1000\",\n \"simmons-sds-7\",\n \"simmons-sds-8\",\n \"simmons-sds-9\",\n \"sony-drp-1\",\n \"soundmaster-stix-st-305\",\n \"suzuki-rpm-40\",\n \"tama-ts-500\",\n \"technics-ax-5\",\n \"technics-pcm-dp-50\",\n \"wersi-prisma-dx-5\",\n \"yamaha-dd-5\",\n \"yamaha-rx-11\",\n \"yamaha-rx-15\",\n \"yamaha-rx-21\",\n \"yamaha-rx-5\",\n ],\n vol5: [\n \"boss-dr-pad-drp-i\",\n \"casio-ct-403\",\n \"casio-cz-230s\",\n \"casio-ht-700\",\n \"casio-rz-1\",\n \"cheetah-spec-drum\",\n \"forat-f-9000\",\n \"korg-ddd-5\",\n \"korg-dss-1\",\n \"m-p-c-electronics-dsm-1\",\n \"pearl-sy-1\",\n \"roland-tr-505\",\n \"sequential-circuits-studio-440\",\n \"simmons-sds-2000\",\n \"simmons-sdx\",\n \"yamaha-pss-130\",\n \"yamaha-ptx8\",\n \"yamaha-rx-21l\",\n ],\n};\n\nconst machineToPack: ReadonlyMap<string, DrumAbusePackId> = (() => {\n const m = new Map<string, DrumAbusePackId>();\n for (const pack of DRUM_ABUSE_PACKS) {\n for (const id of MACHINES_BY_PACK[pack]) m.set(id, pack);\n }\n return m;\n})();\n\nexport function getDrumAbuseMachineNames(): string[] {\n return [...machineToPack.keys()];\n}\n\nexport function getDrumAbuseMachinesForPack(\n pack: DrumAbusePackId,\n): readonly string[] {\n return MACHINES_BY_PACK[pack];\n}\n\nexport function getDrumAbusePackNames(): readonly DrumAbusePackId[] {\n return DRUM_ABUSE_PACKS;\n}\n\nexport function getDrumAbuseMachinePack(\n id: string,\n): DrumAbusePackId | undefined {\n return machineToPack.get(id);\n}\n\n// ---- URL helpers ------------------------------------------------------------\n\nconst encSeg = (s: string) => s.split(\"/\").map(encodeURIComponent).join(\"/\");\n\nfunction packBase(baseUrl: string, pack: DrumAbusePackId): string {\n return `${baseUrl}/drum-abuse-${pack}`;\n}\n\nfunction sampleBaseUrl(\n baseUrl: string,\n pack: DrumAbusePackId,\n urlPath: string,\n): string {\n return `${packBase(baseUrl, pack)}/samples/${encSeg(urlPath)}/`;\n}\n\n/** Build a full sample URL. Exported so external row-level Sampler use\n * (e.g. the sequencer engine) can share the same URL convention. */\nexport function drumAbuseSampleUrl(\n pack: DrumAbusePackId,\n urlPath: string,\n fileNoExt: string,\n format = \"wav\",\n baseUrl = DEFAULT_BASE_URL,\n): string {\n return `${sampleBaseUrl(baseUrl, pack, urlPath)}${encodeURIComponent(fileNoExt)}.${format}`;\n}\n\nfunction stripExt(filename: string): string {\n return filename.replace(/\\.[^.]+$/, \"\");\n}\n\n// ---- Repo JSON types (private) ---------------------------------------------\n\ntype RepoSampleSet = {\n path: string;\n set: string;\n url_path: string;\n samples: string[];\n sample_instruments: string[];\n};\n\ntype RepoMachine = {\n id: string;\n sample_sets: RepoSampleSet[];\n};\n\ntype RepoPackSample = {\n machine_id: string;\n url_path: string;\n file: string;\n};\n\n// ---- Fetch layer ------------------------------------------------------------\n\nconst jsonCache = new Map<string, Promise<unknown>>();\n\nfunction fetchJSON<T>(url: string, storage: Storage): Promise<T> {\n let p = jsonCache.get(url) as Promise<T> | undefined;\n if (!p) {\n p = storage.fetch(url).then((r) => {\n if (r.status >= 400) throw new Error(`DrumAbuse: ${r.status} ${url}`);\n return r.json() as Promise<T>;\n });\n jsonCache.set(url, p);\n }\n return p;\n}\n\n// ---- Preset builders --------------------------------------------------------\n\ntype BuiltPreset = {\n preset: SmplrPreset;\n sampleNames: string[];\n groupNames: string[];\n sampleNamesForGroup: Record<string, string[]>;\n setPath: string | null;\n};\n\nfunction buildMachinePreset(\n machine: RepoMachine,\n setPath: string | undefined,\n baseUrl: string,\n pack: DrumAbusePackId,\n): BuiltPreset {\n if (machine.sample_sets.length === 0) {\n throw new Error(`DrumAbuse: machine \"${machine.id}\" has no sample sets`);\n }\n const set = setPath\n ? machine.sample_sets.find((s) => s.path === setPath)\n : machine.sample_sets[0];\n if (!set) {\n throw new Error(`DrumAbuse: set \"${setPath}\" not found on \"${machine.id}\"`);\n }\n if (set.samples.length === 0) {\n throw new Error(\n `DrumAbuse: set \"${set.path}\" of \"${machine.id}\" has no samples`,\n );\n }\n\n const sampleNames: string[] = [];\n const groupNames: string[] = [];\n const sampleNamesForGroup: Record<string, string[]> = {};\n const aliases: Record<string, number> = {};\n const regions = set.samples.map((file, i) => {\n const key = stripExt(file);\n const midi = MIDI_BASE + i;\n sampleNames.push(key);\n aliases[key] = midi;\n const group = set.sample_instruments[i] || \"\";\n if (group) {\n if (!sampleNamesForGroup[group]) {\n sampleNamesForGroup[group] = [];\n groupNames.push(group);\n aliases[group] = midi;\n }\n sampleNamesForGroup[group].push(key);\n }\n return {\n sample: key,\n keyRange: [midi, midi] as [number, number],\n pitch: midi,\n };\n });\n\n return {\n preset: {\n samples: {\n baseUrl: sampleBaseUrl(baseUrl, pack, set.url_path),\n formats: [\"wav\"],\n },\n groups: [{ regions }],\n aliases,\n },\n sampleNames,\n groupNames,\n sampleNamesForGroup,\n setPath: set.path,\n };\n}\n\nfunction buildPackPreset(\n list: RepoPackSample[],\n baseUrl: string,\n pack: DrumAbusePackId,\n): BuiltPreset {\n if (list.length === 0) {\n throw new Error(`DrumAbuse: empty pack-instrument list for pack \"${pack}\"`);\n }\n\n // First pass: count filename collisions so unique short aliases stay unique.\n const fileCount: Record<string, number> = {};\n for (const s of list) {\n const f = stripExt(s.file);\n fileCount[f] = (fileCount[f] ?? 0) + 1;\n }\n\n const sampleNames: string[] = [];\n const groupNames: string[] = [];\n const sampleNamesForGroup: Record<string, string[]> = {};\n const map: Record<string, string> = {};\n const aliases: Record<string, number> = {};\n\n const regions = list.map((s, i) => {\n const fileKey = stripExt(s.file);\n const uniqueKey = `${s.machine_id}/${fileKey}`;\n const midi = MIDI_BASE + i;\n sampleNames.push(uniqueKey);\n aliases[uniqueKey] = midi;\n if (fileCount[fileKey] === 1) aliases[fileKey] = midi;\n map[uniqueKey] =\n `${packBase(baseUrl, pack)}/samples/${encSeg(s.url_path)}/${encodeURIComponent(s.file)}`;\n\n if (!sampleNamesForGroup[s.machine_id]) {\n sampleNamesForGroup[s.machine_id] = [];\n groupNames.push(s.machine_id);\n aliases[s.machine_id] = midi;\n }\n sampleNamesForGroup[s.machine_id].push(uniqueKey);\n\n return {\n sample: uniqueKey,\n keyRange: [midi, midi] as [number, number],\n pitch: midi,\n };\n });\n\n return {\n preset: {\n samples: { baseUrl: \"\", formats: [\"wav\"], map },\n groups: [{ regions }],\n aliases,\n },\n sampleNames,\n groupNames,\n sampleNamesForGroup,\n setPath: null,\n };\n}\n\n// ---- DrumAbuse factory ------------------------------------------------------\n\nexport type DrumAbuseSource =\n | { kind: \"machine\"; machine: string; set?: string }\n | { kind: \"pack\"; pack: DrumAbusePackId; instrument: string };\n\nexport type DrumAbuseConfig = {\n source: DrumAbuseSource;\n baseUrl: string;\n storage: Storage;\n};\n\nexport type DrumAbuseOptions = Partial<\n DrumAbuseConfig & {\n destination?: AudioNode;\n volume?: number;\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nexport type DrumAbuseExtras = {\n readonly mode: \"machine\" | \"pack\";\n getSampleNames(): string[];\n getGroupNames(): string[];\n getSampleNamesForGroup(groupName: string): string[];\n getMachineId(): string | null;\n getSetPath(): string | null;\n getPackId(): DrumAbusePackId;\n start(event: NoteEvent): StopFn;\n};\n\nexport const DrumAbuse = Instrument<DrumAbuseOptions, DrumAbuseExtras>(\n (_ctx, options = {}, smplr) => {\n const source = options.source;\n if (!source) {\n throw new Error(\"DrumAbuse: options.source is required\");\n }\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const storage = options.storage ?? HttpStorage;\n\n let sampleNames: string[] = [];\n let groupNames: string[] = [];\n let sampleNamesForGroup: Record<string, string[]> = {};\n let machineId: string | null = null;\n let setPath: string | null = null;\n let packId: DrumAbusePackId;\n let mode: \"machine\" | \"pack\";\n\n let presetPromise: Promise<SmplrPreset>;\n\n if (source.kind === \"machine\") {\n mode = \"machine\";\n const pack = getDrumAbuseMachinePack(source.machine);\n if (!pack) {\n throw new Error(`DrumAbuse: unknown machine \"${source.machine}\"`);\n }\n packId = pack;\n machineId = source.machine;\n const url = `${packBase(baseUrl, pack)}/machines/${encodeURIComponent(source.machine)}.json`;\n presetPromise = fetchJSON<RepoMachine>(url, storage).then((machine) => {\n const built = buildMachinePreset(machine, source.set, baseUrl, pack);\n sampleNames = built.sampleNames;\n groupNames = built.groupNames;\n sampleNamesForGroup = built.sampleNamesForGroup;\n setPath = built.setPath;\n return built.preset;\n });\n } else {\n mode = \"pack\";\n if (!(DRUM_ABUSE_PACKS as readonly string[]).includes(source.pack)) {\n throw new Error(`DrumAbuse: unknown pack \"${source.pack}\"`);\n }\n packId = source.pack;\n const url = `${packBase(baseUrl, source.pack)}/instruments/${encodeURIComponent(source.instrument)}.json`;\n presetPromise = fetchJSON<RepoPackSample[]>(url, storage).then((list) => {\n const built = buildPackPreset(list, baseUrl, source.pack);\n sampleNames = built.sampleNames;\n groupNames = built.groupNames;\n sampleNamesForGroup = built.sampleNamesForGroup;\n return built.preset;\n });\n }\n\n const baseStart = smplr.start.bind(smplr);\n const extras: DrumAbuseExtras = {\n get mode() {\n return mode;\n },\n getSampleNames: () => sampleNames.slice(),\n getGroupNames: () => groupNames.slice(),\n getSampleNamesForGroup: (g) => (sampleNamesForGroup[g] ?? []).slice(),\n getMachineId: () => machineId,\n getSetPath: () => setPath,\n getPackId: () => packId,\n start: (event) => {\n const ev = typeof event === \"object\" ? event : { note: event };\n return baseStart({ ...ev, stopId: ev.stopId ?? ev.note });\n },\n };\n\n const ready = presetPromise.then((preset) => smplr.loadInstrument(preset));\n return { extras, ready };\n },\n);\n\nexport type DrumAbuse = ReturnType<typeof DrumAbuse>;\n","/**\n * Encode an AudioBuffer as a WAV file Blob.\n *\n * Supports 32-bit float (lossless) and 16-bit integer (CD quality) formats.\n */\n\n/** Encode AudioBuffer as 32-bit float WAV. */\nexport function audioBufferToWav(buffer: AudioBuffer): Blob {\n return encodeWav(buffer, 32);\n}\n\n/** Encode AudioBuffer as 16-bit integer WAV. */\nexport function audioBufferToWav16(buffer: AudioBuffer): Blob {\n return encodeWav(buffer, 16);\n}\n\nfunction encodeWav(buffer: AudioBuffer, bitDepth: 16 | 32): Blob {\n const numChannels = buffer.numberOfChannels;\n const sampleRate = buffer.sampleRate;\n const length = buffer.length;\n const bytesPerSample = bitDepth / 8;\n const blockAlign = numChannels * bytesPerSample;\n const dataSize = length * blockAlign;\n const headerSize = 44;\n\n const arrayBuffer = new ArrayBuffer(headerSize + dataSize);\n const view = new DataView(arrayBuffer);\n\n // RIFF header\n writeString(view, 0, \"RIFF\");\n view.setUint32(4, 36 + dataSize, true);\n writeString(view, 8, \"WAVE\");\n\n // fmt chunk\n writeString(view, 12, \"fmt \");\n view.setUint32(16, 16, true); // chunk size\n view.setUint16(20, bitDepth === 32 ? 3 : 1, true); // format: 3 = IEEE float, 1 = PCM\n view.setUint16(22, numChannels, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, sampleRate * blockAlign, true); // byte rate\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, bitDepth, true);\n\n // data chunk\n writeString(view, 36, \"data\");\n view.setUint32(40, dataSize, true);\n\n // Interleave channel data\n const channels: Float32Array[] = [];\n for (let ch = 0; ch < numChannels; ch++) {\n channels.push(buffer.getChannelData(ch));\n }\n\n let offset = headerSize;\n for (let i = 0; i < length; i++) {\n for (let ch = 0; ch < numChannels; ch++) {\n const sample = channels[ch][i];\n if (bitDepth === 32) {\n view.setFloat32(offset, sample, true);\n } else {\n // Clamp to [-1, 1] and scale to 16-bit range\n const clamped = Math.max(-1, Math.min(1, sample));\n view.setInt16(\n offset,\n clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff,\n true,\n );\n }\n offset += bytesPerSample;\n }\n }\n\n return new Blob([arrayBuffer], { type: \"audio/wav\" });\n}\n\nfunction writeString(view: DataView, offset: number, str: string): void {\n for (let i = 0; i < str.length; i++) {\n view.setUint8(offset + i, str.charCodeAt(i));\n }\n}\n","import { audioBufferToWav, audioBufferToWav16 } from \"./wav-encoder\";\n\n/**\n * The result of an offline render. Provides the raw AudioBuffer and\n * lazy WAV encoding / download convenience methods.\n */\nexport class RenderResult {\n readonly audioBuffer: AudioBuffer;\n readonly duration: number;\n readonly sampleRate: number;\n\n #wavCache: Blob | undefined;\n #wav16Cache: Blob | undefined;\n\n constructor(audioBuffer: AudioBuffer) {\n this.audioBuffer = audioBuffer;\n this.duration = audioBuffer.duration;\n this.sampleRate = audioBuffer.sampleRate;\n }\n\n /** Encode as 32-bit float WAV. Cached after first call. */\n toWav(): Blob {\n if (!this.#wavCache) {\n this.#wavCache = audioBufferToWav(this.audioBuffer);\n }\n return this.#wavCache;\n }\n\n /** Encode as 16-bit integer WAV. Cached after first call. */\n toWav16(): Blob {\n if (!this.#wav16Cache) {\n this.#wav16Cache = audioBufferToWav16(this.audioBuffer);\n }\n return this.#wav16Cache;\n }\n\n /** Download as 32-bit float WAV file. */\n downloadWav(filename = \"render.wav\"): void {\n downloadBlob(this.toWav(), filename);\n }\n\n /** Download as 16-bit integer WAV file. */\n downloadWav16(filename = \"render.wav\"): void {\n downloadBlob(this.toWav16(), filename);\n }\n}\n\nfunction downloadBlob(blob: Blob, filename: string): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = filename;\n a.click();\n URL.revokeObjectURL(url);\n}\n","/**\n * Trim trailing silence from an AudioBuffer.\n *\n * Scans all channels from the end to find the last sample above the threshold,\n * then returns a new AudioBuffer trimmed to that length.\n */\n\nconst SILENCE_THRESHOLD = 1e-4; // ~-80dB\n\nexport function trimSilence(buffer: AudioBuffer): AudioBuffer {\n const { numberOfChannels, sampleRate, length } = buffer;\n\n // Find the last non-silent sample across all channels\n let lastNonSilent = 0;\n for (let ch = 0; ch < numberOfChannels; ch++) {\n const data = buffer.getChannelData(ch);\n for (let i = length - 1; i >= 0; i--) {\n if (Math.abs(data[i]) > SILENCE_THRESHOLD) {\n if (i > lastNonSilent) lastNonSilent = i;\n break;\n }\n }\n }\n\n // Keep at least 1 sample\n const trimmedLength = Math.max(1, lastNonSilent + 1);\n\n if (trimmedLength === length) return buffer;\n\n // Create a new trimmed buffer\n // Note: OfflineAudioContext is not available here, so we use the constructor\n const trimmed = new AudioBuffer({\n numberOfChannels,\n length: trimmedLength,\n sampleRate,\n });\n\n for (let ch = 0; ch < numberOfChannels; ch++) {\n const source = buffer.getChannelData(ch);\n trimmed.copyToChannel(source.subarray(0, trimmedLength), ch);\n }\n\n return trimmed;\n}\n","import { RenderResult } from \"./render-result\";\nimport { trimSilence } from \"./trim-silence\";\n\nexport type { RenderResult };\n\nexport interface RenderOfflineOptions {\n /** Total duration in seconds. When omitted, uses 60s max and trims trailing silence. */\n duration?: number;\n /** Sample rate. Default: 48000. */\n sampleRate?: number;\n /** Number of output channels. Default: 2 (stereo). */\n channels?: number;\n}\n\nconst DEFAULT_SAMPLE_RATE = 48000;\nconst DEFAULT_CHANNELS = 2;\nconst DEFAULT_MAX_DURATION = 60;\n\n/**\n * Render audio offline using an OfflineAudioContext.\n *\n * The callback receives an OfflineAudioContext. Create instruments,\n * schedule notes using absolute times (starting from 0), then return.\n * The audio is rendered as fast as possible (not real-time).\n *\n * Returns a RenderResult with the rendered AudioBuffer and\n * convenience methods for WAV encoding and download.\n *\n * @example\n * ```ts\n * const result = await renderOffline(async (context) => {\n * const piano = await new SplendidGrandPiano(context).load;\n * piano.start({ note: \"C4\", time: 0, duration: 1 });\n * });\n * result.downloadWav(\"export.wav\");\n * ```\n */\nexport async function renderOffline(\n callback: (context: OfflineAudioContext) => Promise<void>,\n options?: RenderOfflineOptions,\n): Promise<RenderResult> {\n const sampleRate = options?.sampleRate ?? DEFAULT_SAMPLE_RATE;\n const channels = options?.channels ?? DEFAULT_CHANNELS;\n const explicitDuration = options?.duration;\n const duration = explicitDuration ?? DEFAULT_MAX_DURATION;\n const length = Math.ceil(duration * sampleRate);\n\n const offlineContext = new OfflineAudioContext(channels, length, sampleRate);\n\n await callback(offlineContext);\n\n let buffer = await offlineContext.startRendering();\n\n // Auto-trim trailing silence when duration was not explicitly provided\n if (explicitDuration === undefined) {\n buffer = trimSilence(buffer);\n }\n\n return new RenderResult(buffer);\n}\n","import type { TimeSignature } from \"./sequencer\";\n\n/**\n * Parse a musical time value to ticks.\n *\n * Supported formats:\n * \"4n\" — quarter note (4 * ppq / 4 = ppq ticks)\n * \"8n\" — eighth note (4 * ppq / 8 = ppq/2 ticks)\n * \"16n\" — sixteenth note\n * \"2n\" — half note\n * \"1n\" — whole note (4 * ppq ticks)\n * \"4n.\" — dotted quarter (ppq * 1.5 ticks)\n * \"1m\" — one measure (numerator * ppq * 4 / denominator ticks)\n * \"2m\" — two measures\n * \"1:1\" — bar 1, beat 1 (0 ticks; 1-indexed)\n * \"2:1\" — bar 2, beat 1 (1 measure in)\n * \"1:2\" — bar 1, beat 2 (one denominator-defined beat in)\n * \"1:1:48\" — bar 1, beat 1, +48 raw ticks\n * \"1:1.5\" — bar 1, beat 1.5 (fractional beat)\n * 0, 96, 384 — number passthrough (already in ticks)\n */\nexport function parseTicks(\n time: string | number,\n ppq: number,\n timeSignature: TimeSignature,\n): number {\n if (typeof time === \"number\") return time;\n\n const t = time.trim();\n\n // Bare number string: \"0\", \"96\", \"384.5\"\n if (/^\\d+(\\.\\d+)?$/.test(t)) {\n return parseFloat(t);\n }\n\n const beatTicks = ppq * (4 / timeSignature.denominator);\n const barTicks = beatTicks * timeSignature.numerator;\n\n // Measure: \"1m\", \"2m\", \"0.5m\"\n const measureMatch = /^(\\d+(?:\\.\\d+)?)m$/.exec(t);\n if (measureMatch) {\n return parseFloat(measureMatch[1]) * barTicks;\n }\n\n // Note value: \"4n\", \"8n\", \"4n.\" (dotted)\n // Formula: ticks = (4 * ppq) / denominator\n const noteMatch = /^(\\d+(?:\\.\\d+)?)n(\\.?)$/.exec(t);\n if (noteMatch) {\n const denominator = parseFloat(noteMatch[1]);\n const dotted = noteMatch[2] === \".\";\n let ticks = (4 * ppq) / denominator;\n if (dotted) ticks *= 1.5;\n return ticks;\n }\n\n // Position: \"bar:beat\" or \"bar:beat:tick\" (all 1-indexed, can be fractional)\n const posMatch =\n /^(\\d+(?:\\.\\d+)?):(\\d+(?:\\.\\d+)?)(?::(\\d+(?:\\.\\d+)?))?$/.exec(t);\n if (posMatch) {\n const bar = parseFloat(posMatch[1]);\n const beat = parseFloat(posMatch[2]);\n const tick = posMatch[3] ? parseFloat(posMatch[3]) : 0;\n return (bar - 1) * barTicks + (beat - 1) * beatTicks + tick;\n }\n\n throw new Error(`parseTicks: cannot parse \"${time}\"`);\n}\n","/**\n * TransportClock\n *\n * Converts between musical ticks and AudioContext time with support for:\n * - BPM changes mid-playback (via checkpoints)\n * - Pause / resume\n * - Seek to arbitrary tick position\n * - Loop restart (seekAt a future audio time)\n *\n * All time values are in AudioContext seconds (context.currentTime).\n * Ticks are the internal unit: ppq ticks per quarter note.\n *\n * Principle: a Checkpoint records that at a specific audio time, a specific\n * tick position was reached at a specific BPM. Checkpoints are always ordered\n * by audioTime. The conversion functions find the last checkpoint whose\n * audioTime (or tick) is <= the query value and interpolate from there.\n */\n\nexport type TransportState = \"stopped\" | \"playing\" | \"paused\";\n\ntype Checkpoint = {\n /** Musical tick at this anchor point. */\n tick: number;\n /** AudioContext time (seconds) at this anchor point. */\n audioTime: number;\n /** BPM in effect from this checkpoint forward. */\n bpm: number;\n};\n\nimport type { TimeSignature } from \"./sequencer\";\n\nexport type TransportClockOptions = {\n bpm?: number;\n ppq?: number;\n timeSignature?: TimeSignature;\n};\n\nexport class TransportClock {\n private readonly _context: BaseAudioContext;\n\n private _bpm: number;\n readonly ppq: number;\n private _timeSignature: TimeSignature;\n\n private _state: TransportState = \"stopped\";\n private _checkpoints: Checkpoint[] = [];\n private _pausedAtTick = 0;\n\n constructor(context: BaseAudioContext, options: TransportClockOptions = {}) {\n this._context = context;\n this._bpm = options.bpm ?? 120;\n this.ppq = options.ppq ?? 480;\n this._timeSignature = options.timeSignature ?? {\n numerator: 4,\n denominator: 4,\n };\n }\n\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n\n get state(): TransportState {\n return this._state;\n }\n\n // ---------------------------------------------------------------------------\n // BPM / time signature\n // ---------------------------------------------------------------------------\n\n get bpm(): number {\n return this._bpm;\n }\n\n /**\n * Set BPM. If currently playing, inserts a new checkpoint at the current\n * audio time so that all future tick↔time conversions use the new tempo,\n * while already-converted past events remain unaffected.\n */\n set bpm(value: number) {\n if (this._state === \"playing\") {\n const now = this._context.currentTime;\n const tick = this.audioTimeToTick(now);\n this._checkpoints.push({ tick, audioTime: now, bpm: value });\n }\n this._bpm = value;\n }\n\n get timeSignature(): TimeSignature {\n return this._timeSignature;\n }\n\n set timeSignature(value: TimeSignature) {\n this._timeSignature = value;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Start playback. Records a checkpoint at the current audio time.\n * @param offsetTick Musical tick to start from (default 0).\n */\n start(offsetTick = 0): void {\n const audioTime = this._context.currentTime;\n this._checkpoints = [{ tick: offsetTick, audioTime, bpm: this._bpm }];\n this._state = \"playing\";\n }\n\n /**\n * Pause playback. Saves the current tick position so resume can start from\n * the same place.\n */\n pause(): void {\n if (this._state !== \"playing\") return;\n this._pausedAtTick = this.currentTick;\n this._state = \"paused\";\n }\n\n /**\n * Resume from paused. Creates a new checkpoint at the current audio time\n * anchored to the saved tick position.\n */\n resume(): void {\n if (this._state !== \"paused\") return;\n const audioTime = this._context.currentTime;\n this._checkpoints = [\n { tick: this._pausedAtTick, audioTime, bpm: this._bpm },\n ];\n this._state = \"playing\";\n }\n\n /**\n * Stop playback and reset position to 0.\n */\n stop(): void {\n this._checkpoints = [];\n this._pausedAtTick = 0;\n this._state = \"stopped\";\n }\n\n // ---------------------------------------------------------------------------\n // Seek\n // ---------------------------------------------------------------------------\n\n /**\n * Seek to a tick position immediately (at context.currentTime).\n * Replaces all checkpoints with a single new one.\n * Works while playing or paused.\n */\n seek(tick: number): void {\n if (this._state === \"playing\") {\n const audioTime = this._context.currentTime;\n this._checkpoints = [{ tick, audioTime, bpm: this._bpm }];\n } else {\n this._pausedAtTick = tick;\n }\n }\n\n /**\n * Re-anchor: at a specific future audio time, the tick position will jump to\n * `tick`. Used for sample-accurate loop restarts.\n *\n * Any checkpoints at or after `audioTime` are removed and replaced with this\n * new anchor, preserving the BPM that was in effect at that time.\n *\n * @internal Leaks checkpoint-list semantics; only called by `Sequencer._flush`\n * for loop-boundary re-anchoring. Not safe to share between Sequencers — see\n * thoughts/research/2026-05-17_20-18-43_shared-transport.md §3. Must not be\n * exported from any barrel.\n */\n seekAt(tick: number, audioTime: number): void {\n // Find the BPM that will be in effect at audioTime\n let bpm = this._bpm;\n for (const cp of this._checkpoints) {\n if (cp.audioTime <= audioTime) bpm = cp.bpm;\n }\n this._checkpoints = this._checkpoints.filter(\n (cp) => cp.audioTime < audioTime,\n );\n this._checkpoints.push({ tick, audioTime, bpm });\n }\n\n // ---------------------------------------------------------------------------\n // Position\n // ---------------------------------------------------------------------------\n\n /**\n * Current tick position.\n * - While playing: derived from context.currentTime.\n * - While paused or stopped: the saved tick position.\n */\n get currentTick(): number {\n if (this._state === \"playing\") {\n return this.audioTimeToTick(this._context.currentTime);\n }\n return this._pausedAtTick;\n }\n\n // ---------------------------------------------------------------------------\n // Time conversion\n // ---------------------------------------------------------------------------\n\n /**\n * Convert a tick position to an AudioContext time (seconds).\n *\n * Finds the most recent checkpoint (by audioTime) whose tick <= the target\n * tick, then interpolates forward using that checkpoint's BPM.\n *\n * This correctly handles loop restarts: after `seekAt(0, T)`, a new\n * checkpoint with tick=0 is added, so tick=100 in the new iteration maps\n * to T + 100*spt instead of the first-iteration value.\n */\n tickToAudioTime(tick: number): number {\n const cp = this._findCheckpointForTick(tick);\n return cp.audioTime + (tick - cp.tick) * this._secondsPerTick(cp.bpm);\n }\n\n /**\n * Convert an AudioContext time (seconds) to a tick position.\n *\n * Finds the most recent checkpoint (by audioTime) whose audioTime <= the\n * target time, then interpolates forward.\n */\n audioTimeToTick(audioTime: number): number {\n const cp = this._findCheckpointForAudioTime(audioTime);\n return cp.tick + (audioTime - cp.audioTime) / this._secondsPerTick(cp.bpm);\n }\n\n /**\n * Convert a tick count to seconds at the current (snapshot) BPM.\n *\n * Uses `this._bpm` directly, not the checkpoint history — so after a\n * mid-play BPM change this returns a value based on the *latest* BPM only.\n * For checkpoint-aware durations, use `tickToAudioTime(end) - tickToAudioTime(start)`.\n */\n ticksToSeconds(ticks: number): number {\n return ticks * this._secondsPerTick(this._bpm);\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private _secondsPerTick(bpm: number): number {\n return 60 / (bpm * this.ppq);\n }\n\n /**\n * Find the most recent checkpoint (latest audioTime) whose tick <= targetTick.\n * Falls back to a virtual origin checkpoint if none match.\n */\n private _findCheckpointForTick(targetTick: number): Checkpoint {\n let best: Checkpoint | null = null;\n for (const cp of this._checkpoints) {\n if (cp.tick <= targetTick) {\n best = cp;\n // Keep iterating: checkpoints are audioTime-ordered, so later ones\n // with tick <= targetTick are more recent and should win.\n }\n }\n return best ?? this._origin();\n }\n\n /**\n * Find the most recent checkpoint whose audioTime <= targetTime.\n * Falls back to a virtual origin checkpoint if none match.\n */\n private _findCheckpointForAudioTime(targetTime: number): Checkpoint {\n let best: Checkpoint | null = null;\n for (const cp of this._checkpoints) {\n if (cp.audioTime <= targetTime) {\n best = cp;\n }\n }\n return best ?? this._origin();\n }\n\n /** Virtual origin used before start() is called. */\n private _origin(): Checkpoint {\n return { tick: 0, audioTime: 0, bpm: this._bpm };\n }\n}\n","import { asConstructable } from \"../smplr/as-constructable\";\nimport { parseTicks } from \"./time-parser\";\nimport { TransportClock } from \"./transport-clock\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type SequencerNote = {\n /** Optional identifier for this note. Used as `noteId` in noteOn/noteOff events. Defaults to the note's array index. */\n id?: string | number;\n note: string | number;\n /** Musical position: ticks, \"4n\", \"1m\", \"2:1\", \"1:1.5\", etc. */\n at: string | number;\n /** Note duration: ticks, \"4n\", \"8n\", etc. Omit for a one-shot trigger. */\n duration?: string | number;\n velocity?: number;\n /** Probability (0–100) that this note fires on each pass. Default 100 (always). */\n chance?: number;\n /**\n * Expand into N evenly-spaced sub-notes over `duration`. Requires `duration`;\n * silently ignored if `duration` is omitted. Default 1 (no ratchet). When >1,\n * each sub-note's `noteId` is suffixed with `#0`, `#1`, … so individual\n * ratchet voices can be stopped via `stopNote(\"id#0\")`.\n */\n ratchet?: number;\n /**\n * Multiplicative velocity decay per ratchet step: each step's velocity is\n * scaled by `(1 - decay) ** step_index`. 0 = constant, 1 = silence by last\n * step. Default 0.\n */\n ratchetVelocityDecay?: number;\n};\n\n/**\n * Any instrument the Sequencer can drive.\n * Compatible with SplendidGrandPiano, DrumMachine, Smplr, and any object\n * that has a `start()` method accepting note + optional scheduling params.\n */\nexport type SequencerInstrument = {\n start(event: {\n note: string | number;\n time?: number;\n duration?: number;\n velocity?: number;\n noteId?: string | number;\n onStart?: (event: unknown) => void;\n onEnded?: (event: unknown) => void;\n }): unknown;\n};\n\n/** Emitted with \"noteOn\" and \"noteOff\" events. */\nexport type SequencerNoteEvent = {\n noteId: string | number;\n trackIndex: number;\n noteIndex: number;\n note: SequencerNote;\n};\n\n/**\n * Time signature as a `{ numerator, denominator }` pair (e.g. `{ numerator: 7, denominator: 8 }`\n * for 7/8). The numerator counts beats per bar; the denominator defines the\n * note value of one beat (4 = quarter note, 8 = eighth note, …).\n */\nexport type TimeSignature = { numerator: number; denominator: number };\n\n/** Normalise a raw number / TimeSignature / undefined into a TimeSignature. */\nfunction normaliseTimeSignature(\n input: number | TimeSignature | undefined,\n): TimeSignature {\n if (input === undefined) return { numerator: 4, denominator: 4 };\n if (typeof input === \"number\") return { numerator: input, denominator: 4 };\n return input;\n}\n\nexport type SequencerOptions = {\n bpm?: number;\n ppq?: number;\n /** Time signature. Accepts `4` (interpreted as 4/4) or `{ numerator, denominator }`. */\n timeSignature?: number | TimeSignature;\n loop?: boolean;\n loopStart?: string | number;\n loopEnd?: string | number;\n /** How far ahead (ms) to pre-schedule notes. Default 200. */\n lookaheadMs?: number;\n /** How often (ms) the flush loop runs. Default 50. */\n intervalMs?: number;\n /** Randomise timing (ms) and velocity per note for a human feel. */\n humanize?: { timingMs?: number; velocity?: number };\n /** Emit a \"step\" event at this interval. Accepts musical notation or ticks: \"16n\", \"8n\", ticks, etc. */\n stepSize?: string | number;\n};\n\n/**\n * Per-track options accepted by {@link Sequencer.addTrack} and\n * {@link Sequencer.setPatterns}.\n */\nexport type AddTrackOptions = {\n /**\n * Stable track id. Required to address this track via\n * {@link Sequencer.setTrackVolume}, {@link Sequencer.muteTrack},\n * {@link Sequencer.soloTrack}, etc.\n */\n id?: string;\n /** Per-track humanize. Overrides {@link SequencerOptions.humanize} when set. */\n humanize?: { timingMs?: number; velocity?: number };\n /** Multiplicative velocity scalar in [0, 1+]. Default 1. */\n volume?: number;\n /** When true, this track does not dispatch any notes. Default false. */\n muted?: boolean;\n /**\n * When true, only soloed tracks dispatch notes. If any track in the pattern\n * is soloed, every non-soloed track is silenced. Default false.\n */\n solo?: boolean;\n};\n\n/**\n * Public shape for one pattern accepted by {@link Sequencer.setPatterns}.\n */\nexport type PatternInput = {\n tracks: Array<\n {\n instrument: SequencerInstrument;\n notes: SequencerNote[];\n } & AddTrackOptions\n >;\n /**\n * Pattern length override in ticks or musical time. Defaults to the longest\n * track in this pattern.\n */\n loopEnd?: string | number;\n};\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ntype StopFn = (time?: number) => void;\n\ntype Track = {\n instrument: SequencerInstrument;\n notes: SequencerNote[];\n id?: string;\n /** Per-track humanize override; undefined → fall back to the sequencer's global humanize. */\n humanize?: { timing: number; velocity: number };\n volume: number;\n muted: boolean;\n solo: boolean;\n};\n\ntype RepeatEvent = {\n callback: (time: number) => void;\n intervalTicks: number;\n /** Next tick at which this event should fire. Advances after each firing. */\n nextTick: number;\n /** Original start tick, used to reset on loop/seek. */\n startTick: number;\n};\n\ntype Pattern = {\n tracks: Track[];\n /** Pattern length override in ticks; null = default to longest track. */\n loopEndOverride: number | null;\n /** Cached pattern length: max(at + duration) across all tracks. */\n totalTicks: number;\n};\n\n// ---------------------------------------------------------------------------\n// Sequencer\n// ---------------------------------------------------------------------------\n\nclass SequencerImpl {\n private readonly _context: BaseAudioContext;\n private readonly _clock: TransportClock;\n private readonly _ppq: number;\n\n private _timeSignature: TimeSignature;\n private _stepTicks: number | undefined;\n /**\n * Patterns. Always at least one (the implicit default pattern). Replaced\n * atomically by {@link setPatterns}.\n */\n private _patterns: Pattern[] = [\n { tracks: [], loopEndOverride: null, totalTicks: 0 },\n ];\n /** Indices into {@link _patterns} defining playback order. */\n private _chainOrder: number[] = [0];\n /** Current position within {@link _chainOrder}. */\n private _chainIndex = 0;\n /**\n * True once {@link setPatterns} has been called. After this point,\n * `addTrack` / `removeTrack` / `clearTracks` throw because the chain shape\n * is owned by the patterns array.\n */\n private _patternsExplicit = false;\n private _repeatEvents: RepeatEvent[] = [];\n private _listeners: Map<string, Set<(...args: any[]) => void>> = new Map();\n\n // Loop\n private _loop: boolean;\n private _loopStartTick: number;\n\n // Timing\n private _lookaheadSec: number;\n private _intervalMs: number;\n private _humanize: { timing: number; velocity: number };\n\n // Flush loop state\n private _intervalId: ReturnType<typeof setInterval> | undefined;\n /** AudioContext time high-water mark: notes up to here have been scheduled. */\n private _scheduledThrough = 0;\n /** Guards against scheduling the auto-stop setTimeout more than once. */\n private _endScheduled = false;\n /** Active voices keyed by noteId, so individual notes can be stopped. */\n private _activeVoices: Map<string | number, StopFn> = new Map();\n\n constructor(context: BaseAudioContext, options: SequencerOptions = {}) {\n this._context = context;\n this._ppq = options.ppq ?? 480;\n this._timeSignature = normaliseTimeSignature(options.timeSignature);\n\n this._clock = new TransportClock(context, {\n bpm: options.bpm ?? 120,\n ppq: this._ppq,\n timeSignature: this._timeSignature,\n });\n\n this._loop = options.loop ?? false;\n this._loopStartTick =\n options.loopStart !== undefined\n ? parseTicks(options.loopStart, this._ppq, this._timeSignature)\n : 0;\n\n if (options.loopEnd !== undefined) {\n this._patterns[0].loopEndOverride = parseTicks(\n options.loopEnd,\n this._ppq,\n this._timeSignature,\n );\n }\n\n this._stepTicks =\n options.stepSize !== undefined\n ? parseTicks(options.stepSize, this._ppq, this._timeSignature)\n : undefined;\n\n this._lookaheadSec = (options.lookaheadMs ?? 200) / 1000;\n this._intervalMs = options.intervalMs ?? 50;\n this._humanize = {\n timing: options.humanize?.timingMs ?? 0,\n velocity: options.humanize?.velocity ?? 0,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Tracks\n // ---------------------------------------------------------------------------\n\n /**\n * Add a track to the (implicit, default) pattern. Throws after\n * {@link setPatterns} has been called — use {@link setPatterns} to mutate\n * the chain.\n */\n addTrack(\n instrument: SequencerInstrument,\n notes: SequencerNote[],\n options?: AddTrackOptions,\n ): this {\n this._assertImplicitPattern(\"addTrack\");\n const pattern = this._patterns[0];\n pattern.tracks.push(this._buildTrack(instrument, notes, options));\n pattern.totalTicks = this._computePatternTotalTicks(pattern);\n return this;\n }\n\n removeTrack(instrument: SequencerInstrument): this {\n this._assertImplicitPattern(\"removeTrack\");\n const pattern = this._patterns[0];\n pattern.tracks = pattern.tracks.filter((t) => t.instrument !== instrument);\n pattern.totalTicks = this._computePatternTotalTicks(pattern);\n return this;\n }\n\n clearTracks(): this {\n this._assertImplicitPattern(\"clearTracks\");\n const pattern = this._patterns[0];\n pattern.tracks = [];\n pattern.totalTicks = 0;\n return this;\n }\n\n /**\n * Replace the sequencer's patterns. Each pattern owns its own tracks and\n * optional `loopEnd`. After this call, `addTrack` / `removeTrack` /\n * `clearTracks` throw — the chain is owned by the patterns array.\n *\n * `chainOrder` is reset to `[0, 1, …, patterns.length - 1]`.\n */\n setPatterns(patterns: PatternInput[]): this {\n if (patterns.length === 0) {\n throw new Error(\"setPatterns requires at least one pattern\");\n }\n this._patterns = patterns.map((p) => {\n const built: Pattern = {\n tracks: p.tracks.map((t) => this._buildTrack(t.instrument, t.notes, t)),\n loopEndOverride:\n p.loopEnd !== undefined\n ? parseTicks(p.loopEnd, this._ppq, this._timeSignature)\n : null,\n totalTicks: 0,\n };\n built.totalTicks = this._computePatternTotalTicks(built);\n return built;\n });\n this._chainOrder = this._patterns.map((_, i) => i);\n this._chainIndex = 0;\n this._patternsExplicit = true;\n return this;\n }\n\n /** Current chain order: indices into the patterns array, in playback order. */\n get chainOrder(): number[] {\n return [...this._chainOrder];\n }\n\n /**\n * Set a new chain order. Each entry must be a valid pattern index.\n * Throws if `order` is empty or contains an out-of-range index.\n */\n set chainOrder(order: number[]) {\n if (order.length === 0) {\n throw new Error(\"chainOrder must not be empty\");\n }\n for (const idx of order) {\n if (idx < 0 || idx >= this._patterns.length) {\n throw new Error(`chainOrder index ${idx} out of range`);\n }\n }\n this._chainOrder = [...order];\n if (this._chainIndex >= order.length) this._chainIndex = 0;\n }\n\n /**\n * Set a track's multiplicative volume scalar. Affects every note dispatched\n * by the track from the next flush onwards. No-op if no track has the\n * given id. Search is scoped to the currently-playing pattern.\n */\n setTrackVolume(id: string, volume: number): this {\n const t = this._findTrack(id);\n if (t) t.volume = volume;\n return this;\n }\n\n /** Mute a track by id. No-op if no track has the given id. */\n muteTrack(id: string): this {\n return this._setTrackFlag(id, \"muted\", true);\n }\n\n /** Unmute a track by id. No-op if no track has the given id. */\n unmuteTrack(id: string): this {\n return this._setTrackFlag(id, \"muted\", false);\n }\n\n /** Solo a track by id. While any track is soloed, non-soloed tracks are silenced. */\n soloTrack(id: string): this {\n return this._setTrackFlag(id, \"solo\", true);\n }\n\n /** Remove the solo flag from a track. */\n unsoloTrack(id: string): this {\n return this._setTrackFlag(id, \"solo\", false);\n }\n\n /**\n * Locate a track by id, scoped to the currently-playing pattern.\n */\n private _findTrack(id: string): Track | undefined {\n return this._currentPattern().tracks.find((t) => t.id === id);\n }\n\n private _setTrackFlag(\n id: string,\n flag: \"muted\" | \"solo\",\n value: boolean,\n ): this {\n const t = this._findTrack(id);\n if (t) t[flag] = value;\n return this;\n }\n\n private _buildTrack(\n instrument: SequencerInstrument,\n notes: SequencerNote[],\n options?: AddTrackOptions,\n ): Track {\n return {\n instrument,\n notes,\n id: options?.id,\n humanize: options?.humanize\n ? {\n timing: options.humanize.timingMs ?? 0,\n velocity: options.humanize.velocity ?? 0,\n }\n : undefined,\n volume: options?.volume ?? 1,\n muted: options?.muted ?? false,\n solo: options?.solo ?? false,\n };\n }\n\n private _currentPattern(): Pattern {\n return (\n this._patterns[this._chainOrder[this._chainIndex]] ?? this._patterns[0]\n );\n }\n\n private _assertImplicitPattern(method: string): void {\n if (this._patternsExplicit) {\n throw new Error(\n `${method}() is not available after setPatterns(); use setPatterns() to update the chain.`,\n );\n }\n }\n\n private _computePatternTotalTicks(pattern: Pattern): number {\n let max = 0;\n for (const track of pattern.tracks) {\n for (const note of track.notes) {\n const atTick = parseTicks(note.at, this._ppq, this._timeSignature);\n const durTick =\n note.duration !== undefined\n ? parseTicks(note.duration, this._ppq, this._timeSignature)\n : 0;\n max = Math.max(max, atTick + durTick);\n }\n }\n return max;\n }\n\n // ---------------------------------------------------------------------------\n // Playback\n // ---------------------------------------------------------------------------\n\n get state() {\n return this._clock.state;\n }\n\n /**\n * Start playback from `offsetTick`, or resume from pause if no offset given.\n */\n start(offsetTick?: number): this {\n if (this._clock.state === \"playing\") return this;\n\n if (this._clock.state === \"paused\" && offsetTick === undefined) {\n // Resume\n this._clock.resume();\n this._scheduledThrough = this._context.currentTime;\n this._startLoop();\n this._emitStateChange(\"playing\");\n return this;\n }\n\n const startTick = offsetTick ?? 0;\n this._clock.start(startTick);\n this._scheduledThrough = this._context.currentTime;\n this._endScheduled = false;\n this._chainIndex = 0;\n this._resetRepeatEvents(startTick);\n this._startLoop();\n this._emitStateChange(\"playing\");\n return this;\n }\n\n pause(): this {\n if (this._clock.state !== \"playing\") return this;\n this._clock.pause();\n this._stopLoop();\n this._emitStateChange(\"paused\");\n return this;\n }\n\n stop(): this {\n this._clock.stop();\n this._stopLoop();\n this._endScheduled = false;\n this._activeVoices.clear();\n this._emitStateChange(\"stopped\");\n return this;\n }\n\n /**\n * Stop a single note that was scheduled by the sequencer.\n * @param noteId The id of the note (from SequencerNote.id or auto-assigned index).\n * @param time Optional AudioContext time to schedule the stop.\n */\n stopNote(noteId: string | number, time?: number): this {\n const stopFn = this._activeVoices.get(noteId);\n if (stopFn) {\n stopFn(time);\n this._activeVoices.delete(noteId);\n }\n return this;\n }\n\n /**\n * Toggle between playing and paused. If stopped, starts from the beginning.\n */\n togglePlayPause(): this {\n if (this._clock.state === \"playing\") return this.pause();\n return this.start();\n }\n\n // ---------------------------------------------------------------------------\n // Tempo\n // ---------------------------------------------------------------------------\n\n get bpm(): number {\n return this._clock.bpm;\n }\n\n set bpm(value: number) {\n this._clock.bpm = value;\n }\n\n get timeSignature(): TimeSignature {\n return { ...this._timeSignature };\n }\n\n set timeSignature(value: number | TimeSignature) {\n this._timeSignature = normaliseTimeSignature(value);\n this._clock.timeSignature = this._timeSignature;\n for (const p of this._patterns) {\n p.totalTicks = this._computePatternTotalTicks(p);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Position\n // ---------------------------------------------------------------------------\n\n /** Current transport position as \"bar:beat:tick\" (1-indexed). */\n get position(): string {\n return this._tickToPosition(this._clock.currentTick);\n }\n\n /**\n * Seek to a position. Accepts ticks or any time string (\"2:1\", \"4n\", …).\n * Works while playing (seamless) or stopped/paused.\n */\n set position(value: string | number) {\n const targetTick = parseTicks(\n String(value),\n this._ppq,\n this._timeSignature,\n );\n this._clock.seek(targetTick);\n if (this._clock.state === \"playing\") {\n this._scheduledThrough = this._context.currentTime;\n this._endScheduled = false;\n this._resetRepeatEvents(targetTick);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Loop\n // ---------------------------------------------------------------------------\n\n get loop(): boolean {\n return this._loop;\n }\n\n set loop(value: boolean) {\n this._loop = value;\n }\n\n /** Loop start in ticks. */\n get loopStart(): number {\n return this._loopStartTick;\n }\n\n set loopStart(value: string | number) {\n this._loopStartTick = parseTicks(\n String(value),\n this._ppq,\n this._timeSignature,\n );\n }\n\n /**\n * Loop end in ticks for the currently-playing pattern. Defaults to the end\n * of the pattern's longest track.\n */\n get loopEnd(): number {\n const p = this._currentPattern();\n return p.loopEndOverride ?? p.totalTicks;\n }\n\n set loopEnd(value: string | number) {\n this._currentPattern().loopEndOverride = parseTicks(\n String(value),\n this._ppq,\n this._timeSignature,\n );\n }\n\n /**\n * Normalised loop position [0, 1]. Always 0 when loop=false.\n */\n get progress(): number {\n if (!this._loop) return 0;\n const loopEnd = this.loopEnd;\n const duration = loopEnd - this._loopStartTick;\n if (duration <= 0) return 0;\n const tick = this._clock.currentTick;\n return Math.max(0, Math.min(1, (tick - this._loopStartTick) / duration));\n }\n\n // ---------------------------------------------------------------------------\n // Callback scheduling (pattern API)\n // ---------------------------------------------------------------------------\n\n /**\n * Schedule a callback to fire on every `interval` while the sequencer plays.\n * Returns a cancel function.\n *\n * @param callback Called with the exact AudioContext time of each firing.\n * @param interval Musical interval: \"4n\", \"8n\", \"1m\", ticks, etc.\n * @param startAt First firing position (default 0 = beginning).\n */\n scheduleRepeat(\n callback: (time: number) => void,\n interval: string | number,\n startAt: string | number = 0,\n ): () => void {\n const intervalTicks = parseTicks(\n String(interval),\n this._ppq,\n this._timeSignature,\n );\n const startTick = parseTicks(\n String(startAt),\n this._ppq,\n this._timeSignature,\n );\n const event: RepeatEvent = {\n callback,\n intervalTicks,\n nextTick: startTick,\n startTick,\n };\n this._repeatEvents.push(event);\n return () => {\n this._repeatEvents = this._repeatEvents.filter((e) => e !== event);\n };\n }\n\n // ---------------------------------------------------------------------------\n // Events\n // ---------------------------------------------------------------------------\n\n /**\n * Listen to a sequencer event.\n *\n * | Event | Args |\n * |-----------------|---------------------------------------------------|\n * | \"statechange\" | (state: \"playing\" \\| \"paused\" \\| \"stopped\") |\n * | \"start\" | |\n * | \"stop\" | |\n * | \"pause\" | |\n * | \"end\" | |\n * | \"loop\" | |\n * | \"patternChange\" | (patternIndex: number, time: number) |\n * | \"beat\" | (beat: number, time: number) |\n * | \"bar\" | (bar: number, time: number) |\n * | \"step\" | (stepIndex: number, time: number) |\n * | \"noteOn\" | (event: SequencerNoteEvent) |\n * | \"noteOff\" | (event: SequencerNoteEvent) |\n */\n on(event: string, callback: (...args: any[]) => void): this {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n this._listeners.get(event)!.add(callback);\n return this;\n }\n\n off(event: string, callback: (...args: any[]) => void): this {\n this._listeners.get(event)?.delete(callback);\n return this;\n }\n\n // ---------------------------------------------------------------------------\n // Private — interval management\n // ---------------------------------------------------------------------------\n\n private _startLoop(): void {\n if (this._intervalId !== undefined) return;\n this._intervalId = setInterval(() => this._flush(), this._intervalMs);\n }\n\n private _stopLoop(): void {\n if (this._intervalId !== undefined) {\n clearInterval(this._intervalId);\n this._intervalId = undefined;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — flush loop (the timing engine)\n // ---------------------------------------------------------------------------\n\n private _flush(): void {\n const now = this._context.currentTime;\n const windowEnd = now + this._lookaheadSec;\n\n const fromTick = this._clock.audioTimeToTick(this._scheduledThrough);\n const toTick = this._clock.audioTimeToTick(windowEnd);\n\n const pattern = this._currentPattern();\n const isMultiPattern = this._chainOrder.length > 1;\n const patternEndTick = pattern.loopEndOverride ?? pattern.totalTicks;\n const isLastInChain = this._chainIndex === this._chainOrder.length - 1;\n // Single-pattern restart uses the configured loopStart; chain patterns\n // always restart from tick 0 of the next pattern.\n const patternStartTick = isMultiPattern ? 0 : this._loopStartTick;\n\n // Cross-boundary: advance chain (or wrap a looping single pattern).\n // Single-pattern + !loop falls through to the auto-stop path below.\n const willAdvance =\n patternEndTick > patternStartTick &&\n toTick >= patternEndTick &&\n (isMultiPattern || this._loop) &&\n !(isLastInChain && !this._loop);\n\n if (willAdvance) {\n // Part 1: notes up to the pattern boundary.\n this._scheduleWindow(fromTick, patternEndTick);\n\n const restartAudioTime = this._clock.tickToAudioTime(patternEndTick);\n\n if (isMultiPattern) {\n this._chainIndex = (this._chainIndex + 1) % this._chainOrder.length;\n this._emit(\n \"patternChange\",\n this._chainOrder[this._chainIndex],\n restartAudioTime,\n );\n // Wrapping the chain back to index 0 also counts as a loop.\n if (this._chainIndex === 0) {\n this._emit(\"loop\");\n }\n } else {\n this._emit(\"loop\");\n }\n\n const nextStartTick = isMultiPattern ? 0 : this._loopStartTick;\n this._clock.seekAt(nextStartTick, restartAudioTime);\n this._resetRepeatEvents(nextStartTick);\n\n // Part 2: overflow into the new pattern within the same window.\n const overflowToTick = this._clock.audioTimeToTick(windowEnd);\n this._scheduleWindow(nextStartTick, overflowToTick);\n\n this._scheduledThrough = windowEnd;\n return;\n }\n\n this._scheduleWindow(fromTick, toTick);\n this._scheduledThrough = windowEnd;\n\n // Auto-stop once we've passed the end of the last pattern in the chain\n // (or the only pattern in non-loop mode). Uses the pattern's loopEnd\n // override when set; otherwise falls back to the longest-track length.\n if (\n !this._loop &&\n !this._endScheduled &&\n isLastInChain &&\n patternEndTick > 0 &&\n toTick >= patternEndTick\n ) {\n this._endScheduled = true;\n const endAudioTime = this._clock.tickToAudioTime(patternEndTick);\n const delay = Math.max(0, (endAudioTime - now) * 1000);\n setTimeout(() => {\n this._stopLoop();\n this._clock.stop();\n this._emit(\"end\");\n this._emit(\"statechange\", \"stopped\");\n }, delay);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — window scheduling\n // ---------------------------------------------------------------------------\n\n private _scheduleWindow(fromTick: number, toTick: number): void {\n // ---- Track notes (current pattern) ----\n const tracks = this._currentPattern().tracks;\n const anySolo = tracks.some((t) => t.solo);\n\n for (let trackIndex = 0; trackIndex < tracks.length; trackIndex++) {\n const track = tracks[trackIndex];\n if (track.muted) continue;\n if (anySolo && !track.solo) continue;\n\n const trackHumanize = track.humanize ?? this._humanize;\n\n for (let noteIndex = 0; noteIndex < track.notes.length; noteIndex++) {\n const note = track.notes[noteIndex];\n const noteTick = parseTicks(note.at, this._ppq, this._timeSignature);\n if (noteTick < fromTick || noteTick >= toTick) continue;\n\n // Chance gate — re-rolled every pass through the scheduler\n if (note.chance !== undefined && note.chance < 100) {\n if (Math.random() * 100 >= note.chance) continue;\n }\n\n const audioTime = this._clock.tickToAudioTime(noteTick);\n const durationSec =\n note.duration !== undefined\n ? this._clock.ticksToSeconds(\n parseTicks(note.duration, this._ppq, this._timeSignature),\n )\n : undefined;\n\n const timingOffset = trackHumanize.timing\n ? ((Math.random() * 2 - 1) * trackHumanize.timing) / 1000\n : 0;\n const velocityOffset = trackHumanize.velocity\n ? Math.round((Math.random() * 2 - 1) * trackHumanize.velocity)\n : 0;\n\n const baseNoteId = note.id ?? noteIndex;\n const noteEvent: SequencerNoteEvent = {\n noteId: baseNoteId,\n trackIndex,\n noteIndex,\n note,\n };\n\n const ratchetCount =\n note.ratchet && note.ratchet > 1 && durationSec !== undefined\n ? Math.floor(note.ratchet)\n : 1;\n const ratchetDecay = note.ratchetVelocityDecay ?? 0;\n const ratchetStepSec =\n ratchetCount > 1 && durationSec !== undefined\n ? durationSec / ratchetCount\n : 0;\n const ratchetDurationSec =\n ratchetCount > 1 ? ratchetStepSec : durationSec;\n\n for (let r = 0; r < ratchetCount; r++) {\n const ratchetOffsetSec = r * ratchetStepSec;\n const ratchetVelocityScale =\n ratchetCount > 1 ? Math.pow(1 - ratchetDecay, r) : 1;\n const subNoteId =\n ratchetCount > 1 ? `${baseNoteId}#${r}` : baseNoteId;\n\n const result = track.instrument.start({\n note: note.note,\n time: Math.max(0, audioTime + timingOffset + ratchetOffsetSec),\n duration: ratchetDurationSec,\n velocity:\n (note.velocity ?? 100) * track.volume * ratchetVelocityScale +\n velocityOffset,\n noteId: subNoteId,\n onStart: () => this._emit(\"noteOn\", noteEvent),\n onEnded: () => {\n this._activeVoices.delete(subNoteId);\n this._emit(\"noteOff\", noteEvent);\n },\n });\n\n // Capture the stop function if the instrument returns one\n if (typeof result === \"function\") {\n this._activeVoices.set(subNoteId, result as StopFn);\n }\n }\n }\n }\n\n // ---- Repeat events (callback API) ----\n for (const rep of this._repeatEvents) {\n while (rep.nextTick >= fromTick && rep.nextTick < toTick) {\n rep.callback(this._clock.tickToAudioTime(rep.nextTick));\n rep.nextTick += rep.intervalTicks;\n }\n }\n\n // ---- Beat / bar events ----\n this._emitBeatsInWindow(fromTick, toTick);\n\n // ---- Step events ----\n this._emitStepsInWindow(fromTick, toTick);\n }\n\n // ---------------------------------------------------------------------------\n // Private — beat / bar events\n // ---------------------------------------------------------------------------\n\n private _emitStepsInWindow(fromTick: number, toTick: number): void {\n if (!this._stepTicks) return;\n const firstStep =\n Math.ceil((fromTick - 0.001) / this._stepTicks) * this._stepTicks;\n for (let t = firstStep; t < toTick; t += this._stepTicks) {\n if (t < 0) continue;\n const stepIndex = Math.floor(t / this._stepTicks);\n const audioTime = this._clock.tickToAudioTime(t);\n this._emit(\"step\", stepIndex, audioTime);\n }\n }\n\n private _emitBeatsInWindow(fromTick: number, toTick: number): void {\n const beatTicks = this._ppq * (4 / this._timeSignature.denominator);\n const barTicks = beatTicks * this._timeSignature.numerator;\n\n // Small tolerance so floating-point drift doesn't skip a beat at tick=0.\n const firstBeat = Math.ceil((fromTick - 0.001) / beatTicks) * beatTicks;\n\n for (let t = firstBeat; t < toTick; t += beatTicks) {\n if (t < 0) continue;\n const audioTime = this._clock.tickToAudioTime(t);\n // 1-indexed absolute beat number from the start of the score.\n const beat = Math.floor(t / beatTicks) + 1;\n this._emit(\"beat\", beat, audioTime);\n if (t % barTicks === 0) {\n const bar = Math.floor(t / barTicks) + 1;\n this._emit(\"bar\", bar, audioTime);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — utilities\n // ---------------------------------------------------------------------------\n\n private _emit(event: string, ...args: any[]): void {\n const handlers = this._listeners.get(event);\n if (handlers) {\n for (const fn of handlers) {\n fn(...args);\n }\n }\n }\n\n /** Emit both the specific state event (\"start\"/\"pause\"/\"stop\") and the unified \"statechange\" event. */\n private _emitStateChange(state: \"playing\" | \"paused\" | \"stopped\"): void {\n const eventName =\n state === \"playing\" ? \"start\" : state === \"paused\" ? \"pause\" : \"stop\";\n this._emit(eventName);\n this._emit(\"statechange\", state);\n }\n\n /** Format a raw tick count as \"bar:beat:tick\" (all 1-indexed). */\n private _tickToPosition(tick: number): string {\n const beatTicks = this._ppq * (4 / this._timeSignature.denominator);\n const barTicks = beatTicks * this._timeSignature.numerator;\n const bar = Math.floor(tick / barTicks) + 1;\n const ticksInBar = tick % barTicks;\n const beat = Math.floor(ticksInBar / beatTicks) + 1;\n const ticksInBeat = Math.round(ticksInBar % beatTicks);\n return `${bar}:${beat}:${ticksInBeat}`;\n }\n\n /**\n * Reset all repeat events so their next firing is the first occurrence\n * at or after `fromTick`.\n */\n private _resetRepeatEvents(fromTick: number): void {\n for (const rep of this._repeatEvents) {\n rep.nextTick = rep.startTick;\n if (fromTick > rep.startTick && rep.intervalTicks > 0) {\n const steps = Math.ceil((fromTick - rep.startTick) / rep.intervalTicks);\n rep.nextTick = rep.startTick + steps * rep.intervalTicks;\n }\n }\n }\n}\n\nexport const Sequencer = asConstructable(SequencerImpl);\nexport type Sequencer = ReturnType<typeof Sequencer>;\n","import { toMidi } from \"./midi\";\nimport { SmplrGroup, SmplrPreset, SmplrRegion } from \"./types\";\n\nexport type SfzConvertOptions = {\n /** Base URL prepended to all sample paths. */\n baseUrl: string;\n /**\n * Transform a raw SFZ sample path (e.g. \"Arco\\\\C4.wav\") to a SmplrPreset\n * relative path WITHOUT the audio extension (e.g. \"Arco/C4\").\n * The SampleLoader will append \".<format>\" when building the final URL.\n */\n pathFromSampleName: (name: string) => string;\n /** Audio formats in preference order. Defaults to [\"ogg\", \"m4a\"]. */\n formats?: string[];\n};\n\n/**\n * Parse SFZ text and convert to a SmplrPreset descriptor.\n *\n * Handles both inline format (`<region> sample=foo.wav lokey=60`)\n * and multi-line format (headers on their own line, opcodes below).\n *\n * Fixes the \"dropped final region\" bug present in sfz2.ts by ensuring\n * the last scope is always closed.\n *\n * @internal Not part of the public 1.0 API surface.\n */\nexport function sfzToPreset(\n sfzText: string,\n options: SfzConvertOptions,\n): SmplrPreset {\n const formats = options.formats ?? [\"ogg\", \"m4a\"];\n\n // Resolve #define preprocessor directives before tokenizing\n const tokens = tokenize(resolveDefines(sfzText));\n\n // State machine\n type Mode = \"global\" | \"group\" | \"region\";\n let mode: Mode = \"global\";\n\n const globalProps: Record<string, string | number> = {};\n let groupProps: Record<string, string | number> = {};\n let regionProps: Record<string, string | number> = {};\n\n const groups: SmplrGroup[] = [];\n let currentGroup: SmplrGroup | null = null;\n\n function closeScope() {\n if (mode === \"global\") {\n Object.assign(globalProps, regionProps);\n } else if (mode === \"group\") {\n groupProps = { ...regionProps };\n // Build a new SmplrGroup from groupProps\n currentGroup = buildGroup(groupProps);\n groups.push(currentGroup);\n } else if (mode === \"region\") {\n // Merge: global → group → region\n const merged = { ...globalProps, ...groupProps, ...regionProps };\n const region = buildRegion(merged, options.pathFromSampleName);\n if (region) {\n // Ensure we have a current group\n if (!currentGroup) {\n currentGroup = { regions: [] };\n groups.push(currentGroup);\n }\n currentGroup.regions.push(region);\n }\n }\n regionProps = {};\n }\n\n for (const token of tokens) {\n if (token.type === \"header\") {\n closeScope();\n mode = token.value as Mode;\n if (mode === \"group\") {\n // New group scope\n groupProps = {};\n currentGroup = null;\n }\n } else {\n regionProps[token.key] = token.value;\n }\n }\n\n // Close the final scope\n closeScope();\n\n // Filter out empty groups\n const nonEmptyGroups = groups.filter((g) => g.regions.length > 0);\n\n return {\n samples: {\n baseUrl: options.baseUrl,\n formats,\n },\n groups: nonEmptyGroups,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Group / Region builders\n// ---------------------------------------------------------------------------\n\nfunction buildGroup(props: Record<string, string | number>): SmplrGroup {\n const group: SmplrGroup = { regions: [] };\n\n const lokey = num(props, \"lokey\");\n const hikey = num(props, \"hikey\");\n if (lokey !== undefined && hikey !== undefined) {\n group.keyRange = [lokey, hikey];\n }\n\n const lovel = num(props, \"lovel\");\n const hivel = num(props, \"hivel\");\n if (lovel !== undefined && hivel !== undefined) {\n group.velRange = [lovel, hivel];\n }\n\n const seqLength = num(props, \"seq_length\");\n if (seqLength !== undefined) group.seqLength = seqLength;\n\n const groupNum = num(props, \"group\");\n if (groupNum !== undefined) group.group = groupNum;\n\n const offBy = num(props, \"off_by\");\n if (offBy !== undefined) group.offBy = offBy;\n\n const volume = num(props, \"volume\");\n if (volume !== undefined) group.volume = volume;\n\n const ampRelease = num(props, \"ampeg_release\");\n if (ampRelease !== undefined) group.ampRelease = ampRelease;\n\n const tune = num(props, \"tune\");\n if (tune !== undefined) group.tune = tune / 100; // SFZ tune is in cents, convert to semitones\n\n return group;\n}\n\nfunction buildRegion(\n props: Record<string, string | number>,\n pathFromSampleName: (name: string) => string,\n): SmplrRegion | null {\n const sampleRaw = str(props, \"sample\");\n if (!sampleRaw) return null;\n\n const sample = pathFromSampleName(sampleRaw);\n const region: SmplrRegion = { sample };\n\n // Key range\n const key = num(props, \"key\");\n if (key !== undefined) {\n region.key = key;\n } else {\n const lokey = num(props, \"lokey\");\n const hikey = num(props, \"hikey\");\n if (lokey !== undefined && hikey !== undefined) {\n region.keyRange = [lokey, hikey];\n }\n }\n\n // Pitch\n const pitchKeycenter = num(props, \"pitch_keycenter\");\n if (pitchKeycenter !== undefined) {\n region.pitch = pitchKeycenter;\n } else if (region.keyRange) {\n // Fall back to lokey as pitch if pitch_keycenter absent\n region.pitch = region.keyRange[0];\n } else if (key !== undefined) {\n region.pitch = key;\n }\n\n // Velocity range\n const lovel = num(props, \"lovel\");\n const hivel = num(props, \"hivel\");\n if (lovel !== undefined && hivel !== undefined) {\n region.velRange = [lovel, hivel];\n }\n\n // Round-robin\n const seqPosition = num(props, \"seq_position\");\n if (seqPosition !== undefined) region.seqPosition = seqPosition;\n\n // Exclusive groups\n const groupNum = num(props, \"group\");\n if (groupNum !== undefined) region.group = groupNum;\n\n const offBy = num(props, \"off_by\");\n if (offBy !== undefined) region.offBy = offBy;\n\n // Volume (dB)\n const volume = num(props, \"volume\");\n if (volume !== undefined) region.volume = volume;\n\n // Tune (SFZ cents → semitones)\n const tune = num(props, \"tune\");\n if (tune !== undefined) region.tune = tune / 100;\n\n // Amplitude release\n const ampRelease = num(props, \"ampeg_release\");\n if (ampRelease !== undefined) region.ampRelease = ampRelease;\n\n // Velocity curve\n const ampVelcurve = numArr(props, \"amp_velcurve\");\n if (ampVelcurve) region.ampVelCurve = ampVelcurve;\n\n return region;\n}\n\n// ---------------------------------------------------------------------------\n// Preprocessor — resolve #define directives\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve `#define $VAR value` directives by replacing all `$VAR` occurrences\n * in the text and stripping the directive lines.\n */\nfunction resolveDefines(sfz: string): string {\n const defines: Record<string, string> = {};\n const lines = sfz.split(\"\\n\");\n const output: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n const match = trimmed.match(/^#define\\s+(\\$\\w+)\\s+(.+)$/);\n if (match) {\n defines[match[1]] = match[2].trim();\n } else {\n output.push(line);\n }\n }\n\n let result = output.join(\"\\n\");\n for (const [key, value] of Object.entries(defines)) {\n // Escape $ for regex and replace all occurrences\n result = result.split(key).join(value);\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Tokenizer\n// ---------------------------------------------------------------------------\n\ntype HeaderToken = { type: \"header\"; value: string };\ntype PropToken = { type: \"prop\"; key: string; value: string | number };\ntype Token = HeaderToken | PropToken;\n\n/**\n * Tokenize SFZ text into a flat list of header or prop tokens.\n *\n * Handles:\n * - `// line comments`\n * - `<header>` — may appear inline or on own line\n * - `key=value` pairs — multiple per line, value may be a path (no spaces)\n */\nfunction tokenize(sfz: string): Token[] {\n const tokens: Token[] = [];\n\n for (let line of sfz.split(\"\\n\")) {\n // Strip line comments\n const commentIdx = line.indexOf(\"//\");\n if (commentIdx >= 0) line = line.slice(0, commentIdx);\n line = line.trim();\n if (!line) continue;\n\n // Process the line chunk by chunk\n let pos = 0;\n while (pos < line.length) {\n // Skip leading whitespace\n while (pos < line.length && line[pos] === \" \") pos++;\n if (pos >= line.length) break;\n\n // Header: <something>\n if (line[pos] === \"<\") {\n const end = line.indexOf(\">\", pos);\n if (end < 0) break;\n const headerName = line\n .slice(pos + 1, end)\n .trim()\n .toLowerCase();\n tokens.push({ type: \"header\", value: headerName });\n pos = end + 1;\n continue;\n }\n\n // Key=value: find the next = sign\n const eqIdx = line.indexOf(\"=\", pos);\n if (eqIdx < 0) break;\n\n const key = line.slice(pos, eqIdx).trim();\n\n // Value: read until next whitespace (for simple values) or next key=\n // We read until whitespace, but if the next token also looks like key=,\n // we stop there.\n let valueEnd = eqIdx + 1;\n // Find the end of the value: either end of line or the start of the next key=\n // Strategy: find next whitespace-preceded word that contains '='\n const rest = line.slice(eqIdx + 1);\n const nextKeyMatch = rest.match(/\\s+\\S+=\\S/);\n let rawValue: string;\n if (nextKeyMatch && nextKeyMatch.index !== undefined) {\n rawValue = rest.slice(0, nextKeyMatch.index).trim();\n valueEnd =\n eqIdx +\n 1 +\n nextKeyMatch.index +\n nextKeyMatch[0].length -\n nextKeyMatch[0].trimStart().length;\n } else {\n rawValue = rest.trim();\n valueEnd = line.length;\n }\n\n if (key && rawValue !== undefined) {\n const numVal = Number(rawValue);\n tokens.push({\n type: \"prop\",\n key,\n value: isNaN(numVal) ? rawValue : numVal,\n });\n }\n\n pos = valueEnd;\n }\n }\n\n return tokens;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction num(\n props: Record<string, string | number>,\n key: string,\n): number | undefined {\n const v = props[key];\n if (typeof v === \"number\") return v;\n return undefined;\n}\n\nfunction str(\n props: Record<string, string | number>,\n key: string,\n): string | undefined {\n const v = props[key];\n if (typeof v === \"string\") return v;\n return undefined;\n}\n\nfunction numArr(\n props: Record<string, string | number>,\n _prefix: string,\n): [number, number] | undefined {\n // SFZ amp_velcurve_N=V format: key is amp_velcurve_<velocity>\n for (const [k, v] of Object.entries(props)) {\n if (k.startsWith(\"amp_velcurve_\")) {\n const vel = Number(k.slice(\"amp_velcurve_\".length));\n if (!isNaN(vel) && typeof v === \"number\") {\n return [vel, v];\n }\n }\n }\n return undefined;\n}\n","import { AudioInsert } from \"./smplr/connect\";\nimport { Subscribe } from \"./smplr/signals\";\n\n// @private\nexport function createTremolo(\n context: BaseAudioContext,\n depth: Subscribe<number>,\n): AudioInsert {\n const input = context.createGain();\n const output = context.createGain();\n\n // force mono sources to be stereo\n input.channelCount = 2;\n input.channelCountMode = \"explicit\";\n\n const splitter = context.createChannelSplitter(2);\n const ampL = context.createGain();\n const ampR = context.createGain();\n const merger = context.createChannelMerger(2);\n\n const lfoL = context.createOscillator();\n lfoL.type = \"sine\";\n lfoL.frequency.value = 1;\n lfoL.start();\n const lfoLAmp = context.createGain();\n const lfoR = context.createOscillator();\n lfoR.type = \"sine\";\n lfoR.frequency.value = 1.1;\n lfoR.start();\n const lfoRAmp = context.createGain();\n\n input.connect(splitter);\n splitter.connect(ampL, 0);\n splitter.connect(ampR, 1);\n ampL.connect(merger, 0, 0);\n ampR.connect(merger, 0, 1);\n lfoL.connect(lfoLAmp);\n lfoLAmp.connect(ampL.gain);\n lfoR.connect(lfoRAmp);\n lfoRAmp.connect(ampR.gain);\n merger.connect(output);\n\n const unsubscribe = depth((depth) => {\n lfoLAmp.gain.value = depth;\n lfoRAmp.gain.value = depth;\n });\n\n input.disconnect = () => {\n unsubscribe();\n lfoL.stop();\n lfoR.stop();\n input.disconnect(splitter);\n splitter.disconnect(ampL, 0);\n splitter.disconnect(ampR, 1);\n ampL.disconnect(merger, 0, 0);\n ampR.disconnect(merger, 0, 1);\n lfoL.disconnect(ampL);\n lfoR.disconnect(ampR);\n merger.disconnect(output);\n };\n\n return { input, output };\n}\n","import { Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress } from \"./smplr/types\";\nimport { sfzToPreset } from \"./smplr/sfz-convert\";\nimport { createControl } from \"./smplr/signals\";\nimport { midiVelToGain } from \"./smplr/volume\";\nimport { createTremolo } from \"./tremolo\";\n\nexport function getElectricPianoNames() {\n return Object.keys(INSTRUMENTS);\n}\n\ntype InstrumentConfig = {\n sfzUrl: string;\n baseUrl: string;\n pathFromSampleName: (name: string) => string;\n};\n\n/** Strip file extension and prepend samples/ (Greg Sullivan pianos) */\nfunction gsPath(name: string): string {\n return \"samples/\" + name.replace(/\\.\\w+$/, \"\");\n}\n\n/** Strip file extension (VCSL instruments) */\nfunction vcslPath(name: string): string {\n return name.replace(/\\.\\w+$/, \"\");\n}\n\nconst GS_BASE =\n \"https://smpldsnds.github.io/sfzinstruments-greg-sullivan-e-pianos\";\n\nconst INSTRUMENTS: Record<string, InstrumentConfig> = {\n CP80: {\n sfzUrl: `${GS_BASE}/cp80/CP80.sfz`,\n baseUrl: `${GS_BASE}/cp80`,\n pathFromSampleName: gsPath,\n },\n PianetT: {\n sfzUrl: `${GS_BASE}/planet-t/Pianet T.sfz`,\n baseUrl: `${GS_BASE}/planet-t`,\n pathFromSampleName: gsPath,\n },\n WurlitzerEP200: {\n sfzUrl: `${GS_BASE}/wurlitzer-ep200/Wurlitzer EP200.sfz`,\n baseUrl: `${GS_BASE}/wurlitzer-ep200`,\n pathFromSampleName: gsPath,\n },\n TX81Z: {\n sfzUrl:\n \"https://smpldsnds.github.io/sgossner-vcsl/Electrophones/TX81Z - FM Piano.sfz\",\n baseUrl: \"https://smpldsnds.github.io/sgossner-vcsl/Electrophones\",\n pathFromSampleName: vcslPath,\n },\n};\n\nexport type ElectricPianoOptions = Partial<{\n instrument: string;\n storage: Storage;\n destination: AudioNode;\n volume: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan: number;\n velocity: number;\n onLoadProgress: (progress: LoadProgress) => void;\n /** Audio formats to try, in order of preference. Defaults to [\"ogg\", \"m4a\"]. */\n formats: string[];\n}>;\n\ntype ElectricPianoExtras = {\n tremolo: Readonly<{ level: (value: number) => void }>;\n};\n\nexport const ElectricPiano = Instrument(\n (\n ctx: BaseAudioContext,\n options: ElectricPianoOptions & { instrument: string },\n smplr,\n ) => {\n const config = INSTRUMENTS[options.instrument];\n if (!config) {\n throw new Error(\n `Unknown electric piano: \"${options.instrument}\". ` +\n `Valid names: ${Object.keys(INSTRUMENTS).join(\", \")}`,\n );\n }\n\n // Tremolo control + insert node — sync, so `tremolo.level(...)` is\n // callable before `await load` resolves.\n const depth = createControl(0);\n const tremolo: ElectricPianoExtras[\"tremolo\"] = {\n level: (level) => depth.set(midiVelToGain(level)),\n };\n const tremoloNode = createTremolo(ctx, depth.subscribe);\n smplr.output.addInsert(tremoloNode);\n\n const ready = fetch(config.sfzUrl)\n .then((r) => r.text())\n .then((sfzText) =>\n smplr.loadInstrument(\n sfzToPreset(sfzText, {\n baseUrl: config.baseUrl,\n pathFromSampleName: config.pathFromSampleName,\n formats: options.formats ?? [\"ogg\", \"m4a\"],\n }),\n ),\n );\n\n return { extras: { tremolo }, ready };\n },\n);\n\n/** Instance type returned by the {@link ElectricPiano} factory. */\nexport type ElectricPiano = ReturnType<typeof ElectricPiano>;\n","import { Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport type { PluginSmplr } from \"./smplr/instrument\";\nimport { LoadProgress } from \"./smplr/types\";\nimport { sfzToPreset } from \"./smplr/sfz-convert\";\n\nconst VCSL_BASE_URL = \"https://smpldsnds.github.io/sgossner-vcsl\";\n\nlet instruments: string[] = [];\n\nexport async function getVersilianInstruments(): Promise<string[]> {\n if (instruments.length) return instruments;\n instruments = await fetch(VCSL_BASE_URL + \"/sfz_files.json\").then((res) =>\n res.json(),\n );\n return instruments;\n}\n\nexport type VersilianConfig = {\n instrument: string;\n storage: Storage;\n};\n\nexport type VersilianOptions = Partial<\n VersilianConfig & {\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\n/**\n * Versilian\n *\n * The Versilian Community Sample Library is an open CC0 general-purpose sample\n * library created by Versilian Studios LLC.\n */\nexport const Versilian = Instrument(\n (ctx: BaseAudioContext, options: VersilianOptions = {}, smplr) =>\n loadVersilianInstrument(smplr, options),\n);\n\n/** Instance type returned by the {@link Versilian} factory. */\nexport type Versilian = ReturnType<typeof Versilian>;\n\n/**\n * Fetch the SFZ for a VCSL instrument and load it into `smplr`. Shared by\n * the {@link Versilian} and {@link Mallet} factories — not exported from the\n * package barrel.\n */\nexport function loadVersilianInstrument(\n smplr: PluginSmplr,\n options: VersilianOptions,\n): Promise<void> {\n const instrument = options.instrument ?? \"Strings/Violin/Violin - Arco\";\n const sfzUrl = `${VCSL_BASE_URL}/${instrument}.sfz`;\n const base = instrument.slice(0, instrument.lastIndexOf(\"/\") + 1);\n const sampleBaseUrl = `${VCSL_BASE_URL}/${base}`;\n\n return fetch(sfzUrl)\n .then((r) => r.text())\n .then((sfzText) =>\n smplr.loadInstrument(\n sfzToPreset(sfzText, {\n baseUrl: sampleBaseUrl,\n pathFromSampleName: (name) => name.replace(/\\.wav$/i, \"\"),\n formats: [\"ogg\", \"m4a\"],\n }),\n ),\n );\n}\n","import { Instrument } from \"./smplr\";\nimport { loadVersilianInstrument, VersilianOptions } from \"./versilian\";\n\nexport function getMalletNames(): string[] {\n return Object.keys(NAME_TO_PATH);\n}\n\nexport const Mallet = Instrument(\n (ctx: BaseAudioContext, options: VersilianOptions = {}, smplr) =>\n loadVersilianInstrument(smplr, {\n ...options,\n instrument: NAME_TO_PATH[options.instrument ?? \"\"],\n }),\n);\n\n/** Instance type returned by the {@link Mallet} factory. */\nexport type Mallet = ReturnType<typeof Mallet>;\n\ntype MalletName = keyof typeof NAME_TO_PATH;\n\nexport const NAME_TO_PATH: Record<string, string | undefined> = {\n \"Balafon - Hard Mallet\": \"Idiophones/Struck Idiophones/Balafon - Hard Mallet\",\n \"Balafon - Keyswitch\": \"Idiophones/Struck Idiophones/Balafon - Keyswitch\",\n \"Balafon - Soft Mallet\": \"Idiophones/Struck Idiophones/Balafon - Soft Mallet\",\n \"Balafon - Traditional Mallet\":\n \"Idiophones/Struck Idiophones/Balafon - Traditional Mallet\",\n\n \"Tubular Bells 1\": \"Idiophones/Struck Idiophones/Tubular Bells 1\",\n \"Tubular Bells 2\": \"Idiophones/Struck Idiophones/Tubular Bells 2\",\n\n \"Vibraphone - Bowed\": \"Idiophones/Struck Idiophones/Vibraphone - Bowed\",\n \"Vibraphone - Hard Mallets\":\n \"Idiophones/Struck Idiophones/Vibraphone - Hard Mallets\",\n \"Vibraphone - Keyswitch\":\n \"Idiophones/Struck Idiophones/Vibraphone - Keyswitch\",\n \"Vibraphone - Soft Mallets\":\n \"Idiophones/Struck Idiophones/Vibraphone - Soft Mallets\",\n\n \"Xylophone - Hard Mallets\":\n \"Idiophones/Struck Idiophones/Xylophone - Hard Mallets\",\n \"Xylophone - Keyswitch\": \"Idiophones/Struck Idiophones/Xylophone - Keyswitch\",\n \"Xylophone - Medium Mallets\":\n \"Idiophones/Struck Idiophones/Xylophone - Medium Mallets\",\n \"Xylophone - Soft Mallets\":\n \"Idiophones/Struck Idiophones/Xylophone - Soft Mallets\",\n} as const;\n","/**\n * Given a list of [midi, sampleName] pairs, return one entry per sample with\n * a keyRange that covers all MIDI notes closer to that sample than to any\n * neighbour. The first sample extends down to 0; the last extends up to 127.\n *\n * The boundary between two adjacent samples A and B (A < B) is placed at\n * `floor((A + B) / 2)`, matching the behaviour of the old `findNearestMidiInLayer`\n * which always resolved ties in favour of the lower sample.\n */\n/** @internal Not part of the public 1.0 API surface. */\nexport type SpreadResult = {\n keyRange: [number, number];\n pitch: number;\n sample: string;\n};\n\n/** @internal Not part of the public 1.0 API surface. */\nexport function spreadKeyRanges(samples: [number, string][]): SpreadResult[] {\n if (samples.length === 0) return [];\n\n // Work on a sorted copy — caller order doesn't matter\n const sorted = [...samples].sort(([a], [b]) => a - b);\n\n return sorted.map(([midi, name], i) => {\n const low = i === 0 ? 0 : Math.floor((sorted[i - 1][0] + midi) / 2) + 1;\n\n const high =\n i === sorted.length - 1 ? 127 : Math.floor((midi + sorted[i + 1][0]) / 2);\n\n return {\n keyRange: [low, high] as [number, number],\n pitch: midi,\n sample: name,\n };\n });\n}\n","import { toMidi } from \"./smplr/midi\";\nimport { Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress, SmplrGroup, SmplrPreset } from \"./smplr/types\";\nimport { spreadKeyRanges } from \"./smplr/utils\";\n\nconst INSTRUMENT_VARIATIONS: Record<string, [string, string]> = {\n \"300 STRINGS CELLO\": [\"300 STRINGS\", \"CELL\"],\n \"300 STRINGS VIOLA\": [\"300 STRINGS\", \"VIOL\"],\n};\n\nexport function getMellotronNames() {\n return [\n \"300 STRINGS CELLO\",\n \"300 STRINGS VIOLA\",\n \"8VOICE CHOIR\",\n \"BASSA+STRNGS\",\n \"BOYS CHOIR\",\n \"CHA CHA FLT\",\n \"CHM CLARINET\",\n \"CHMB 3 VLNS\",\n \"CHMB ALTOSAX\",\n \"CHMB FEMALE\",\n \"CHMB MALE VC\",\n \"CHMB TNR SAX\",\n \"CHMB TRMBONE\",\n \"CHMB TRUMPET\",\n \"CHMBLN CELLO\",\n \"CHMBLN FLUTE\",\n \"CHMBLN OBOE\",\n \"DIXIE+TRMBN\",\n \"FOXTROT+SAX\",\n \"HALFSP.BRASS\",\n \"MIXED STRGS\",\n \"MKII BRASS\",\n \"MKII GUITAR\",\n \"MKII ORGAN\",\n \"MKII SAX\",\n \"MKII VIBES\",\n \"MKII VIOLINS\",\n \"MOVE BS+STGS\",\n \"STRGS+BRASS\",\n \"TROMB+TRMPT\",\n \"TRON 16VLNS\",\n \"TRON CELLO\",\n \"TRON FLUTE\",\n \"TRON VIOLA\",\n ];\n}\n\nexport type MellotronConfig = {\n instrument: string;\n storage: Storage;\n};\n\nexport type MellotronOptions = Partial<\n MellotronConfig & {\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n decayTime?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nexport const Mellotron = Instrument(\n (ctx: BaseAudioContext, options: MellotronOptions = {}, smplr) => {\n const instrument = options.instrument ?? \"MKII VIOLINS\";\n const variation = INSTRUMENT_VARIATIONS[instrument];\n const instrumentName = variation ? variation[0] : instrument;\n const baseUrl = `https://smpldsnds.github.io/archiveorg-mellotron/${instrumentName}/`;\n\n return fetch(baseUrl + \"files.json\")\n .then((r) => r.json() as Promise<string[]>)\n .then((names) =>\n smplr.loadInstrument(\n mellotronToPreset(names, {\n instrument: instrumentName,\n variation: variation?.[1],\n }),\n ),\n );\n },\n);\n\n/** Instance type returned by the {@link Mellotron} factory. */\nexport type Mellotron = ReturnType<typeof Mellotron>;\n\n// ---------------------------------------------------------------------------\n// mellotronToPreset — pure converter function\n// ---------------------------------------------------------------------------\n\ntype MellotronJsonConfig = {\n instrument: string;\n variation?: string;\n};\n\n/**\n * Convert a Mellotron files.json sample list to SmplrPreset.\n *\n * - Filters by variation string if provided.\n * - Extracts MIDI from the first word of each sample name.\n * - Uses spreadKeyRanges so nearby notes pitch-shift to the nearest sample.\n * - All regions get loopAuto to produce tape-loop playback.\n */\nexport function mellotronToPreset(\n sampleNames: string[],\n config: MellotronJsonConfig,\n): SmplrPreset {\n const entries: [number, string][] = [];\n\n for (const sampleName of sampleNames) {\n // Filter by variation (e.g., only \"CELL\" samples for CELLO variation)\n if (config.variation && !sampleName.includes(config.variation)) continue;\n\n const midi = toMidi(sampleName.split(\" \")[0] ?? \"\");\n if (!midi) continue;\n\n entries.push([midi, sampleName]);\n }\n\n const spread = spreadKeyRanges(entries);\n const baseUrl = `https://smpldsnds.github.io/archiveorg-mellotron/${config.instrument}/`;\n\n const regions: SmplrGroup[\"regions\"] = spread.map(\n ({ keyRange, pitch, sample }) => ({\n sample,\n keyRange,\n pitch,\n loopAuto: { startRatio: 0.1, endRatio: 0.9 },\n }),\n );\n\n return {\n samples: {\n baseUrl,\n formats: [\"ogg\", \"m4a\"],\n },\n groups: [{ regions }],\n };\n}\n","export const PROCESSOR = `\"use strict\";(()=>{var f=class extends AudioWorkletProcessor{_pDLength;_preDelay;_pDWrite;_lp1;_lp2;_lp3;_excPhase;_taps;_Delays;sampleRate;static get parameterDescriptors(){return[[\"preDelay\",0,0,sampleRate-1,\"k-rate\"],[\"bandwidth\",.9999,0,1,\"k-rate\"],[\"inputDiffusion1\",.75,0,1,\"k-rate\"],[\"inputDiffusion2\",.625,0,1,\"k-rate\"],[\"decay\",.5,0,1,\"k-rate\"],[\"decayDiffusion1\",.7,0,.999999,\"k-rate\"],[\"decayDiffusion2\",.5,0,.999999,\"k-rate\"],[\"damping\",.005,0,1,\"k-rate\"],[\"excursionRate\",.5,0,2,\"k-rate\"],[\"excursionDepth\",.7,0,2,\"k-rate\"],[\"wet\",1,0,1,\"k-rate\"],[\"dry\",0,0,1,\"k-rate\"]].map(e=>new Object({name:e[0],defaultValue:e[1],minValue:e[2],maxValue:e[3],automationRate:e[4]}))}constructor(e){super(),this.sampleRate=sampleRate,this._Delays=[],this._pDLength=sampleRate+(128-sampleRate%128),this._preDelay=new Float32Array(this._pDLength),this._pDWrite=0,this._lp1=0,this._lp2=0,this._lp3=0,this._excPhase=0,[.004771345,.003595309,.012734787,.009307483,.022579886,.149625349,.060481839,.1249958,.030509727,.141695508,.089244313,.106280031].forEach(a=>this.makeDelay(a,sampleRate)),this._taps=Int16Array.from([.008937872,.099929438,.064278754,.067067639,.066866033,.006283391,.035818689,.011861161,.121870905,.041262054,.08981553,.070931756,.011256342,.004065724],a=>Math.round(a*sampleRate))}makeDelay(e,a){let t=Math.round(e*a),s=2**Math.ceil(Math.log2(t));this._Delays.push([new Float32Array(s),t-1,0,s-1])}writeDelay(e,a){return this._Delays[e][0][this._Delays[e][1]]=a}readDelay(e){return this._Delays[e][0][this._Delays[e][2]]}readDelayAt(e,a){let t=this._Delays[e];return t[0][t[2]+a&t[3]]}readDelayCAt(e,a){let t=this._Delays[e],s=a-~~a,d=~~a+t[2]-1,r=t[3],D=t[0][d++&r],l=t[0][d++&r],h=t[0][d++&r],y=t[0][d&r],u=(3*(l-h)-D+y)/2,m=2*h+D-(5*l+y)/2,c=(h-D)/2;return((u*s+m)*s+c)*s+l}process(e,a,t){let s=~~t.preDelay[0],d=t.bandwidth[0],r=t.inputDiffusion1[0],D=t.inputDiffusion2[0],l=t.decay[0],h=t.decayDiffusion1[0],y=t.decayDiffusion2[0],u=1-t.damping[0],m=t.excursionRate[0]/sampleRate,c=t.excursionDepth[0]*sampleRate/1e3,w=t.wet[0]*.6,A=t.dry[0];if(e[0].length==2)for(let i=127;i>=0;i--)this._preDelay[this._pDWrite+i]=(e[0][0][i]+e[0][1][i])*.5,a[0][0][i]=e[0][0][i]*A,a[0][1][i]=e[0][1][i]*A;else if(e[0].length>0){this._preDelay.set(e[0][0],this._pDWrite);for(let i=127;i>=0;i--)a[0][0][i]=a[0][1][i]=e[0][0][i]*A}else this._preDelay.set(new Float32Array(128),this._pDWrite);let o=0;for(;o<128;){let i=0,b=0;this._lp1+=d*(this._preDelay[(this._pDLength+this._pDWrite-s+o)%this._pDLength]-this._lp1);let p=this.writeDelay(0,this._lp1-r*this.readDelay(0));p=this.writeDelay(1,r*(p-this.readDelay(1))+this.readDelay(0)),p=this.writeDelay(2,r*p+this.readDelay(1)-D*this.readDelay(2)),p=this.writeDelay(3,D*(p-this.readDelay(3))+this.readDelay(2));let k=D*p+this.readDelay(3),g=c*(1+Math.cos(this._excPhase*6.28)),x=c*(1+Math.sin(this._excPhase*6.2847)),_=this.writeDelay(4,k+l*this.readDelay(11)+h*this.readDelayCAt(4,g));this.writeDelay(5,this.readDelayCAt(4,g)-h*_),this._lp2+=u*(this.readDelay(5)-this._lp2),_=this.writeDelay(6,l*this._lp2-y*this.readDelay(6)),this.writeDelay(7,this.readDelay(6)+y*_),_=this.writeDelay(8,k+l*this.readDelay(7)+h*this.readDelayCAt(8,x)),this.writeDelay(9,this.readDelayCAt(8,x)-h*_),this._lp3+=u*(this.readDelay(9)-this._lp3),_=this.writeDelay(10,l*this._lp3-y*this.readDelay(10)),this.writeDelay(11,this.readDelay(10)+y*_),i=this.readDelayAt(9,this._taps[0])+this.readDelayAt(9,this._taps[1])-this.readDelayAt(10,this._taps[2])+this.readDelayAt(11,this._taps[3])-this.readDelayAt(5,this._taps[4])-this.readDelayAt(6,this._taps[5])-this.readDelayAt(7,this._taps[6]),b=this.readDelayAt(5,this._taps[7])+this.readDelayAt(5,this._taps[8])-this.readDelayAt(6,this._taps[9])+this.readDelayAt(7,this._taps[10])-this.readDelayAt(9,this._taps[11])-this.readDelayAt(10,this._taps[12])-this.readDelayAt(11,this._taps[13]),a[0][0][o]+=i*w,a[0][1][o]+=b*w,this._excPhase+=m,o++;for(let R=0,n=this._Delays[0];R<this._Delays.length;n=this._Delays[++R])n[1]=n[1]+1&n[3],n[2]=n[2]+1&n[3]}return this._pDWrite=(this._pDWrite+128)%this._pDLength,!0}};registerProcessor(\"DattorroReverb\",f);})();`;\n","import { asConstructable } from \"../smplr/as-constructable\";\nimport { PROCESSOR } from \"./processor.min\";\n\nconst PARAMS = [\n \"preDelay\",\n \"bandwidth\",\n \"inputDiffusion1\",\n \"inputDiffusion2\",\n \"decay\",\n \"decayDiffusion1\",\n \"decayDiffusion2\",\n \"damping\",\n \"excursionRate\",\n \"excursionDepth\",\n \"wet\",\n \"dry\",\n] as const;\n\nconst init = new WeakMap<AudioContext, Promise<void>>();\n\nasync function createDattorroReverbEffect(\n context: AudioContext,\n): Promise<AudioWorkletNode | undefined> {\n if (!context.audioWorklet) {\n console.warn(\n \"AudioWorklet not supported in this context. Reverb not available.\",\n );\n return undefined;\n }\n let ready = init.get(context);\n if (!ready) {\n const blob = new Blob([PROCESSOR], { type: \"application/javascript\" });\n const url = URL.createObjectURL(blob);\n ready = context.audioWorklet.addModule(url);\n init.set(context, ready);\n }\n await ready;\n\n const reverb = new AudioWorkletNode(context, \"DattorroReverb\", {\n outputChannelCount: [2],\n });\n return reverb;\n}\n\nclass ReverbImpl {\n #effect: AudioWorkletNode | undefined;\n #ready: Promise<this>;\n public readonly input: AudioNode;\n #output: AudioNode;\n\n constructor(context: AudioContext) {\n this.input = context.createGain();\n this.#output = context.destination;\n this.#ready = createDattorroReverbEffect(context).then((reverb) => {\n if (reverb) {\n this.input.connect(reverb);\n reverb.connect(this.#output);\n this.#effect = reverb;\n }\n return this;\n });\n }\n\n get paramNames() {\n return PARAMS;\n }\n\n getParam(name: (typeof PARAMS)[number]): AudioParam | undefined {\n return this.#effect?.parameters.get(\"preDelay\");\n }\n\n get isReady(): boolean {\n return this.#effect !== undefined;\n }\n\n ready(): Promise<this> {\n return this.#ready;\n }\n\n connect(output: AudioNode) {\n if (this.#effect) {\n this.#effect.disconnect(this.#output);\n this.#effect.connect(output);\n }\n this.#output = output;\n }\n}\n\nexport const Reverb = asConstructable(ReverbImpl);\nexport type Reverb = ReturnType<typeof Reverb>;\n","import {\n AudioBuffers,\n AudioBuffersLoader,\n loadAudioBuffer,\n} from \"./smplr/load-audio\";\nimport { toMidi } from \"./smplr/midi\";\nimport { HttpStorage, Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress, SmplrPreset } from \"./smplr/types\";\nimport { spreadKeyRanges } from \"./smplr/utils\";\n\ntype SamplerBase = {\n storage?: Storage;\n detune?: number;\n volume?: number;\n pan?: number;\n velocity?: number;\n decayTime?: number;\n lpfCutoffHz?: number;\n destination?: AudioNode;\n volumeToGain?: (volume: number) => number;\n onLoadProgress?: (progress: LoadProgress) => void;\n};\n\ntype SamplerBuffers =\n | Record<string | number, string | AudioBuffer | AudioBuffers>\n | AudioBuffersLoader;\n\ntype SamplerBuffersInput = {\n buffers?: SamplerBuffers;\n preset?: never;\n};\n\ntype SamplerPresetInput = {\n preset: SmplrPreset;\n buffers?: never;\n};\n\nexport type SamplerConfig = SamplerBase &\n (SamplerBuffersInput | SamplerPresetInput);\n\n/** Input accepted by {@link Sampler.reload}: a `SmplrPreset` schema or a flat buffers record/loader. */\nexport type SamplerReloadInput = SmplrPreset | SamplerBuffers;\n\ntype SamplerExtras = {\n reload: (input: SamplerReloadInput) => Promise<void>;\n};\n\nfunction isSmplrPreset(x: unknown): x is SmplrPreset {\n return (\n typeof x === \"object\" &&\n x !== null &&\n \"groups\" in x &&\n Array.isArray((x as SmplrPreset).groups)\n );\n}\n\n/**\n * A Sampler instrument. Accepts either a flat record of samples\n * (`{ buffers: { C4: \"url\" } }`) or a full `SmplrPreset`\n * (`{ preset: { samples, groups, ... } }`) for advanced use cases including\n * per-region pitch/velocity/round-robin control.\n *\n * Use `sampler.reload(input)` to swap content at runtime. `reload` accepts\n * either shape (flat record or `SmplrPreset`), regardless of which mode was\n * used at construction.\n */\nexport const Sampler = Instrument<SamplerConfig, SamplerExtras>(\n (ctx: BaseAudioContext, options: SamplerConfig = {}, smplr) => {\n const storage = options.storage ?? HttpStorage;\n\n const loadFromInput = (input: SamplerReloadInput): Promise<void> => {\n if (isSmplrPreset(input)) {\n return smplr.loadInstrument(input);\n }\n return getSource(ctx, input)\n .then((source) => buildSamplerBuffers(source, ctx, storage, options))\n .then(({ json, buffers }) => smplr.loadInstrument(json, buffers));\n };\n\n const initialInput: SamplerReloadInput =\n \"preset\" in options && options.preset\n ? options.preset\n : ((options as SamplerBuffersInput).buffers ?? {});\n\n return {\n extras: { reload: loadFromInput },\n ready: loadFromInput(initialInput),\n };\n },\n);\n\nfunction getSource(\n ctx: BaseAudioContext,\n raw: NonNullable<Partial<SamplerConfig>[\"buffers\"]>,\n): Promise<Record<string | number, string | AudioBuffer>> {\n if (typeof raw === \"function\") {\n const ab: AudioBuffers = {};\n return (raw as AudioBuffersLoader)(ctx, ab).then(\n () => ab as Record<string | number, string | AudioBuffer>,\n );\n }\n return Promise.resolve(raw as Record<string | number, string | AudioBuffer>);\n}\n\n// ---------------------------------------------------------------------------\n// samplerToPreset — pure converter function (no async)\n// ---------------------------------------------------------------------------\n\ntype SamplerJsonOptions = Pick<\n SamplerConfig,\n \"decayTime\" | \"lpfCutoffHz\" | \"detune\"\n>;\n\ntype ConvertResult = {\n json: SmplrPreset;\n /** Resolved AudioBuffer instances, including URL-fetched ones. */\n buffers: Map<string, AudioBuffer>;\n};\n\n/**\n * Load all URL samples and build a SmplrPreset + pre-loaded buffers map.\n * All samples (URL-fetched and pre-provided AudioBuffers) are passed as\n * pre-loaded, so SampleLoader never makes network requests.\n */\nasync function buildSamplerBuffers(\n source: Record<string | number, string | AudioBuffer>,\n context: BaseAudioContext,\n storage: Storage,\n options: Partial<SamplerJsonOptions>,\n): Promise<ConvertResult> {\n const { json, urlMap, preloaded } = samplerToPreset(source, options);\n\n // Fetch URL-based samples\n await Promise.all(\n Object.entries(urlMap).map(async ([name, url]) => {\n const buffer = await loadAudioBuffer(context, url, storage);\n if (buffer) preloaded.set(name, buffer);\n }),\n );\n\n return { json, buffers: preloaded };\n}\n\ntype InternalConvertResult = {\n json: SmplrPreset;\n urlMap: Record<string, string>;\n preloaded: Map<string, AudioBuffer>;\n};\n\n/**\n * Convert a flat source Record to SmplrPreset + separated URL map + pre-loaded buffers.\n *\n * - Keys that are valid MIDI names/numbers → MIDI-mapped regions.\n * If ALL keys are MIDI-parseable, spread key ranges (pitch-shifting).\n * Otherwise each MIDI key gets an exact [n, n] range.\n * - Non-MIDI keys are assigned sequential MIDI numbers and added to `aliases`.\n * - AudioBuffer values → pre-loaded map (no fetch).\n * - String URL values → urlMap (fetched asynchronously by caller).\n */\nexport function samplerToPreset(\n source: Record<string | number, string | AudioBuffer>,\n options: Partial<SamplerJsonOptions> = {},\n): InternalConvertResult {\n const keys = Object.keys(source);\n const preloaded = new Map<string, AudioBuffer>();\n const urlMap: Record<string, string> = {};\n const aliases: Record<string, number> = {};\n\n // Separate MIDI-parseable keys from arbitrary string keys\n const midiEntries: [number, string][] = [];\n const nonMidiKeys: string[] = [];\n\n for (const key of keys) {\n const midi = toMidi(key as string | number);\n if (midi !== undefined) {\n midiEntries.push([midi, key]);\n } else {\n nonMidiKeys.push(key);\n }\n }\n\n const allMidi = nonMidiKeys.length === 0;\n\n type Entry = {\n midi: number;\n key: string;\n sampleName: string;\n keyRange: [number, number];\n pitch: number;\n };\n\n const entries: Entry[] = [];\n\n if (allMidi && midiEntries.length > 0) {\n // All keys are MIDI → spread key ranges for pitch-shifting\n const spread = spreadKeyRanges(\n midiEntries.map(([midi, key]) => [midi, key] as [number, string]),\n );\n for (let i = 0; i < midiEntries.length; i++) {\n const [midi, key] = midiEntries[i];\n const { keyRange, pitch } = spread[i];\n entries.push({ midi, key, sampleName: key, keyRange, pitch });\n }\n } else {\n // Mixed or all non-MIDI: exact ranges for MIDI keys, sequential for others\n for (const [midi, key] of midiEntries) {\n entries.push({\n midi,\n key,\n sampleName: key,\n keyRange: [midi, midi],\n pitch: midi,\n });\n }\n\n let seqMidi = 0;\n for (const key of nonMidiKeys) {\n while (entries.some((e) => e.midi === seqMidi)) seqMidi++;\n const midi = seqMidi++;\n aliases[key] = midi;\n entries.push({\n midi,\n key,\n sampleName: key,\n keyRange: [midi, midi],\n pitch: midi,\n });\n }\n }\n\n // Populate pre-loaded map and URL map\n for (const { key, sampleName } of entries) {\n const value = source[key];\n if (value instanceof AudioBuffer) {\n preloaded.set(sampleName, value);\n } else if (typeof value === \"string\") {\n urlMap[sampleName] = value;\n }\n }\n\n const json: SmplrPreset = {\n // baseUrl doesn't matter: all samples will be pre-loaded\n samples: { baseUrl: \"\", formats: [\"ogg\"] },\n groups: [\n {\n regions: entries.map(({ sampleName, keyRange, pitch }) => ({\n sample: sampleName,\n keyRange,\n pitch,\n })),\n },\n ],\n aliases: Object.keys(aliases).length > 0 ? aliases : undefined,\n defaults: {\n ampRelease: options.decayTime,\n lpfCutoffHz: options.lpfCutoffHz,\n detune: options.detune,\n },\n };\n\n return { json, urlMap, preloaded };\n}\n\n/** Instance type returned by the {@link Sampler} factory. */\nexport type Sampler = ReturnType<typeof Sampler>;\n","import { Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress } from \"./smplr/types\";\nimport { sfzToPreset } from \"./smplr/sfz-convert\";\n\nexport function getSmolkenNames() {\n return [\"Pizzicato\", \"Arco\", \"Switched\"];\n}\n\nfunction getSmolkenUrl(instrument: string) {\n const FILES: Record<string, string> = {\n Arco: \"arco\",\n Pizzicato: \"pizz\",\n Switched: \"switched\",\n };\n return `https://smpldsnds.github.io/sfzinstruments-dsmolken-double-bass/d_smolken_rubner_bass_${FILES[instrument]}.sfz`;\n}\n\nexport type SmolkenConfig = {\n instrument: string;\n storage: Storage;\n};\n\nexport type SmolkenOptions = Partial<\n SmolkenConfig & {\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nconst SMOLKEN_BASE_URL =\n \"https://smpldsnds.github.io/sfzinstruments-dsmolken-double-bass\";\n\nexport const Smolken = Instrument(\n (ctx: BaseAudioContext, options: SmolkenOptions = {}, smplr) => {\n const sfzUrl = getSmolkenUrl(options.instrument ?? \"Arco\");\n return fetch(sfzUrl)\n .then((r) => r.text())\n .then((sfzText) =>\n smplr.loadInstrument(\n sfzToPreset(sfzText, {\n baseUrl: SMOLKEN_BASE_URL,\n pathFromSampleName: (name) =>\n name.replace(/\\\\/g, \"/\").replace(/\\.wav$/i, \"\"),\n formats: [\"ogg\", \"m4a\"],\n }),\n ),\n );\n },\n);\n\n/** Instance type returned by the {@link Smolken} factory. */\nexport type Smolken = ReturnType<typeof Smolken>;\n","import { findFirstSupportedFormat } from \"../smplr/load-audio\";\n\nexport function gleitzKitUrl(name: string, kit: string) {\n const format = findFirstSupportedFormat([\"ogg\", \"mp3\"]) ?? \"mp3\";\n console.debug(`Soundfont: using ${format} format for ${name}`);\n return `https://gleitz.github.io/midi-js-soundfonts/${kit}/${name}-${format}.js`;\n}\n\nexport const SOUNDFONT_KITS = [\"MusyngKite\", \"FluidR3_GM\"];\nexport const DEFAULT_SOUNDFONT_KIT = SOUNDFONT_KITS[0];\n\nexport const SOUNDFONT_INSTRUMENTS = [\n \"accordion\",\n \"acoustic_bass\",\n \"acoustic_grand_piano\",\n \"acoustic_guitar_nylon\",\n \"acoustic_guitar_steel\",\n \"agogo\",\n \"alto_sax\",\n \"applause\",\n \"bagpipe\",\n \"banjo\",\n \"baritone_sax\",\n \"bassoon\",\n \"bird_tweet\",\n \"blown_bottle\",\n \"brass_section\",\n \"breath_noise\",\n \"bright_acoustic_piano\",\n \"celesta\",\n \"cello\",\n \"choir_aahs\",\n \"church_organ\",\n \"clarinet\",\n \"clavinet\",\n \"contrabass\",\n \"distortion_guitar\",\n \"drawbar_organ\",\n \"dulcimer\",\n \"electric_bass_finger\",\n \"electric_bass_pick\",\n \"electric_grand_piano\",\n \"electric_guitar_clean\",\n \"electric_guitar_jazz\",\n \"electric_guitar_muted\",\n \"electric_piano_1\",\n \"electric_piano_2\",\n \"english_horn\",\n \"fiddle\",\n \"flute\",\n \"french_horn\",\n \"fretless_bass\",\n \"fx_1_rain\",\n \"fx_2_soundtrack\",\n \"fx_3_crystal\",\n \"fx_4_atmosphere\",\n \"fx_5_brightness\",\n \"fx_6_goblins\",\n \"fx_7_echoes\",\n \"fx_8_scifi\",\n \"glockenspiel\",\n \"guitar_fret_noise\",\n \"guitar_harmonics\",\n \"gunshot\",\n \"harmonica\",\n \"harpsichord\",\n \"helicopter\",\n \"honkytonk_piano\",\n \"kalimba\",\n \"koto\",\n \"lead_1_square\",\n \"lead_2_sawtooth\",\n \"lead_3_calliope\",\n \"lead_4_chiff\",\n \"lead_5_charang\",\n \"lead_6_voice\",\n \"lead_7_fifths\",\n \"lead_8_bass__lead\",\n \"marimba\",\n \"melodic_tom\",\n \"music_box\",\n \"muted_trumpet\",\n \"oboe\",\n \"ocarina\",\n \"orchestra_hit\",\n \"orchestral_harp\",\n \"overdriven_guitar\",\n \"pad_1_new_age\",\n \"pad_2_warm\",\n \"pad_3_polysynth\",\n \"pad_4_choir\",\n \"pad_5_bowed\",\n \"pad_6_metallic\",\n \"pad_7_halo\",\n \"pad_8_sweep\",\n \"pan_flute\",\n \"percussive_organ\",\n \"piccolo\",\n \"pizzicato_strings\",\n \"recorder\",\n \"reed_organ\",\n \"reverse_cymbal\",\n \"rock_organ\",\n \"seashore\",\n \"shakuhachi\",\n \"shamisen\",\n \"shanai\",\n \"sitar\",\n \"slap_bass_1\",\n \"slap_bass_2\",\n \"soprano_sax\",\n \"steel_drums\",\n \"string_ensemble_1\",\n \"string_ensemble_2\",\n \"synth_bass_1\",\n \"synth_bass_2\",\n \"synth_brass_1\",\n \"synth_brass_2\",\n \"synth_choir\",\n \"synth_drum\",\n \"synth_strings_1\",\n \"synth_strings_2\",\n \"taiko_drum\",\n \"tango_accordion\",\n \"telephone_ring\",\n \"tenor_sax\",\n \"timpani\",\n \"tinkle_bell\",\n \"tremolo_strings\",\n \"trombone\",\n \"trumpet\",\n \"tuba\",\n \"tubular_bells\",\n \"vibraphone\",\n \"viola\",\n \"violin\",\n \"voice_oohs\",\n \"whistle\",\n \"woodblock\",\n \"xylophone\",\n];\n","import { toMidi } from \"../smplr/midi\";\n\nexport type LoopData = Record<number, [number, number]>;\n\nexport function getGoldstSoundfontLoopsUrl(instrument: string, kit: string) {\n if (instrument.startsWith(\"http\")) return undefined;\n return `https://goldst.dev/midi-js-soundfonts/${kit}/${instrument}-loop.json`;\n}\n\n/**\n *\n * @see https://github.com/goldst/midi-js-soundfonts\n * @see https://github.com/danigb/smplr/issues/23\n */\nexport async function fetchSoundfontLoopData(\n url?: string,\n sampleRate = 44100,\n): Promise<LoopData | undefined> {\n if (!url) return undefined;\n try {\n const req = await fetch(url);\n if (req.status !== 200) return;\n\n const raw = await req.json();\n const loopData: LoopData = {};\n Object.keys(raw).forEach((key) => {\n const midi = toMidi(key);\n if (midi) {\n const offsets = raw[key];\n loopData[midi] = [offsets[0] / sampleRate, offsets[1] / sampleRate];\n }\n });\n return loopData;\n } catch (err) {\n return undefined;\n }\n}\n","import { HttpStorage, Storage } from \"../storage\";\nimport { Instrument } from \"../smplr\";\nimport { LoadProgress, SmplrGroup, SmplrPreset } from \"../smplr/types\";\nimport { spreadKeyRanges } from \"../smplr/utils\";\nimport { toMidi } from \"../smplr/midi\";\nimport {\n SOUNDFONT_INSTRUMENTS,\n SOUNDFONT_KITS,\n DEFAULT_SOUNDFONT_KIT,\n gleitzKitUrl,\n} from \"./soundfont-instrument\";\nimport {\n LoopData,\n fetchSoundfontLoopData,\n getGoldstSoundfontLoopsUrl,\n} from \"./soundfont-loops\";\n\nexport function getSoundfontKits() {\n return SOUNDFONT_KITS;\n}\n\nexport function getSoundfontNames() {\n return SOUNDFONT_INSTRUMENTS;\n}\n\ntype SoundfontConfig = {\n kit: \"FluidR3_GM\" | \"MusyngKite\" | string;\n instrument?: string;\n instrumentUrl: string;\n storage: Storage;\n extraGain: number;\n loadLoopData: boolean;\n loopDataUrl?: string;\n};\n\nexport type SoundfontOptions = Partial<\n SoundfontConfig & {\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nexport const Soundfont = Instrument(\n (ctx: BaseAudioContext, options: SoundfontOptions = {}, smplr) => {\n const config = getSoundfontConfig(options);\n\n // Apply extra gain insert synchronously, before the first audible note\n // can reach the output.\n const gain = ctx.createGain();\n gain.gain.value = config.extraGain;\n smplr.output.addInsert(gain);\n\n return loadSoundfontData(ctx, config).then(\n ({ buffers, noteNames, loopData }) =>\n smplr.loadInstrument(soundfontToPreset(noteNames, loopData), buffers),\n );\n },\n);\n\n/** Instance type returned by the {@link Soundfont} factory. */\nexport type Soundfont = ReturnType<typeof Soundfont>;\n\n// ---------------------------------------------------------------------------\n// loadSoundfontData — async loader for base64-encoded MIDI.js files\n// ---------------------------------------------------------------------------\n\ntype SoundfontData = {\n buffers: Map<string, AudioBuffer>;\n noteNames: string[];\n loopData?: LoopData;\n};\n\nasync function loadSoundfontData(\n context: BaseAudioContext,\n config: SoundfontConfig,\n): Promise<SoundfontData> {\n const [{ buffers, noteNames }, loopData] = await Promise.all([\n decodeSoundfontFile(context, config),\n fetchSoundfontLoopData(config.loopDataUrl),\n ]);\n\n return { buffers, noteNames, loopData };\n}\n\nasync function decodeSoundfontFile(\n context: BaseAudioContext,\n config: SoundfontConfig,\n): Promise<{ buffers: Map<string, AudioBuffer>; noteNames: string[] }> {\n const sourceFile = await (\n await config.storage.fetch(config.instrumentUrl)\n ).text();\n const json = midiJsToJson(sourceFile);\n\n const noteNames = Object.keys(json);\n const buffers = new Map<string, AudioBuffer>();\n\n await Promise.all(\n noteNames.map(async (noteName) => {\n const midi = toMidi(noteName);\n if (!midi) return;\n try {\n const audioData = base64ToArrayBuffer(\n removeBase64Prefix(json[noteName]),\n );\n const buffer = await context.decodeAudioData(audioData);\n buffers.set(noteName, buffer);\n } catch (error) {\n console.warn(\n `Soundfont: failed to decode note ${noteName}`,\n error instanceof Error ? error.message : error,\n );\n }\n }),\n );\n\n return { buffers, noteNames: [...buffers.keys()] };\n}\n\n// ---------------------------------------------------------------------------\n// soundfontToPreset — pure converter function\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a list of note names (with optional loop data) to SmplrPreset.\n * Uses spreadKeyRanges so notes between recorded pitches pitch-shift correctly.\n */\nexport function soundfontToPreset(\n noteNames: string[],\n loopData?: LoopData,\n): SmplrPreset {\n const entries: [number, string][] = [];\n\n for (const noteName of noteNames) {\n const midi = toMidi(noteName);\n if (midi === undefined) continue;\n entries.push([midi, noteName]);\n }\n\n const spread = spreadKeyRanges(entries);\n\n const regions: SmplrGroup[\"regions\"] = spread.map(\n ({ keyRange, pitch, sample }) => {\n const region: SmplrGroup[\"regions\"][number] = { sample, keyRange, pitch };\n\n // Apply loop data if available\n if (loopData) {\n const loop = loopData[pitch];\n if (loop) {\n region.loop = true;\n region.loopStart = loop[0];\n region.loopEnd = loop[1];\n }\n }\n\n return region;\n },\n );\n\n return {\n // baseUrl doesn't matter — all buffers are pre-loaded\n samples: { baseUrl: \"\", formats: [\"ogg\"] },\n groups: [{ regions }],\n };\n}\n\n// ---------------------------------------------------------------------------\n// getSoundfontConfig\n// ---------------------------------------------------------------------------\n\nfunction getSoundfontConfig(options: SoundfontOptions): SoundfontConfig {\n if (!options.instrument && !options.instrumentUrl) {\n throw Error(\"Soundfont: instrument or instrumentUrl is required\");\n }\n const config = {\n kit: options.kit ?? DEFAULT_SOUNDFONT_KIT,\n instrument: options.instrument,\n storage: options.storage ?? HttpStorage,\n extraGain: options.extraGain ?? 5,\n loadLoopData: options.loadLoopData ?? false,\n loopDataUrl: options.loopDataUrl,\n instrumentUrl: options.instrumentUrl ?? \"\",\n };\n\n if (config.instrument && config.instrument.startsWith(\"http\")) {\n console.warn(\n \"Use 'instrumentUrl' instead of 'instrument' to load from a URL\",\n );\n config.instrumentUrl = config.instrument;\n config.instrument = undefined;\n }\n\n if (!config.instrumentUrl) {\n if (config.instrument) {\n config.instrumentUrl = gleitzKitUrl(config.instrument, config.kit);\n } else {\n throw Error(\n \"Soundfont: 'instrument' or 'instrumentUrl' configuration parameter is required\",\n );\n }\n } else {\n if (config.kit !== DEFAULT_SOUNDFONT_KIT || config.instrument) {\n console.warn(\n \"Soundfont: 'kit' and 'instrument' config parameters are ignored because 'instrumentUrl' is explicitly set.\",\n );\n }\n }\n\n if (config.loadLoopData && config.instrument && !config.loopDataUrl) {\n config.loopDataUrl = getGoldstSoundfontLoopsUrl(\n config.instrument,\n config.kit,\n );\n }\n\n return config;\n}\n\n// ---------------------------------------------------------------------------\n// Base64 / MIDI.js helpers\n// ---------------------------------------------------------------------------\n\nfunction midiJsToJson(source: string): Record<string, string> {\n const header = source.indexOf(\"MIDI.Soundfont.\");\n if (header < 0) throw Error(\"Invalid MIDI.js Soundfont format\");\n const start = source.indexOf(\"=\", header) + 2;\n const end = source.lastIndexOf(\",\");\n return JSON.parse(source.slice(start, end) + \"}\");\n}\n\nfunction removeBase64Prefix(audioBase64: string) {\n return audioBase64.slice(audioBase64.indexOf(\",\") + 1);\n}\n\nfunction base64ToArrayBuffer(base64: string) {\n const decoded = window.atob(base64);\n const len = decoded.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = decoded.charCodeAt(i);\n }\n return bytes.buffer;\n}\n","import { Instrument } from \"./smplr\";\nimport { SmplrGroup, SmplrPreset } from \"./smplr/types\";\n\ntype Sf2 = {\n instruments: Sf2Instrument[];\n};\n\ntype Sf2Instrument = {\n header: {\n name: string;\n };\n zones: Sf2Zone[];\n};\n\ntype Sf2Zone = {\n sample: Sf2Sample;\n keyRange?: { lo: number; hi: number };\n};\n\ntype Sf2Sample = {\n data: Int16Array;\n header: {\n name: string;\n sampleRate: number;\n originalPitch: number;\n pitchCorrection: number;\n start: number;\n end: number;\n startLoop: number;\n endLoop: number;\n };\n};\n\nexport type Soundfont2Options = {\n url: string;\n createSoundfont: (data: Uint8Array) => Sf2;\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n};\n\nexport function sf2InstrumentToPreset(\n sf2Instrument: Sf2Instrument,\n context: BaseAudioContext,\n): { json: SmplrPreset; buffers: Map<string, AudioBuffer> } {\n const buffers = new Map<string, AudioBuffer>();\n const regions: SmplrGroup[\"regions\"] = [];\n\n for (const zone of sf2Instrument.zones) {\n const { sample, keyRange } = zone;\n const { header } = sample;\n const sampleName = header.name;\n\n const float32 = new Float32Array(sample.data.length);\n for (let i = 0; i < sample.data.length; i++)\n float32[i] = sample.data[i] / 32768;\n const audioBuffer = context.createBuffer(\n 1,\n float32.length,\n header.sampleRate,\n );\n audioBuffer.getChannelData(0).set(float32);\n buffers.set(sampleName, audioBuffer);\n\n const hasLoop = header.startLoop >= 0 && header.endLoop > header.startLoop;\n\n regions.push({\n sample: sampleName,\n pitch: header.originalPitch,\n ...(keyRange && {\n keyRange: [keyRange.lo, keyRange.hi] as [number, number],\n }),\n ...(hasLoop && {\n loop: true,\n loopStart: header.startLoop / header.sampleRate,\n loopEnd: header.endLoop / header.sampleRate,\n }),\n });\n }\n\n return {\n json: { samples: { baseUrl: \"\", formats: [] }, groups: [{ regions }] },\n buffers,\n };\n}\n\ntype Soundfont2SamplerExtras = {\n readonly instrumentNames: string[];\n loadInstrument(instrumentName: string): Promise<void> | undefined;\n};\n\nexport const Soundfont2 = Instrument(\n (ctx: BaseAudioContext, options: Soundfont2Options, smplr) => {\n // Mutable closure state — extras read these; parse promise populates them.\n let soundfont: Sf2 | undefined = undefined;\n let instrumentNamesList: string[] = [];\n\n // Capture the base `loadInstrument(json, buffers)` *before* the extras\n // below shadow it on the instance — otherwise the call inside the\n // override would recurse into itself with the wrong arity.\n const baseLoadInstrument = smplr.loadInstrument.bind(smplr);\n\n const extras: Soundfont2SamplerExtras = {\n get instrumentNames(): string[] {\n return instrumentNamesList;\n },\n loadInstrument(instrumentName) {\n const sf2inst = soundfont?.instruments.find(\n (inst: Sf2Instrument) => inst.header.name === instrumentName,\n );\n if (!sf2inst) return undefined;\n const { json, buffers } = sf2InstrumentToPreset(sf2inst, ctx);\n return baseLoadInstrument(json, buffers);\n },\n };\n\n const ready = loadSoundfont(options).then((sf2) => {\n soundfont = sf2;\n instrumentNamesList = sf2.instruments.map(\n (inst: Sf2Instrument) => inst.header.name,\n );\n });\n\n return { extras, ready };\n },\n);\n\n/** Instance type returned by the {@link Soundfont2} factory. */\nexport type Soundfont2 = ReturnType<typeof Soundfont2>;\n\n/** @deprecated Use `Soundfont2` instead. */\nexport const Soundfont2Sampler = Soundfont2;\n/** @deprecated Use `Soundfont2` instead. */\nexport type Soundfont2Sampler = Soundfont2;\n\nasync function loadSoundfont(options: Soundfont2Options) {\n const buffer = await fetch(options.url).then((res) => res.arrayBuffer());\n const data = new Uint8Array(buffer);\n return options.createSoundfont(data);\n}\n","import { HttpStorage, Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress, SmplrGroup, SmplrPreset } from \"./smplr/types\";\nimport { spreadKeyRanges } from \"./smplr/utils\";\n\n/**\n * Configuration options for SplendidGrandPiano.\n */\nexport type SplendidGrandPianoConfig = {\n baseUrl: string;\n storage: Storage;\n /** Global detune in cents, applied to all notes. */\n detune: number;\n /** Default velocity (0–127) when not specified per note. */\n velocity: number;\n /** Release time in seconds. Maps to SmplrPreset defaults.ampRelease. */\n decayTime: number;\n /** Destination audio node. Defaults to context.destination. */\n destination?: AudioNode;\n /** Master volume (0–127 MIDI scale). */\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n /** Called after each buffer is loaded or served from cache. */\n onLoadProgress?: (progress: LoadProgress) => void;\n /** Audio formats to try, in order of preference. Defaults to [\"ogg\", \"m4a\"]. */\n formats?: string[];\n /** Limit which notes are fetched. Useful for reducing initial load time. */\n notesToLoad?: {\n notes: number[];\n velocityRange: [number, number];\n };\n};\n\nconst BASE_URL =\n \"https://smpldsnds.github.io/sfzinstruments-splendid-grand-piano/samples\";\n\nconst DEFAULTS: SplendidGrandPianoConfig = {\n baseUrl: BASE_URL,\n storage: HttpStorage,\n detune: 0,\n volume: 100,\n velocity: 100,\n decayTime: 0.5,\n};\n\nexport const SplendidGrandPiano = Instrument(\n (\n ctx: BaseAudioContext,\n options: Partial<SplendidGrandPianoConfig> = {},\n smplr,\n ) => smplr.loadInstrument(pianoToPreset({ ...DEFAULTS, ...options })),\n);\n\n/** Instance type returned by the {@link SplendidGrandPiano} factory. */\nexport type SplendidGrandPiano = ReturnType<typeof SplendidGrandPiano>;\n\n// ---------------------------------------------------------------------------\n// pianoToPreset — pure function, independently testable\n// ---------------------------------------------------------------------------\n\ntype PianoJsonOptions = Pick<\n SplendidGrandPianoConfig,\n \"baseUrl\" | \"detune\" | \"decayTime\" | \"notesToLoad\" | \"formats\"\n>;\n\n/**\n * Convert the LAYERS array and user options into a SmplrPreset descriptor.\n *\n * Each layer becomes a SmplrGroup with its velRange. If `notesToLoad` is\n * specified, layers and samples are filtered accordingly. The PPP layer\n * includes a low-pass filter cutoff.\n *\n * `spreadKeyRanges` is used to pre-compute which key range each sample\n * covers, replacing the old on-the-fly `findNearestMidiInLayer` logic.\n */\nexport function pianoToPreset(options: PianoJsonOptions): SmplrPreset {\n const { notesToLoad } = options;\n\n // Filter layers by requested velocity range\n const layers = notesToLoad\n ? LAYERS.filter(\n (layer) =>\n layer.vel_range[0] <= notesToLoad.velocityRange[1] &&\n layer.vel_range[1] >= notesToLoad.velocityRange[0],\n )\n : LAYERS;\n\n const groups: SmplrGroup[] = layers.map((layer) => {\n // Filter samples by requested MIDI notes\n const samples = (\n notesToLoad\n ? layer.samples.filter(([midi]) =>\n notesToLoad.notes.includes(midi as number),\n )\n : layer.samples\n ) as [number, string][];\n\n const regions = spreadKeyRanges(samples).map(\n ({ keyRange, pitch, sample }) => ({\n keyRange,\n pitch,\n sample,\n }),\n );\n\n const group: SmplrGroup = {\n velRange: layer.vel_range as [number, number],\n regions,\n };\n\n if (\"cutoff\" in layer && layer.cutoff !== undefined) {\n group.lpfCutoffHz = layer.cutoff as number;\n }\n\n return group;\n });\n\n return {\n samples: {\n baseUrl: options.baseUrl,\n formats: options.formats ?? [\"ogg\", \"m4a\"],\n },\n defaults: {\n ampRelease: options.decayTime,\n detune: options.detune,\n },\n groups,\n };\n}\n\n// ---------------------------------------------------------------------------\n// LAYERS — piano sample data\n// ---------------------------------------------------------------------------\n\nexport const LAYERS = [\n {\n name: \"PPP\",\n vel_range: [1, 40],\n cutoff: 1000,\n samples: [\n [23, \"PP B-1\"],\n [27, \"PP D#0\"],\n [29, \"PP F0\"],\n [31, \"PP G0\"],\n [33, \"PP A0\"],\n [35, \"PP B0\"],\n [37, \"PP C#1\"],\n [38, \"PP D1\"],\n [40, \"PP E1\"],\n [41, \"PP F1\"],\n [43, \"PP G1\"],\n [45, \"PP A1\"],\n [47, \"PP B1\"],\n [48, \"PP C2\"],\n [50, \"PP D2\"],\n [52, \"PP E2\"],\n [53, \"PP F2\"],\n [55, \"PP G2\"],\n [56, \"PP G#2\"],\n [57, \"PP A2\"],\n [58, \"PP A#2\"],\n [59, \"PP B2\"],\n [60, \"PP C3\"],\n [62, \"PP D3\"],\n [64, \"PP E3\"],\n [65, \"PP F3\"],\n [67, \"PP G3\"],\n [69, \"PP A3\"],\n [71, \"PP B3\"],\n [72, \"PP C4\"],\n [74, \"PP D4\"],\n [76, \"PP E4\"],\n [77, \"PP F4\"],\n [79, \"PP G4\"],\n [80, \"PP G#4\"],\n [81, \"PP A4\"],\n [82, \"PP A#4\"],\n [83, \"PP B4\"],\n [85, \"PP C#5\"],\n [86, \"PP D5\"],\n [87, \"PP D#5\"],\n [89, \"PP F5\"],\n [90, \"PP F#5\"],\n [91, \"PP G5\"],\n [92, \"PP G#5\"],\n [93, \"PP A5\"],\n [94, \"PP A#5\"],\n [95, \"PP B5\"],\n [96, \"PP C6\"],\n [97, \"PP C#6\"],\n [98, \"PP D6\"],\n [99, \"PP D#6\"],\n [100, \"PP E6\"],\n [101, \"PP F6\"],\n [102, \"PP F#6\"],\n [103, \"PP G6\"],\n [104, \"PP G#6\"],\n [105, \"PP A6\"],\n [106, \"PP A#6\"],\n [107, \"PP B6\"],\n [108, \"PP C7\"],\n ],\n },\n {\n name: \"PP\",\n vel_range: [41, 67],\n samples: [\n [23, \"PP B-1\"],\n [27, \"PP D#0\"],\n [29, \"PP F0\"],\n [31, \"PP G0\"],\n [33, \"PP A0\"],\n [35, \"PP B0\"],\n [37, \"PP C#1\"],\n [38, \"PP D1\"],\n [40, \"PP E1\"],\n [41, \"PP F1\"],\n [43, \"PP G1\"],\n [45, \"PP A1\"],\n [47, \"PP B1\"],\n [48, \"PP C2\"],\n [50, \"PP D2\"],\n [52, \"PP E2\"],\n [53, \"PP F2\"],\n [55, \"PP G2\"],\n [56, \"PP G#2\"],\n [57, \"PP A2\"],\n [58, \"PP A#2\"],\n [59, \"PP B2\"],\n [60, \"PP C3\"],\n [62, \"PP D3\"],\n [64, \"PP E3\"],\n [65, \"PP F3\"],\n [67, \"PP G3\"],\n [69, \"PP A3\"],\n [71, \"PP B3\"],\n [72, \"PP C4\"],\n [74, \"PP D4\"],\n [76, \"PP E4\"],\n [77, \"PP F4\"],\n [79, \"PP G4\"],\n [80, \"PP G#4\"],\n [81, \"PP A4\"],\n [82, \"PP A#4\"],\n [83, \"PP B4\"],\n [85, \"PP C#5\"],\n [86, \"PP D5\"],\n [87, \"PP D#5\"],\n [89, \"PP F5\"],\n [90, \"PP F#5\"],\n [91, \"PP G5\"],\n [92, \"PP G#5\"],\n [93, \"PP A5\"],\n [94, \"PP A#5\"],\n [95, \"PP B5\"],\n [96, \"PP C6\"],\n [97, \"PP C#6\"],\n [98, \"PP D6\"],\n [99, \"PP D#6\"],\n [100, \"PP E6\"],\n [101, \"PP F6\"],\n [102, \"PP F#6\"],\n [103, \"PP G6\"],\n [104, \"PP G#6\"],\n [105, \"PP A6\"],\n [106, \"PP A#6\"],\n [107, \"PP B6\"],\n [108, \"PP C7\"],\n ],\n },\n {\n name: \"MP\",\n vel_range: [68, 84],\n samples: [\n [23, \"Mp B-1\"],\n [27, \"Mp D#0\"],\n [29, \"Mp F0\"],\n [31, \"Mp G0\"],\n [33, \"Mp A0\"],\n [35, \"Mp B0\"],\n [37, \"Mp C#1\"],\n [38, \"Mp D1\"],\n [40, \"Mp E1\"],\n [41, \"Mp F1\"],\n [43, \"Mp G1\"],\n [45, \"Mp A1\"],\n [47, \"Mp B1\"],\n [48, \"Mp C2\"],\n [50, \"Mp D2\"],\n [52, \"Mp E2\"],\n [53, \"Mp F2\"],\n [55, \"Mp G2\"],\n [56, \"Mp G#2\"],\n [57, \"Mp A2\"],\n [58, \"Mp A#2\"],\n [59, \"Mp B2\"],\n [60, \"Mp C3\"],\n [62, \"Mp D3\"],\n [64, \"Mp E3\"],\n [65, \"Mp F3\"],\n [67, \"Mp G3\"],\n [69, \"Mp A3\"],\n [71, \"Mp B3\"],\n [72, \"Mp C4\"],\n [74, \"Mp D4\"],\n [76, \"Mp E4\"],\n [77, \"Mp F4\"],\n [79, \"Mp G4\"],\n [80, \"Mp G#4\"],\n [81, \"Mp A4\"],\n [82, \"Mp A#4\"],\n [83, \"Mp B4\"],\n [85, \"Mp C#5\"],\n [86, \"Mp D5\"],\n [87, \"Mp D#5\"],\n [88, \"Mp E5\"],\n [89, \"Mp F5\"],\n [90, \"Mp F#5\"],\n [91, \"Mp G5\"],\n [92, \"Mp G#5\"],\n [93, \"Mp A5\"],\n [94, \"Mp A#5\"],\n [95, \"Mp B5\"],\n [96, \"Mp C6\"],\n [97, \"Mp C#6\"],\n [98, \"Mp D6\"],\n [99, \"Mp D#6\"],\n [100, \"PP E6\"],\n [101, \"Mp F6\"],\n [102, \"Mp F#6\"],\n [103, \"Mp G6\"],\n [104, \"Mp G#6\"],\n [105, \"Mp A6\"],\n [106, \"Mp A#6\"],\n [107, \"PP B6\"],\n [108, \"PP C7\"],\n ],\n },\n {\n name: \"MF\",\n vel_range: [85, 100],\n samples: [\n [23, \"Mf B-1\"],\n [27, \"Mf D#0\"],\n [29, \"Mf F0\"],\n [31, \"Mf G0\"],\n [33, \"Mf A0\"],\n [35, \"Mf B0\"],\n [37, \"MF C#1\"],\n [38, \"MF D1\"],\n [40, \"MF E1\"],\n [41, \"MF F1\"],\n [43, \"MF G1\"],\n [45, \"MF A1\"],\n [47, \"MF B1\"],\n [48, \"MF C2\"],\n [50, \"MF D2\"],\n [52, \"MF E2\"],\n [53, \"MF F2\"],\n [55, \"MF G2\"],\n [56, \"MF G#2\"],\n [57, \"MF A2\"],\n [58, \"MF A#2\"],\n [59, \"MF B2\"],\n [60, \"MF C3\"],\n [62, \"MF D3\"],\n [64, \"MF E3\"],\n [65, \"MF F3\"],\n [67, \"MF G3\"],\n [69, \"MF A3\"],\n [71, \"MF B3\"],\n [72, \"MF C4\"],\n [74, \"Mf D4\"],\n [76, \"Mf E4\"],\n [77, \"Mf F4\"],\n [79, \"Mf G4\"],\n [80, \"Mf G#4\"],\n [81, \"Mf A4\"],\n [82, \"Mf A#4\"],\n [83, \"Mf B4\"],\n [85, \"Mf C#5\"],\n [86, \"Mf D5\"],\n [87, \"Mf D#5\"],\n [88, \"Mf E5\"],\n [89, \"Mf F5\"],\n [90, \"Mf F#5\"],\n [91, \"Mf G5\"],\n [92, \"Mf G#5\"],\n [93, \"Mf A5\"],\n [94, \"Mf A#5\"],\n [95, \"Mf B5\"],\n [96, \"Mf C6\"],\n [97, \"Mf C#6\"],\n [98, \"Mf D6\"],\n [99, \"Mf D#6\"],\n [100, \"Mf E6\"],\n [101, \"Mf F6\"],\n [102, \"Mf F#6\"],\n [103, \"Mf G6\"],\n [104, \"Mf G#6\"],\n [105, \"Mf A6\"],\n [106, \"Mf A#6\"],\n [107, \"Mf B6\"],\n [108, \"PP C7\"],\n ],\n },\n {\n name: \"FF\",\n vel_range: [101, 127],\n samples: [\n [23, \"FF B-1\"],\n [27, \"FF D#0\"],\n [29, \"FF F0\"],\n [31, \"FF G0\"],\n [33, \"FF A0\"],\n [35, \"FF B0\"],\n [37, \"FF C#1\"],\n [38, \"FF D1\"],\n [40, \"FF E1\"],\n [41, \"FF F1\"],\n [43, \"FF G1\"],\n [45, \"FF A1\"],\n [47, \"FF B1\"],\n [48, \"FF C2\"],\n [50, \"FF D2\"],\n [52, \"FF E2\"],\n [53, \"FF F2\"],\n [55, \"FF G2\"],\n [56, \"FF G#2\"],\n [57, \"FF A2\"],\n [58, \"FF A#2\"],\n [59, \"FF B2\"],\n [60, \"FF C3\"],\n [62, \"FF D3\"],\n [64, \"FF E3\"],\n [65, \"FF F3\"],\n [67, \"FF G3\"],\n [69, \"FF A3\"],\n [71, \"FF B3\"],\n [72, \"FF C4\"],\n [74, \"FF D4\"],\n [76, \"FF E4\"],\n [77, \"FF F4\"],\n [79, \"FF G4\"],\n [80, \"FF G#4\"],\n [81, \"FF A4\"],\n [82, \"FF A#4\"],\n [83, \"FF B4\"],\n [85, \"FF C#5\"],\n [86, \"FF D5\"],\n [88, \"FF E5\"],\n [89, \"FF F5\"],\n [91, \"FF G5\"],\n [93, \"FF A5\"],\n [95, \"Mf B5\"],\n [96, \"Mf C6\"],\n [97, \"Mf C#6\"],\n [98, \"Mf D6\"],\n [99, \"Mf D#6\"],\n [100, \"Mf E6\"],\n [102, \"Mf F#6\"],\n [103, \"Mf G6\"],\n [104, \"Mf G#6\"],\n [105, \"Mf A6\"],\n [106, \"Mf A#6\"],\n [107, \"Mf B6\"],\n [108, \"Mf C7\"],\n ],\n },\n];\n"],"mappings":"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AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,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AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACxIO,SAAS,2BAA2B,YAAoB,KAAa;AAC1E,MAAI,WAAW,WAAW,MAA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AAA,MACP,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;A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","names":["volume","send","canPlay","_cache","_a","_b","_context","_context","_voices","_a","midi","_a","str","depth","INSTRUMENTS","sampleBaseUrl"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/smplr/as-constructable.ts","../src/storage.ts","../src/smplr/connect.ts","../src/smplr/signals.ts","../src/smplr/volume.ts","../src/smplr/channel.ts","../src/smplr/midi.ts","../src/smplr/params.ts","../src/smplr/region-matcher.ts","../src/smplr/load-audio.ts","../src/smplr/sample-loader.ts","../src/smplr/sorted-queue.ts","../src/smplr/scheduler.ts","../src/smplr/voice.ts","../src/smplr/voice-manager.ts","../src/smplr/smplr.ts","../src/smplr/instrument.ts","../src/drum-machine/dm-instrument.ts","../src/drum-machine/drum-machine.ts","../src/drum-abuse/index.ts","../src/offline/wav-encoder.ts","../src/offline/render-result.ts","../src/offline/trim-silence.ts","../src/offline/render-offline.ts","../src/sequencer/time-parser.ts","../src/sequencer/transport-clock.ts","../src/sequencer/sequencer.ts","../src/smplr/sfz-convert.ts","../src/tremolo.ts","../src/electric-piano.ts","../src/versilian.ts","../src/mallet.ts","../src/smplr/utils.ts","../src/mellotron.ts","../src/reverb/processor.min.ts","../src/reverb/reverb.ts","../src/sampler.ts","../src/smolken.ts","../src/soundfont/soundfont-instrument.ts","../src/soundfont/soundfont-loops.ts","../src/soundfont/soundfont.ts","../src/soundfont2.ts","../src/splendid-grand-piano.ts"],"sourcesContent":["export * from \"./drum-machine/drum-machine\";\nexport * from \"./drum-abuse\";\nexport * from \"./offline\";\nexport * from \"./smplr\";\nexport * from \"./sequencer\";\nexport * from \"./electric-piano\";\nexport * from \"./mallet\";\nexport * from \"./mellotron\";\nexport * from \"./reverb/reverb\";\nexport * from \"./sampler\";\nexport * from \"./smolken\";\nexport * from \"./soundfont/soundfont\";\nexport * from \"./soundfont2\";\nexport * from \"./splendid-grand-piano\";\nexport * from \"./storage\";\nexport * from \"./versilian\";\n","/**\n * Wrap a class so it is callable both as `X(...)` (preferred) and as\n * `new X(...)` (kept for compatibility with pre-1.0 examples). Returns\n * a value with both call and construct signatures.\n *\n * Used by the auxiliary exports (`Sequencer`, `Reverb`, `CacheStorage`,\n * `Scheduler`, `SampleLoader`) to match the dual signature already shipped\n * by `InstrumentFactory`. Instrument factories themselves use the richer\n * `Instrument()` builder instead, which owns option-splitting and the\n * ready-promise lifecycle.\n */\nexport type Constructable<A extends unknown[], R> = {\n (...args: A): R;\n /** @deprecated Call as a function: `X(...)` instead of `new X(...)`. */\n new (...args: A): R;\n};\n\nexport function asConstructable<A extends unknown[], R>(\n Klass: new (...args: A) => R,\n): Constructable<A, R> {\n // Must be a regular function declaration (not an arrow): arrow functions\n // are not constructible, so `new asConstructable(X)()` would throw.\n // When invoked via `new`, the function returns an object, which the JS\n // spec uses in place of the freshly-allocated `this`.\n function factory(...args: A): R {\n return new Klass(...args);\n }\n return factory as unknown as Constructable<A, R>;\n}\n","import { asConstructable } from \"./smplr/as-constructable\";\n\nexport type StorageResponse = {\n readonly status: number;\n arrayBuffer(): Promise<ArrayBuffer>;\n json(): Promise<any>;\n text(): Promise<string>;\n};\n\nexport type Storage = {\n fetch: (url: string) => Promise<StorageResponse>;\n};\n\nexport const HttpStorage: Storage = {\n fetch(url) {\n return fetch(url);\n },\n};\n\nclass CacheStorageImpl implements Storage {\n #cache: Promise<Cache>;\n\n constructor(name = \"smplr\") {\n if (typeof window === \"undefined\" || !(\"caches\" in window)) {\n this.#cache = Promise.reject(\"CacheStorage not supported\");\n // Attach a no-op handler so node doesn't surface this as an unhandled\n // rejection in environments where `fetch()` is never called.\n this.#cache.catch(() => {});\n } else {\n this.#cache = caches.open(name);\n }\n }\n\n async fetch(url: string): Promise<StorageResponse> {\n const request = new Request(url);\n try {\n return await this.#tryFromCache(request);\n } catch (err) {\n const response = await fetch(request);\n await this.#saveResponse(request, response);\n return response;\n }\n }\n\n async #tryFromCache(request: Request): Promise<StorageResponse> {\n const cache = await this.#cache;\n const response = await cache.match(request);\n if (response) return response;\n else throw Error(\"Not found\");\n }\n\n async #saveResponse(request: Request, response: Response) {\n try {\n const cache = await this.#cache;\n await cache.put(request, response.clone());\n } catch (err) {}\n }\n}\n\nexport const CacheStorage = asConstructable(CacheStorageImpl);\nexport type CacheStorage = ReturnType<typeof CacheStorage>;\n","export type AudioInsert = {\n input: AudioNode;\n output: AudioNode;\n};\n\nexport function connectSerial(nodes: (AudioNode | AudioInsert | undefined)[]) {\n const _nodes = nodes.filter((x): x is AudioNode | AudioInsert => !!x);\n _nodes.reduce((a, b) => {\n const left = \"output\" in a ? a.output : a;\n const right = \"input\" in b ? b.input : b;\n left.connect(right);\n return b;\n });\n\n return () => {\n _nodes.reduce((a, b) => {\n const left = \"output\" in a ? a.output : a;\n const right = \"input\" in b ? b.input : b;\n left.disconnect(right);\n return b;\n });\n };\n}\n\nexport function connectAudioBus(\n node: AudioNode,\n destination: AudioNode,\n gain: number,\n) {\n const mix = node.context.createGain();\n mix.gain.value = gain;\n node.connect(mix);\n mix.connect(destination);\n\n return () => {\n node.disconnect(mix);\n mix.disconnect(destination);\n };\n}\n","/**\n * A function to unsubscribe from an event or control\n */\nexport type Unsubscribe = () => void;\n/**\n * A function that listener to event or control changes\n */\nexport type Listener<T> = (value: T) => void;\n/**\n * A function to subscribe an trigger or control events\n */\nexport type Subscribe<T> = (listener: Listener<T>) => Unsubscribe;\n\n/**\n * A trigger is a subscribable event\n */\nexport type Trigger<T> = {\n subscribe: Subscribe<T>;\n trigger: (event: T) => void;\n};\n\n/**\n * A control is a subscribable value\n */\nexport type Control<T> = {\n subscribe: Subscribe<T>;\n set: (value: T) => void;\n get: () => T;\n};\n\n/**\n * Create a control signal\n * @param initialValue\n * @returns Control\n */\nexport function createControl<T>(initialValue: T): Control<T> {\n let current = initialValue;\n const listeners = new Set<Listener<T>>();\n\n function subscribe(listener: Listener<T>) {\n listeners.add(listener);\n listener(current);\n return () => {\n listeners.delete(listener);\n };\n }\n\n function set(value: T) {\n current = value;\n listeners.forEach((listener) => listener(current));\n }\n\n function get(): T {\n return current;\n }\n return { subscribe, set, get };\n}\n\nexport function createTrigger<T>(): Trigger<T> {\n const listeners = new Set<Listener<T>>();\n\n function subscribe(listener: Listener<T>) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n }\n\n function trigger(value: T) {\n listeners.forEach((listener) => listener(value));\n }\n\n return { subscribe, trigger };\n}\n\nexport function unsubscribeAll(unsubscribe: Array<Unsubscribe | undefined>) {\n let done = false;\n return () => {\n if (done) return;\n done = true;\n unsubscribe.forEach((cb) => cb?.());\n };\n}\n","/// This is how the MIDI association converts midi velocity [0..127] into gain [0..1]\n/// @see https://www.midi.org/specifications/file-format-specifications/dls-downloadable-sounds/dls-level-1\nexport function midiVelToGain(vel: number) {\n return (vel * vel) / 16129; // 16129 = 127 * 127\n}\n\nexport function dbToGain(decibels: number) {\n return Math.pow(10, decibels / 20);\n}\n","import { AudioInsert, connectSerial } from \"./connect\";\nimport { Control, createControl } from \"./signals\";\nimport { midiVelToGain } from \"./volume\";\n\nexport type ChannelConfig = {\n destination: AudioNode;\n volume: number;\n volumeToGain: (volume: number) => number;\n pan?: number;\n};\n\nexport type OutputChannel = Omit<Channel, \"input\">;\n\ntype Send = {\n name: string;\n mix: GainNode;\n disconnect: () => void;\n};\n\n/**\n * An output channel with audio effects\n * @private\n */\nexport class Channel {\n /** @deprecated Use `output.volume = n` instead. */\n public readonly setVolume: (vol: number) => void;\n public readonly input: AudioNode;\n\n #volume: GainNode;\n #panner: StereoPannerNode;\n #sends?: Send[];\n #inserts?: (AudioNode | AudioInsert)[];\n #disconnect: () => void;\n #unsubscribe: () => void;\n #config: Readonly<ChannelConfig>;\n #volumeControl: Control<number>;\n #disconnected = false;\n\n constructor(\n public readonly context: BaseAudioContext,\n options?: Partial<ChannelConfig>,\n ) {\n this.#config = {\n destination: options?.destination ?? context.destination,\n volume: options?.volume ?? 100,\n volumeToGain: options?.volumeToGain ?? midiVelToGain,\n pan: options?.pan ?? 0,\n };\n\n this.input = context.createGain();\n this.#volume = context.createGain();\n this.#panner = context.createStereoPanner();\n this.#panner.pan.value = this.#config.pan!;\n\n this.#disconnect = connectSerial([\n this.input,\n this.#volume,\n this.#panner,\n this.#config.destination,\n ]);\n\n const volume = createControl(this.#config.volume);\n this.#volumeControl = volume;\n this.setVolume = volume.set;\n this.#unsubscribe = volume.subscribe((volume) => {\n this.#volume.gain.value = this.#config.volumeToGain(volume);\n });\n }\n\n get volume(): number {\n return this.#volumeControl.get();\n }\n\n set volume(value: number) {\n this.#volumeControl.set(value);\n }\n\n get pan(): number {\n return this.#panner.pan.value;\n }\n\n set pan(value: number) {\n this.#panner.pan.value = value;\n }\n\n addInsert(effect: AudioNode | AudioInsert) {\n if (this.#disconnected) {\n throw Error(\"Can't add insert to disconnected channel\");\n }\n this.#inserts ??= [];\n this.#inserts.push(effect);\n this.#disconnect();\n this.#disconnect = connectSerial([\n this.input,\n ...this.#inserts,\n this.#volume,\n this.#panner,\n this.#config.destination,\n ]);\n }\n\n addEffect(\n name: string,\n effect: AudioNode | { input: AudioNode },\n mixValue: number,\n ) {\n if (this.#disconnected) {\n throw Error(\"Can't add effect to disconnected channel\");\n }\n const mix = this.context.createGain();\n mix.gain.value = mixValue;\n const input = \"input\" in effect ? effect.input : effect;\n const disconnect = connectSerial([this.#volume, mix, input]);\n\n this.#sends ??= [];\n this.#sends.push({ name, mix, disconnect });\n }\n\n setEffectMix(name: string, mix: number) {\n if (this.#disconnected) {\n throw Error(\"Can't send effect to disconnected channel\");\n }\n\n const send = this.#sends?.find((send) => send.name === name);\n if (send) {\n send.mix.gain.value = mix;\n } else {\n console.warn(\"Send bus not found: \" + name);\n }\n }\n\n /** @deprecated Use `setEffectMix(name, mix)` instead. */\n sendEffect(name: string, mix: number) {\n this.setEffectMix(name, mix);\n }\n\n disconnect() {\n if (this.#disconnected) return;\n this.#disconnected = true;\n this.#disconnect();\n this.#unsubscribe();\n this.#sends?.forEach((send) => send.disconnect());\n this.#sends = undefined;\n }\n}\n","function noteNameToMidi(note: string): number | undefined {\n const REGEX = /^([a-gA-G]?)(#{1,}|b{1,}|)(-?\\d+)$/;\n const m = REGEX.exec(note);\n if (!m) return;\n const letter = m[1].toUpperCase();\n if (!letter) return;\n\n const acc = m[2];\n const alt = acc[0] === \"b\" ? -acc.length : acc.length;\n const oct = m[3] ? +m[3] : 4;\n\n const step = (letter.charCodeAt(0) + 3) % 7;\n return [0, 2, 4, 5, 7, 9, 11][step] + alt + 12 * (oct + 1);\n}\n\n/** @internal Not part of the public 1.0 API surface. */\nexport function toMidi(note: string | number | undefined): number | undefined {\n return note === undefined\n ? undefined\n : typeof note === \"number\"\n ? note\n : noteNameToMidi(note);\n}\n\n/** @internal Not part of the public 1.0 API surface. */\nexport function findNearestMidi(\n midi: number,\n isAvailable: Record<string | number, unknown>,\n): [number, number] {\n let i = 0;\n while (isAvailable[midi + i] === undefined && i < 128) {\n if (i > 0) i = -i;\n else i = -i + 1;\n }\n\n return i === 127 ? [midi, 0] : [midi + i, -i * 100];\n}\n","import { PlaybackParams, SmplrGroup, SmplrRegion, VoiceParams } from \"./types\";\n\n/**\n * Hardcoded defaults — the baseline when nothing else is specified.\n */\nexport const PARAM_DEFAULTS: Required<PlaybackParams> = {\n volume: 0,\n tune: 0,\n detune: 0,\n ampRelease: 0.3,\n ampAttack: 0,\n lpfCutoffHz: 20000,\n offset: 0,\n loop: false,\n loopStart: 0,\n loopEnd: 0,\n reverse: false,\n};\n\nconst PLAYBACK_KEYS = Object.keys(PARAM_DEFAULTS) as (keyof PlaybackParams)[];\n\n/**\n * Extract only PlaybackParams fields from a group or region object,\n * ignoring structural fields like keyRange, velRange, regions, etc.\n */\nfunction pickPlaybackParams(obj: PlaybackParams): PlaybackParams {\n const result: PlaybackParams = {};\n for (const key of PLAYBACK_KEYS) {\n const value = obj[key];\n if (value !== undefined) (result as Record<string, unknown>)[key] = value;\n }\n return result;\n}\n\n/**\n * Per-note overrides that can be passed via NoteEvent at play time.\n */\nexport type NoteOverrides = {\n detune?: number;\n lpfCutoffHz?: number;\n loop?: boolean;\n ampRelease?: number;\n reverse?: boolean;\n};\n\n/**\n * Resolve the final VoiceParams for one matched region by merging four levels:\n *\n * PARAM_DEFAULTS → json.defaults → group → region → noteOverrides\n *\n * Detune is computed in cents:\n * (playedMidi - region.pitch + tune) * 100 + detune + noteOverrides.detune\n *\n * @param defaults Global defaults from SmplrPreset.defaults\n * @param group The matched SmplrGroup\n * @param region The matched SmplrRegion\n * @param midi The played MIDI note number\n * @param velocity The played velocity (0-127)\n * @param overrides Per-note overrides from the NoteEvent\n */\nexport function resolveParams(\n defaults: PlaybackParams | undefined,\n group: SmplrGroup,\n region: SmplrRegion,\n midi: number,\n velocity: number,\n overrides?: NoteOverrides,\n): VoiceParams {\n // Merge: hardcoded defaults → json.defaults → group → region\n const merged: Required<PlaybackParams> = {\n ...PARAM_DEFAULTS,\n ...defaults,\n ...pickPlaybackParams(group),\n ...pickPlaybackParams(region),\n };\n\n // Determine sample root pitch:\n // - region.pitch is the authoritative root MIDI note of the sample\n // - if absent, fall back to region.key (which sets both keyRange and pitch)\n // - if neither, assume the sample is tuned to the played note (no pitch shift)\n const pitch = region.pitch ?? region.key ?? midi;\n const semitones = midi - pitch;\n\n // Detune in cents: pitch transpose + tune offset (in semitones) + fine detune (cents)\n let detune = (semitones + merged.tune) * 100 + merged.detune;\n\n // Apply note-level overrides\n if (overrides?.detune !== undefined) detune += overrides.detune;\n\n return {\n detune,\n velocity,\n volume: merged.volume,\n ampRelease: overrides?.ampRelease ?? merged.ampRelease,\n ampAttack: merged.ampAttack,\n lpfCutoffHz: overrides?.lpfCutoffHz ?? merged.lpfCutoffHz,\n offset: merged.offset,\n loop: overrides?.loop ?? merged.loop,\n loopStart: merged.loopStart,\n loopEnd: merged.loopEnd,\n ampVelCurve: region.ampVelCurve,\n loopAuto: region.loopAuto,\n reverse: overrides?.reverse ?? merged.reverse,\n };\n}\n","import { SmplrGroup, SmplrPreset, SmplrRegion } from \"./types\";\n\n/**\n * A region that matched a note event. Carries resolved identity fields and references\n * to the original group/region objects so Smplr can call resolveParams().\n */\nexport type MatchedRegion = {\n sample: string; // buffer key\n pitch: number; // root MIDI pitch of the sample (used for detune calculation)\n group?: number; // exclusive group number (for VoiceManager)\n offBy?: number; // stop voices in this group before playing\n groupRef: SmplrGroup; // original group, passed to resolveParams()\n regionRef: SmplrRegion; // original region, passed to resolveParams()\n};\n\n// ---------------------------------------------------------------------------\n// Pre-processed internal types — built once in the constructor\n// ---------------------------------------------------------------------------\n\ntype ProcessedRegion = {\n keyLow: number;\n keyHigh: number;\n pitch: number | undefined; // undefined → use played MIDI note as pitch\n velLow: number;\n velHigh: number;\n ccRange?: Record<string, [number, number]>;\n seqPosition: number; // 1-based\n group?: number;\n offBy?: number;\n sample: string;\n ref: SmplrRegion;\n};\n\ntype ProcessedGroup = {\n keyLow: number;\n keyHigh: number;\n velLow: number;\n velHigh: number;\n ccRange?: Record<string, [number, number]>;\n seqLength?: number;\n group?: number;\n offBy?: number;\n regions: ProcessedRegion[];\n ref: SmplrGroup;\n};\n\n// ---------------------------------------------------------------------------\n// Pre-processing helpers\n// ---------------------------------------------------------------------------\n\nfunction processRegion(region: SmplrRegion): ProcessedRegion {\n let keyLow: number;\n let keyHigh: number;\n let pitch: number | undefined;\n\n if (region.key !== undefined) {\n // Shorthand: key sets both the trigger range and the root pitch\n keyLow = keyHigh = region.key;\n pitch = region.key;\n } else if (region.keyRange) {\n [keyLow, keyHigh] = region.keyRange;\n pitch = region.pitch; // may be undefined — resolved at match time\n } else {\n // No key constraint — region matches all MIDI notes\n keyLow = 0;\n keyHigh = 127;\n pitch = region.pitch;\n }\n\n return {\n keyLow,\n keyHigh,\n pitch,\n velLow: region.velRange?.[0] ?? 0,\n velHigh: region.velRange?.[1] ?? 127,\n ccRange: region.ccRange,\n seqPosition: region.seqPosition ?? 1,\n group: region.group,\n offBy: region.offBy,\n sample: region.sample,\n ref: region,\n };\n}\n\nfunction processGroup(group: SmplrGroup): ProcessedGroup {\n return {\n keyLow: group.keyRange?.[0] ?? 0,\n keyHigh: group.keyRange?.[1] ?? 127,\n velLow: group.velRange?.[0] ?? 0,\n velHigh: group.velRange?.[1] ?? 127,\n ccRange: group.ccRange,\n seqLength: group.seqLength,\n group: group.group,\n offBy: group.offBy,\n regions: group.regions.map(processRegion),\n ref: group,\n };\n}\n\n// ---------------------------------------------------------------------------\n// CC matching helper\n// ---------------------------------------------------------------------------\n\nfunction matchesCc(\n ccState: Map<number, number>,\n ccRange?: Record<string, [number, number]>,\n): boolean {\n if (!ccRange) return true;\n for (const [ccStr, [low, high]] of Object.entries(ccRange)) {\n const cc = parseInt(ccStr, 10);\n const value = ccState.get(cc) ?? 0; // default: 0 (pedal up, etc.)\n if (value < low || value > high) return false;\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// RegionMatcher\n// ---------------------------------------------------------------------------\n\nexport class RegionMatcher {\n #groups: ProcessedGroup[];\n #seqCounters: Map<number, number>; // groupIndex → call count\n\n constructor(json: SmplrPreset) {\n this.#groups = json.groups.map(processGroup);\n this.#seqCounters = new Map();\n }\n\n /**\n * Match a note event against all groups and regions.\n *\n * For each group that passes key/vel/cc filters:\n * - Check each region's key/vel/cc filters\n * - Apply round-robin seqPosition filter if group.seqLength is set\n * - Advance the per-group round-robin counter (always, when group matched)\n *\n * Returns all matched regions with resolved pitch, group, offBy.\n */\n match(\n midi: number,\n velocity: number,\n ccState: Map<number, number>,\n ): MatchedRegion[] {\n const results: MatchedRegion[] = [];\n\n for (let gi = 0; gi < this.#groups.length; gi++) {\n const group = this.#groups[gi];\n\n // Group-level filters\n if (midi < group.keyLow || midi > group.keyHigh) continue;\n if (velocity < group.velLow || velocity > group.velHigh) continue;\n if (!matchesCc(ccState, group.ccRange)) continue;\n\n const counter = this.#seqCounters.get(gi) ?? 0;\n\n for (const region of group.regions) {\n // Region-level filters\n if (midi < region.keyLow || midi > region.keyHigh) continue;\n if (velocity < region.velLow || velocity > region.velHigh) continue;\n if (!matchesCc(ccState, region.ccRange)) continue;\n\n // Round-robin filter: only allow the region whose seqPosition matches\n // the current counter for this group\n if (group.seqLength !== undefined) {\n const seqPos = region.seqPosition - 1; // to 0-based\n if (counter % group.seqLength !== seqPos) continue;\n }\n\n results.push({\n sample: region.sample,\n // If no pitch is pre-resolved (no key or pitch on region), fall back to\n // the played note so resolveParams computes 0 semitones of transpose\n pitch: region.pitch ?? midi,\n group: region.group ?? group.group,\n offBy: region.offBy ?? group.offBy,\n groupRef: group.ref,\n regionRef: region.ref,\n });\n }\n\n // Advance per-group round-robin counter whenever the group matched,\n // regardless of whether a region's seqPosition filter passed.\n if (group.seqLength !== undefined) {\n this.#seqCounters.set(gi, counter + 1);\n }\n }\n\n return results;\n }\n}\n","import { Storage } from \"../storage\";\n\nexport type AudioBuffers = Record<string | number, AudioBuffer | undefined>;\n\n/**\n * A function that downloads audio into a AudioBuffers\n */\nexport type AudioBuffersLoader = (\n context: BaseAudioContext,\n buffers: AudioBuffers,\n) => Promise<void>;\n\nexport async function loadAudioBuffer(\n context: BaseAudioContext,\n url: string,\n storage: Storage,\n): Promise<AudioBuffer | undefined> {\n url = url\n .replace(/#/g, \"%23\")\n .replace(/ /g, \"%20\")\n .replace(/([^:]\\/)\\/+/g, \"$1\");\n const response = await storage.fetch(url);\n if (response.status !== 200) {\n console.warn(\n \"Error loading buffer. Invalid status: \",\n response.status,\n url,\n );\n return;\n }\n try {\n const audioData = await response.arrayBuffer();\n const buffer = await context.decodeAudioData(audioData);\n return buffer;\n } catch (error) {\n console.warn(\"Error loading buffer\", error, url);\n }\n}\n\n// Safari reports it can play OGG but decodeAudioData fails on many samples\nfunction isSafari(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const ua = navigator.userAgent;\n return (\n ua.includes(\"Safari\") && !ua.includes(\"Chrome\") && !ua.includes(\"Chromium\")\n );\n}\n\nexport function findFirstSupportedFormat(formats: string[]): string | null {\n if (typeof document === \"undefined\") return null;\n\n // Safari's decodeAudioData fails on OGG even though canPlayType returns \"maybe\"\n // Skip OGG entirely on Safari and use the fallback format (mp3/m4a)\n const skipOgg = isSafari();\n\n const audio = document.createElement(\"audio\");\n for (let i = 0; i < formats.length; i++) {\n const format = formats[i];\n if (skipOgg && format === \"ogg\") {\n continue;\n }\n const canPlay = audio.canPlayType(`audio/${format}`);\n if (canPlay === \"probably\" || canPlay === \"maybe\") {\n return format;\n }\n // check Safari for aac format\n if (format === \"m4a\") {\n const canPlay = audio.canPlayType(`audio/aac`);\n if (canPlay === \"probably\" || canPlay === \"maybe\") {\n return format;\n }\n }\n }\n return null;\n}\n\nexport function getPreferredAudioExtension() {\n const format = findFirstSupportedFormat([\"ogg\", \"m4a\"]) ?? \"ogg\";\n return \".\" + format;\n}\n","import { asConstructable } from \"./as-constructable\";\nimport { findFirstSupportedFormat, loadAudioBuffer } from \"./load-audio\";\nimport { HttpStorage, Storage } from \"../storage\";\nimport { SmplrPreset } from \"./types\";\n\n/**\n * Loads and decodes AudioBuffers for the samples referenced by a {@link SmplrPreset}.\n * Used internally by every smplr instrument; pass an instance via\n * {@link SmplrOptions.loader} to share buffer caching across multiple instruments.\n */\nexport interface SampleLoader {\n /**\n * Load all samples referenced by `json`. Returns a Map keyed by sample\n * name (`region.sample`), values are decoded `AudioBuffer`s. Failed\n * samples are silently omitted (callers handle absence at lookup time).\n *\n * Internally cached by resolved URL, so repeated calls with the same\n * baseUrl/format/path do not re-fetch.\n *\n * @param json The preset describing samples to load.\n * @param options\n * - `buffers`: pre-decoded buffers keyed by sample name — skip fetch for these.\n * - `onProgress`: called with `(loaded, total)` per sample (including cache hits).\n */\n load(\n json: SmplrPreset,\n options?: SampleLoaderLoadOptions,\n ): Promise<Map<string, AudioBuffer>>;\n\n /**\n * @deprecated Pass `{ onProgress }` instead. The bare-callback form is kept\n * for compatibility; the options form is the canonical 1.x signature.\n */\n load(\n json: SmplrPreset,\n onProgress: (loaded: number, total: number) => void,\n ): Promise<Map<string, AudioBuffer>>;\n}\n\n/** Options accepted by `SampleLoader(context, options)`. */\nexport type SampleLoaderOptions = {\n /** Custom storage backend (e.g. `CacheStorage` for offline). Defaults to `HttpStorage`. */\n storage?: Storage;\n};\n\n/** Options accepted by `loader.load(json, options)`. */\nexport type SampleLoaderLoadOptions = {\n /** Pre-decoded buffers keyed by sample name — skip fetch for these. */\n buffers?: Map<string, AudioBuffer>;\n /** Called once per sample (including cache hits) with cumulative progress. */\n onProgress?: (loaded: number, total: number) => void;\n};\n\nclass SampleLoaderImpl implements SampleLoader {\n #context: BaseAudioContext;\n #storage: Storage;\n #cache: Map<string, AudioBuffer> = new Map();\n\n constructor(context: BaseAudioContext, options?: SampleLoaderOptions) {\n this.#context = context;\n this.#storage = options?.storage ?? HttpStorage;\n }\n\n async load(\n json: SmplrPreset,\n onProgressOrOptions?:\n | ((loaded: number, total: number) => void)\n | SampleLoaderLoadOptions,\n ): Promise<Map<string, AudioBuffer>> {\n // Normalise the second argument: support legacy callback or new options object\n const preloaded =\n typeof onProgressOrOptions === \"object\"\n ? onProgressOrOptions.buffers\n : undefined;\n const onProgress =\n typeof onProgressOrOptions === \"function\"\n ? onProgressOrOptions\n : onProgressOrOptions?.onProgress;\n\n const format =\n findFirstSupportedFormat(json.samples.formats) ??\n json.samples.formats[0] ??\n \"ogg\";\n\n const base = json.samples.baseUrl.replace(/\\/$/, \"\");\n const names = collectSampleNames(json);\n const total = names.length;\n let loaded = 0;\n\n const result = new Map<string, AudioBuffer>();\n\n await Promise.all(\n names.map(async (name) => {\n // 1. Check pre-loaded buffers first — no fetch needed\n const pre = preloaded?.get(name);\n if (pre) {\n result.set(name, pre);\n loaded++;\n onProgress?.(loaded, total);\n return;\n }\n\n // 2. Build URL and check internal cache\n const path = json.samples.map?.[name] ?? name;\n const url = `${base}/${path}.${format}`;\n\n let buffer = this.#cache.get(url);\n\n if (!buffer) {\n const fetched = await loadAudioBuffer(\n this.#context,\n url,\n this.#storage,\n );\n if (fetched) {\n buffer = fetched;\n this.#cache.set(url, buffer);\n }\n }\n\n if (buffer) result.set(name, buffer);\n\n loaded++;\n onProgress?.(loaded, total);\n }),\n );\n\n return result;\n }\n}\n\n/** Collect all unique region.sample names across all groups. */\nfunction collectSampleNames(json: SmplrPreset): string[] {\n const seen = new Set<string>();\n for (const group of json.groups) {\n for (const region of group.regions) {\n seen.add(region.sample);\n }\n }\n return [...seen];\n}\n\ntype SampleLoaderFactory = {\n (context: BaseAudioContext, options?: SampleLoaderOptions): SampleLoader;\n /** @deprecated Call as a function: `SampleLoader(...)` instead of `new SampleLoader(...)`. */\n new (context: BaseAudioContext, options?: SampleLoaderOptions): SampleLoader;\n};\n\nexport const SampleLoader: SampleLoaderFactory =\n asConstructable(SampleLoaderImpl);\n","/**\n * A sorted items that uses binary search to insert items in sorted order.\n * @private\n */\nexport class SortedQueue<T> {\n #items: T[] = [];\n constructor(public readonly compare: (a: T, b: T) => number) {}\n\n push(item: T) {\n const len = this.#items.length;\n\n let left = 0;\n let right = len - 1;\n let index = len;\n\n while (left <= right) {\n const mid = Math.floor((left + right) / 2);\n if (this.compare(item, this.#items[mid]) < 0) {\n index = mid;\n right = mid - 1;\n } else {\n left = mid + 1;\n }\n }\n\n this.#items.splice(index, 0, item);\n }\n\n pop() {\n return this.#items.shift();\n }\n\n peek(): T | undefined {\n return this.#items[0];\n }\n\n removeAll(predicate: (item: T) => boolean) {\n const len = this.#items.length;\n this.#items = this.#items.filter((item) => !predicate(item));\n return this.#items.length !== len;\n }\n\n clear() {\n this.#items = [];\n }\n\n size() {\n return this.#items.length;\n }\n}\n","import { asConstructable } from \"./as-constructable\";\nimport { SortedQueue } from \"./sorted-queue\";\nimport { NoteEvent, StopFn } from \"./types\";\n\nconst LOOKAHEAD_MS_DEFAULT = 200;\nconst INTERVAL_MS_DEFAULT = 50;\n\n/**\n * Schedules note events for future dispatch. Used internally by every smplr\n * instrument; pass an instance via {@link SmplrOptions.scheduler} to share one\n * scheduler across multiple instruments.\n */\nexport interface Scheduler {\n /**\n * Dispatch `callback` at `event.time`. If `event.time` is within the\n * scheduler's lookahead window (or omitted), the callback fires synchronously\n * and the returned {@link StopFn} is a no-op. Otherwise the event is queued.\n *\n * The returned function removes the event from the queue before dispatch.\n */\n schedule(event: NoteEvent, callback: (event: NoteEvent) => void): StopFn;\n\n /**\n * Clear all queued (not-yet-dispatched) events and stop the polling\n * interval. Does not affect voices already playing.\n */\n stop(): void;\n}\n\n/** Options accepted by `Scheduler(context, options)`. */\nexport type SchedulerOptions = {\n /**\n * How far ahead of `currentTime` events are dispatched synchronously.\n * Defaults to 200ms.\n */\n lookaheadMs?: number;\n /**\n * How often the queue is polled for events ready to dispatch.\n * Defaults to 50ms.\n */\n intervalMs?: number;\n};\n\ntype QueueItem = {\n time: number;\n event: NoteEvent;\n callback: (event: NoteEvent) => void;\n};\n\nclass SchedulerImpl implements Scheduler {\n #context: BaseAudioContext;\n #lookaheadSec: number;\n #intervalMs: number;\n #queue: SortedQueue<QueueItem>;\n #intervalId: ReturnType<typeof setInterval> | undefined;\n\n constructor(context: BaseAudioContext, options?: SchedulerOptions) {\n this.#context = context;\n this.#lookaheadSec = (options?.lookaheadMs ?? LOOKAHEAD_MS_DEFAULT) / 1000;\n this.#intervalMs = options?.intervalMs ?? INTERVAL_MS_DEFAULT;\n this.#queue = new SortedQueue<QueueItem>((a, b) => a.time - b.time);\n }\n\n schedule(event: NoteEvent, callback: (event: NoteEvent) => void): StopFn {\n const now = this.#context.currentTime;\n const time = getEventTime(event) ?? now;\n\n if (time <= now + this.#lookaheadSec) {\n callback(event);\n return noOp;\n }\n\n const item: QueueItem = { time, event, callback };\n this.#queue.push(item);\n this.#ensureRunning();\n\n return () => {\n this.#queue.removeAll((q) => q === item);\n };\n }\n\n stop(): void {\n this.#queue.clear();\n if (this.#intervalId !== undefined) {\n clearInterval(this.#intervalId);\n this.#intervalId = undefined;\n }\n }\n\n #ensureRunning(): void {\n if (this.#intervalId !== undefined) return;\n\n this.#intervalId = setInterval(() => {\n const dispatchBefore = this.#context.currentTime + this.#lookaheadSec;\n\n while (\n this.#queue.size() > 0 &&\n this.#queue.peek()!.time <= dispatchBefore\n ) {\n const item = this.#queue.pop()!;\n item.callback(item.event);\n }\n\n // Self-terminate when the queue is empty\n if (this.#queue.size() === 0) {\n clearInterval(this.#intervalId);\n this.#intervalId = undefined;\n }\n }, this.#intervalMs);\n }\n}\n\nfunction getEventTime(event: NoteEvent): number | undefined {\n return typeof event === \"object\" ? event.time : undefined;\n}\n\nconst noOp: StopFn = () => {};\n\ntype SchedulerFactory = {\n (context: BaseAudioContext, options?: SchedulerOptions): Scheduler;\n /** @deprecated Call as a function: `Scheduler(...)` instead of `new Scheduler(...)`. */\n new (context: BaseAudioContext, options?: SchedulerOptions): Scheduler;\n};\n\nexport const Scheduler: SchedulerFactory = asConstructable(SchedulerImpl);\n","import { dbToGain, midiVelToGain } from \"./volume\";\nimport { VoiceParams } from \"./types\";\n\nexport class Voice {\n readonly stopId: string | number;\n readonly group: number | undefined;\n\n #context: BaseAudioContext;\n #source: AudioBufferSourceNode;\n #envelope: GainNode;\n #startAt: number;\n #ampRelease: number;\n #state: \"playing\" | \"stopping\" | \"stopped\" = \"playing\";\n #endedCallbacks: (() => void)[] = [];\n\n constructor(\n context: BaseAudioContext,\n buffer: AudioBuffer,\n params: VoiceParams,\n destination: AudioNode,\n stopId: string | number,\n group?: number,\n startTime?: number,\n ) {\n this.#context = context;\n this.stopId = stopId;\n this.group = group;\n this.#ampRelease = params.ampRelease;\n\n // --- Build audio graph ---\n\n const source = context.createBufferSource();\n source.buffer = buffer;\n\n // Detune — Safari workaround: source.detune may not exist\n const cents = params.detune;\n if (source.detune) {\n source.detune.value = cents;\n } else {\n source.playbackRate.value = Math.pow(2, cents / 1200);\n }\n\n // Looping\n if (params.loopAuto) {\n source.loop = true;\n source.loopStart = buffer.duration * params.loopAuto.startRatio;\n source.loopEnd = buffer.duration * params.loopAuto.endRatio;\n } else if (params.loop) {\n source.loop = true;\n source.loopStart = params.loopStart;\n source.loopEnd = params.loopEnd || buffer.duration;\n }\n\n // LPF — only inserted when cutoff is meaningfully below Nyquist\n let lpf: BiquadFilterNode | undefined;\n if (params.lpfCutoffHz < 20000) {\n lpf = context.createBiquadFilter();\n lpf.type = \"lowpass\";\n lpf.frequency.value = params.lpfCutoffHz;\n }\n\n // Velocity gain × dB volume\n const gain = context.createGain();\n gain.gain.value = midiVelToGain(params.velocity) * dbToGain(params.volume);\n\n // Release envelope\n const envelope = context.createGain();\n envelope.gain.value = 1.0;\n\n // Wire: source → [lpf] → gain → envelope → destination\n if (lpf) {\n source.connect(lpf);\n lpf.connect(gain);\n } else {\n source.connect(gain);\n }\n gain.connect(envelope);\n envelope.connect(destination);\n\n // Start\n const startAt = startTime ?? context.currentTime;\n this.#startAt = startAt;\n\n // Offset: VoiceParams.offset is in sample frames; source.start() takes seconds.\n // When playing in reverse (buffer is already reversed), mirror the offset so\n // offset=N from the start of the original buffer maps to (length-N) in the reversed one.\n let offsetSec = 0;\n if (params.offset > 0) {\n offsetSec = params.reverse\n ? (buffer.length - params.offset) / buffer.sampleRate\n : params.offset / buffer.sampleRate;\n }\n source.start(startAt, offsetSec);\n\n this.#source = source;\n this.#envelope = envelope;\n\n // Cleanup when the source naturally ends or is stopped\n source.onended = () => {\n this.#state = \"stopped\";\n envelope.disconnect();\n gain.disconnect();\n lpf?.disconnect();\n source.disconnect();\n for (const cb of this.#endedCallbacks) cb();\n this.#endedCallbacks = [];\n };\n }\n\n /**\n * Stop the voice, applying a release envelope if time is after the start time.\n * Idempotent — subsequent calls after the first are ignored.\n */\n stop(time?: number): void {\n if (this.#state !== \"playing\") return;\n this.#state = \"stopping\";\n\n const t = time ?? this.#context.currentTime;\n\n if (t <= this.#startAt) {\n // Stop at or before start: cancel the note entirely\n this.#source.stop(t);\n } else {\n // Apply release envelope then stop the source\n const stopAt = t + this.#ampRelease;\n this.#envelope.gain.cancelScheduledValues(t);\n this.#envelope.gain.setValueAtTime(1.0, t);\n this.#envelope.gain.linearRampToValueAtTime(0, stopAt);\n this.#source.stop(stopAt);\n }\n }\n\n /**\n * Register a callback to be called when the source node fires its onended event.\n * If the voice has already stopped, the callback is invoked immediately.\n */\n onEnded(cb: () => void): void {\n if (this.#state === \"stopped\") {\n cb();\n } else {\n this.#endedCallbacks.push(cb);\n }\n }\n\n get isActive(): boolean {\n return this.#state !== \"stopped\";\n }\n}\n","import { Voice } from \"./voice\";\n\n/**\n * Tracks active Voice instances and provides O(1) stop operations via Maps.\n *\n * Replaces the old broadcast-stop pattern (O(n) signal to all voices)\n * with direct Set lookups keyed by stopId and group number.\n */\nexport class VoiceManager {\n #voices: Set<Voice> = new Set();\n #byStopId: Map<string | number, Set<Voice>> = new Map();\n #byGroup: Map<number, Set<Voice>> = new Map();\n\n /**\n * Register a voice. Indexes it by stopId and group, then auto-removes it\n * when the voice fires its onEnded callback.\n */\n add(voice: Voice): void {\n this.#voices.add(voice);\n\n // Index by stopId\n getOrCreate(this.#byStopId, voice.stopId).add(voice);\n\n // Index by group (only if the voice belongs to an exclusive group)\n if (voice.group !== undefined) {\n getOrCreate(this.#byGroup, voice.group).add(voice);\n }\n\n // Auto-remove when the voice's source node fires onended\n voice.onEnded(() => this.#remove(voice));\n }\n\n /** Stop all active voices. */\n stopAll(time?: number): void {\n // Snapshot before iterating — stop() may synchronously trigger onEnded\n // which removes voices from the set while we're iterating.\n for (const voice of [...this.#voices]) {\n voice.stop(time);\n }\n }\n\n /** Stop all voices whose stopId matches. */\n stopById(stopId: string | number, time?: number): void {\n const voices = this.#byStopId.get(stopId);\n if (!voices) return;\n for (const voice of [...voices]) {\n voice.stop(time);\n }\n }\n\n /** Stop all voices that belong to an exclusive group number. */\n stopGroup(group: number, time?: number): void {\n const voices = this.#byGroup.get(group);\n if (!voices) return;\n for (const voice of [...voices]) {\n voice.stop(time);\n }\n }\n\n /** Number of voices currently tracked (includes stopping voices not yet ended). */\n get activeCount(): number {\n return this.#voices.size;\n }\n\n #remove(voice: Voice): void {\n this.#voices.delete(voice);\n this.#byStopId.get(voice.stopId)?.delete(voice);\n if (voice.group !== undefined) {\n this.#byGroup.get(voice.group)?.delete(voice);\n }\n }\n}\n\nfunction getOrCreate<K, V>(map: Map<K, Set<V>>, key: K): Set<V> {\n let set = map.get(key);\n if (!set) {\n set = new Set();\n map.set(key, set);\n }\n return set;\n}\n","import { Channel, OutputChannel } from \"./channel\";\nimport type { Smplr } from \"./instrument\";\nimport { toMidi } from \"./midi\";\nimport { Storage } from \"../storage\";\nimport { resolveParams } from \"./params\";\nimport { RegionMatcher } from \"./region-matcher\";\nimport { SampleLoader } from \"./sample-loader\";\nimport { Scheduler } from \"./scheduler\";\nimport {\n LoadProgress,\n NoteEvent,\n PlaybackParams,\n SmplrPreset,\n StopFn,\n StopTarget,\n} from \"./types\";\nimport { Voice } from \"./voice\";\nimport { VoiceManager } from \"./voice-manager\";\n\nexport type SmplrOptions = {\n /** Custom storage backend for sample fetching (e.g. CacheStorage). */\n storage?: Storage;\n /** Destination audio node. Defaults to context.destination. */\n destination?: AudioNode;\n /** Master volume (0–127 MIDI scale). Defaults to 100. */\n volume?: number;\n /** Custom volume-to-gain mapping function. Defaults to midiVelToGain. */\n volumeToGain?: (volume: number) => number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). Defaults to 0. */\n pan?: number;\n /** Default note velocity when not specified in NoteEvent (0–127). Defaults to 100. */\n velocity?: number;\n /** Shared SampleLoader instance. If omitted, a private one is created. */\n loader?: SampleLoader;\n /** Shared Scheduler instance. If omitted, a private one is created. */\n scheduler?: Scheduler;\n /** Called after each buffer is loaded (or served from cache). */\n onLoadProgress?: (progress: LoadProgress) => void;\n /** Called when a note is dispatched to the audio engine (slightly before playback). */\n onStart?: (event: NoteEvent) => void;\n /** Called when each voice's audio node ends. */\n onEnded?: (event: NoteEvent) => void;\n};\n\n/**\n * Fully resolved note event, normalized from the public NoteEvent union type.\n * Used internally after normalization in start().\n */\ntype NormalizedNoteEvent = {\n note: string | number;\n midi: number;\n velocity: number;\n time?: number;\n duration?: number | null;\n detune?: number;\n lpfCutoffHz?: number;\n loop?: boolean;\n ampRelease?: number;\n reverse?: boolean;\n stopId: string | number;\n onStart?: (event: NoteEvent) => void;\n onEnded?: (event: NoteEvent) => void;\n};\n\nfunction compose<T>(\n a: ((e: T) => void) | undefined,\n b: ((e: T) => void) | undefined,\n): ((e: T) => void) | undefined {\n if (a && b)\n return (e) => {\n a(e);\n b(e);\n };\n return a ?? b;\n}\n\n/** Empty RegionMatcher used before loadInstrument() is called. */\nconst EMPTY_JSON: SmplrPreset = {\n samples: { baseUrl: \"\", formats: [] },\n groups: [],\n};\n\n/**\n * Detect whether an argument is a SmplrPreset descriptor.\n * SmplrPreset always has a `groups` array; SmplrOptions does not.\n */\nfunction isSmplrJson(x: unknown): x is SmplrPreset {\n return (\n typeof x === \"object\" &&\n x !== null &&\n \"groups\" in x &&\n Array.isArray((x as SmplrPreset).groups)\n );\n}\n\n/**\n * Internal smplr implementation. Loads samples described by a SmplrPreset\n * descriptor, matches notes to regions, and plays them through a Channel.\n *\n * Not exported from the package barrel — third-party plugins receive an\n * instance typed as {@link PluginSmplr} via the {@link Instrument} builder.\n *\n * Pattern A — json provided at construction:\n * `new SmplrImpl(context, json, options?)`\n *\n * Pattern B — json loaded later via loadInstrument():\n * `new SmplrImpl(context, options?)` then `smplr.loadInstrument(json)`\n */\nexport class SmplrImpl implements Smplr {\n /** The AudioContext (or OfflineAudioContext) passed to the constructor. */\n readonly context: BaseAudioContext;\n /** Shared SampleLoader. Read-only on the public surface; injectable via SmplrOptions.loader. */\n readonly loader: SampleLoader;\n /** Shared Scheduler. Read-only on the public surface; injectable via SmplrOptions.scheduler. */\n readonly scheduler: Scheduler;\n\n /**\n * Resolves when the instrument is ready to play. For Pattern A this tracks\n * the constructor-time load; for Pattern B it starts resolved and may be\n * replaced by the {@link Instrument} builder via {@link _setReady}.\n */\n ready: Promise<void>;\n\n #loadProgress: LoadProgress = { loaded: 0, total: 0 };\n #loadToken = 0;\n #buffers: Map<string, AudioBuffer> = new Map();\n #reversedBuffers: Map<string, AudioBuffer> = new Map();\n #defaults: PlaybackParams | undefined;\n #defaultVelocity: number;\n #aliases: Map<string, number> | undefined;\n #matcher: RegionMatcher;\n #voices: VoiceManager;\n #channel: Channel;\n #onLoadProgress: ((progress: LoadProgress) => void) | undefined;\n #onStart: ((event: NoteEvent) => void) | undefined;\n #onEnded: ((event: NoteEvent) => void) | undefined;\n #ccState: Map<number, number> = new Map();\n #disposed = false;\n\n #assertNotDisposed(action: string): void {\n if (this.#disposed) {\n throw Error(`Cannot ${action} on a disposed Smplr instance.`);\n }\n }\n\n constructor(\n context: BaseAudioContext,\n json: SmplrPreset,\n options?: SmplrOptions,\n );\n constructor(context: BaseAudioContext, options?: SmplrOptions);\n constructor(\n context: BaseAudioContext,\n jsonOrOptions?: SmplrPreset | SmplrOptions,\n maybeOptions?: SmplrOptions,\n ) {\n const json = isSmplrJson(jsonOrOptions) ? jsonOrOptions : undefined;\n const options = isSmplrJson(jsonOrOptions)\n ? maybeOptions\n : (jsonOrOptions as SmplrOptions | undefined);\n\n this.context = context;\n this.#defaults = json?.defaults;\n this.#defaultVelocity = options?.velocity ?? 100;\n this.#onLoadProgress = options?.onLoadProgress;\n this.#onStart = options?.onStart;\n this.#onEnded = options?.onEnded;\n\n if (json?.aliases) {\n this.#aliases = new Map(Object.entries(json.aliases));\n }\n\n // 1. Output channel — volume, routing, effects\n this.#channel = new Channel(context, {\n destination: options?.destination,\n volume: options?.volume,\n volumeToGain: options?.volumeToGain,\n pan: options?.pan,\n });\n\n // 2. Scheduler — shared or private\n this.scheduler = options?.scheduler ?? Scheduler(context);\n\n // 3. Region matcher — pre-processes groups/regions once\n this.#matcher = new RegionMatcher(json ?? EMPTY_JSON);\n\n // 4. Voice manager — tracks active voices for stop operations\n this.#voices = new VoiceManager();\n\n // 5. Sample loader — shared or private\n this.loader =\n options?.loader ?? SampleLoader(context, { storage: options?.storage });\n\n if (json) {\n // Pattern A: load immediately\n this.ready = this.loader\n .load(json, {\n onProgress: (loaded, total) => {\n this.#loadProgress = { loaded, total };\n this.#onLoadProgress?.({ loaded, total });\n },\n })\n .then((buffers) => {\n this.#buffers = buffers;\n });\n } else {\n // Pattern B: resolve immediately; caller will call loadInstrument()\n this.ready = Promise.resolve();\n }\n }\n\n /**\n * @deprecated Use {@link ready} instead. Returns a Promise that resolves\n * to this instance for compatibility with `const x = await new X(ctx).load`.\n */\n get load(): Promise<this> {\n return this.ready.then(() => this);\n }\n\n /**\n * @internal — only the {@link Instrument} builder should call this. Replaces\n * the `ready` promise after plugin setup completes.\n */\n _setReady(p: Promise<void>): void {\n this.ready = p;\n }\n\n /**\n * Load (or replace) the instrument descriptor. All state (matcher, defaults,\n * aliases, reversed-buffer cache, sample buffers) swaps atomically when the\n * load resolves. Concurrent calls are serialized: only the latest call's\n * result is committed; earlier in-flight calls resolve but do not mutate\n * state.\n *\n * Pre-loaded buffers (e.g. base64-decoded) can be passed via the `buffers`\n * parameter — those skip the fetch step.\n */\n loadInstrument(\n json: SmplrPreset,\n buffers?: Map<string, AudioBuffer>,\n ): Promise<void> {\n this.#assertNotDisposed(\"load an instrument\");\n const token = ++this.#loadToken;\n\n return this.loader\n .load(json, {\n buffers,\n onProgress: (loaded, total) => {\n this.#loadProgress = { loaded, total };\n this.#onLoadProgress?.({ loaded, total });\n },\n })\n .then((newBuffers) => {\n if (token !== this.#loadToken) return;\n this.#defaults = json.defaults;\n this.#aliases = json.aliases\n ? new Map(Object.entries(json.aliases))\n : undefined;\n this.#matcher = new RegionMatcher(json);\n this.#reversedBuffers = new Map();\n this.#buffers = newBuffers;\n });\n }\n\n /** Current loading progress snapshot. `total` is known before loading starts. */\n get loadProgress(): LoadProgress {\n return this.#loadProgress;\n }\n\n /** The output channel — use to add effects, adjust volume, or route audio. */\n get output(): OutputChannel {\n return this.#channel;\n }\n\n /**\n * Set a MIDI CC value. Affects region matching for groups/regions that have\n * ccRange constraints (e.g. CC64 sustain pedal).\n */\n setCC(cc: number, value: number): void {\n this.#assertNotDisposed(\"set CC\");\n this.#ccState.set(cc, value);\n }\n\n /**\n * Read the latest value set via {@link setCC}. Returns `0` for any CC that\n * has not been set (matches MIDI's \"undefined controller defaults to 0\"\n * convention).\n */\n getCC(cc: number): number {\n this.#assertNotDisposed(\"read CC\");\n return this.#ccState.get(cc) ?? 0;\n }\n\n /**\n * Set the cents detune applied to every future note. Mutates the instrument's\n * playback defaults in place; takes effect on notes scheduled after the call.\n * In-flight notes are unaffected.\n */\n setDetune(cents: number): void {\n this.#assertNotDisposed(\"set detune\");\n if (!this.#defaults) this.#defaults = {};\n this.#defaults.detune = cents;\n }\n\n /**\n * Set whether every future note plays its sample reversed. The reversed-buffer\n * cache is populated lazily on demand; no cache invalidation is needed in\n * either direction.\n */\n setReverse(reverse: boolean): void {\n this.#assertNotDisposed(\"set reverse\");\n if (!this.#defaults) this.#defaults = {};\n this.#defaults.reverse = reverse;\n }\n\n /**\n * Start playing a note. Returns a StopFn that cancels the note if it hasn't\n * played yet, or stops the resulting voices if it has.\n */\n start(event: NoteEvent): StopFn {\n this.#assertNotDisposed(\"start a note\");\n const normalized = this.#normalizeNoteEvent(event);\n\n const schedulerStop = this.scheduler.schedule(\n normalized as NoteEvent,\n (e) => this.#playNote(e as NormalizedNoteEvent),\n );\n\n return (time?: number) => {\n schedulerStop(); // cancel from queue if not yet dispatched\n this.#voices.stopById(normalized.stopId, time); // stop if already playing\n };\n }\n\n /**\n * Stop voices.\n *\n * - No argument → stop all active voices\n * - String or number → stop all voices with that stopId\n * - `{ stopId }` → stop voices with that stopId, optionally at a future time\n * - `{ time }` (no stopId) → stop all voices at a future time\n */\n stop(target?: StopTarget): void {\n this.#assertNotDisposed(\"stop voices\");\n if (target === undefined) {\n this.#voices.stopAll();\n } else if (typeof target === \"string\" || typeof target === \"number\") {\n this.#voices.stopById(target);\n } else {\n if (target.stopId !== undefined) {\n this.#voices.stopById(target.stopId, target.time);\n } else {\n this.#voices.stopAll(target.time);\n }\n }\n }\n\n /**\n * Stop all voices, dispose the output channel, and stop the scheduler.\n * The instance must not be used after this call — subsequent\n * `start`/`stop`/`setCC`/`getCC`/`loadInstrument` calls throw.\n * Subsequent `dispose()` calls are no-ops.\n */\n dispose(): void {\n if (this.#disposed) return;\n this.#disposed = true;\n this.#voices.stopAll();\n this.#channel.disconnect();\n this.scheduler.stop();\n }\n\n /** @deprecated Use {@link dispose} instead. */\n disconnect(): void {\n this.dispose();\n }\n\n #getBuffer(sample: string, reverse: boolean): AudioBuffer | undefined {\n if (!reverse) return this.#buffers.get(sample);\n const cached = this.#reversedBuffers.get(sample);\n if (cached) return cached;\n const original = this.#buffers.get(sample);\n if (!original) return undefined;\n const reversed = this.context.createBuffer(\n original.numberOfChannels,\n original.length,\n original.sampleRate,\n );\n for (let ch = 0; ch < original.numberOfChannels; ch++) {\n const data = original.getChannelData(ch).slice().reverse();\n reversed.copyToChannel(data, ch);\n }\n this.#reversedBuffers.set(sample, reversed);\n return reversed;\n }\n\n #playNote(event: NormalizedNoteEvent): void {\n const {\n midi,\n velocity,\n time,\n stopId,\n duration,\n detune,\n lpfCutoffHz,\n loop,\n ampRelease,\n reverse,\n onStart,\n onEnded,\n } = event;\n\n const matches = this.#matcher.match(midi, velocity, this.#ccState);\n\n // Stop exclusive groups before starting new voices\n for (const match of matches) {\n if (match.offBy !== undefined) {\n this.#voices.stopGroup(match.offBy, time);\n }\n }\n\n // Create a voice for each matched region\n let voiceStarted = false;\n const effectiveReverse = reverse ?? this.#defaults?.reverse ?? false;\n for (const match of matches) {\n const buffer = this.#getBuffer(match.sample, effectiveReverse);\n if (!buffer) continue;\n\n const params = resolveParams(\n this.#defaults,\n match.groupRef,\n match.regionRef,\n midi,\n velocity,\n { detune, lpfCutoffHz, loop, ampRelease, reverse },\n );\n\n const voice = new Voice(\n this.context,\n buffer,\n params,\n this.#channel.input,\n stopId,\n match.group,\n time,\n );\n\n this.#voices.add(voice);\n\n // onStart fires once on the first matched voice\n if (!voiceStarted) {\n onStart?.(event);\n voiceStarted = true;\n }\n\n // onEnded fires once per voice when its audio node ends\n if (onEnded) {\n voice.onEnded(() => onEnded(event));\n }\n\n // Auto-stop for duration — schedule directly on the audio timeline\n // so it works in both real-time and offline (OfflineAudioContext) contexts.\n if (duration != null) {\n const startT = time ?? this.context.currentTime;\n const releaseAt = startT + duration;\n voice.stop(releaseAt);\n }\n }\n }\n\n #normalizeNoteEvent(event: NoteEvent): NormalizedNoteEvent {\n if (typeof event === \"string\" || typeof event === \"number\") {\n const midi = toMidi(event) ?? this.#aliases?.get(String(event)) ?? 0;\n return {\n note: event,\n midi,\n velocity: this.#defaultVelocity,\n stopId: event,\n onStart: this.#onStart,\n onEnded: this.#onEnded,\n };\n }\n const midi =\n toMidi(event.note) ?? this.#aliases?.get(String(event.note)) ?? 0;\n return {\n ...event,\n midi,\n velocity: event.velocity ?? this.#defaultVelocity,\n stopId: event.stopId ?? event.note,\n onStart: compose(this.#onStart, event.onStart),\n onEnded: compose(this.#onEnded, event.onEnded),\n };\n }\n}\n","import type { OutputChannel } from \"./channel\";\nimport type { SampleLoader } from \"./sample-loader\";\nimport type { Scheduler } from \"./scheduler\";\nimport { SmplrImpl, type SmplrOptions } from \"./smplr\";\nimport type {\n LoadProgress,\n NoteEvent,\n SmplrPreset,\n StopFn,\n StopTarget,\n} from \"./types\";\n\n/**\n * Public Smplr interface — the type plugin authors, helper functions, and\n * users program against. Mirrors the surface of the underlying SmplrImpl\n * class, minus internal helpers.\n *\n * `loadInstrument` is intentionally *not* on this interface — it's the\n * plugin-side API, exposed via {@link PluginSmplr} to plugin bodies only.\n */\nexport interface Smplr {\n readonly context: BaseAudioContext;\n\n /** Resolves when the instrument is ready to play. Preferred over `load`. */\n readonly ready: Promise<void>;\n\n /**\n * @deprecated Use `ready` instead. Returns a Promise that resolves to the\n * instrument for compatibility with `const x = await new X(ctx).load`.\n */\n readonly load: Promise<Smplr>;\n\n readonly output: OutputChannel;\n\n /** Shared with other instruments via SmplrOptions.loader. */\n readonly loader: SampleLoader;\n\n /** Shared with other instruments via SmplrOptions.scheduler. */\n readonly scheduler: Scheduler;\n\n readonly loadProgress: LoadProgress;\n\n start(event: NoteEvent): StopFn;\n stop(target?: StopTarget): void;\n setCC(cc: number, value: number): void;\n\n /**\n * Read the latest value set via `setCC`. Returns `0` for any CC that has\n * not been set (matches MIDI's \"undefined controller defaults to 0\" convention).\n */\n getCC(cc: number): number;\n\n /**\n * Set the cents detune applied to every future note. Mutates the instrument's\n * playback defaults in place; takes effect on notes scheduled after the call.\n * In-flight notes are unaffected.\n */\n setDetune(cents: number): void;\n\n /**\n * Set whether every future note plays its sample reversed. Mutates the\n * instrument's playback defaults in place. The reversed-buffer cache is\n * populated lazily on demand; no cache invalidation is needed in either\n * direction.\n */\n setReverse(reverse: boolean): void;\n\n /**\n * Stop all voices, dispose the output channel, and stop the scheduler.\n * The instance must not be used after this call — subsequent `start`/`stop`/\n * `setCC`/`getCC`/`setControlValue`/`loadInstrument` calls throw. Subsequent\n * `dispose()` calls are no-ops.\n */\n dispose(): void;\n\n /** @deprecated Use `dispose()` instead. */\n disconnect(): void;\n}\n\n/**\n * Plugin-facing widening of {@link Smplr} that exposes `loadInstrument` —\n * the primary plugin → smplr API for wiring an async-loaded JSON.\n *\n * This interface is *not* exported from the package barrel. Plugin authors\n * receive it as the third argument to their {@link SmplrPlugin}.\n */\nexport interface PluginSmplr extends Smplr {\n /**\n * Replace the current instrument JSON and re-fetch buffers. Pre-decoded\n * buffers (e.g. base64-decoded from a soundfont) can be passed via the\n * `buffers` parameter.\n *\n * Resolves when all samples are ready.\n */\n loadInstrument(\n json: SmplrPreset,\n buffers?: Map<string, AudioBuffer>,\n ): Promise<void>;\n}\n\n/**\n * Permitted return shapes for an {@link SmplrPlugin}:\n *\n * - `void` — sync plugin, no async load, no extras\n * - `Promise<void>` — async load, no extras\n * - `{ extras: E; ready: Promise<void> }` — sync extras + async load\n * - `{ ready: Promise<void> }` — async load, no extras (explicit form)\n *\n * Extras keys are merged onto the smplr instance via `Object.assign` and\n * may shadow base {@link Smplr} methods (e.g. DrumMachine overrides `start`\n * to inject `stopId: sample.note`). For sync extras with no async load,\n * use `{ extras, ready: Promise.resolve() }`.\n */\nexport type SmplrPluginResult<E extends object> =\n | void\n | Promise<void>\n | { extras: E; ready: Promise<void> }\n | { ready: Promise<void> };\n\n/**\n * Plugin signature. Receives the audio context, the user options (with\n * SmplrOptions keys already stripped by the {@link Instrument} builder),\n * and a {@link PluginSmplr} the plugin can wire up.\n */\nexport type SmplrPlugin<O, E extends object = {}> = (\n ctx: BaseAudioContext,\n options: O,\n smplr: PluginSmplr,\n) => SmplrPluginResult<E>;\n\n/**\n * The dual call/construct factory produced by {@link Instrument}. Callable\n * without `new` (preferred) or with `new` (kept for compatibility with\n * pre-1.0 examples).\n */\n/**\n * The full instance type produced by an {@link InstrumentFactory} — a Smplr\n * with its plugin extras, plus a `load` Promise refined to resolve back to\n * the same intersection (so `await x.load` preserves the extras shape).\n */\nexport type InstrumentInstance<E extends object = {}> = Smplr &\n E & { readonly load: Promise<Smplr & E> };\n\nexport type InstrumentFactory<O, E extends object = {}> = {\n (\n ctx: BaseAudioContext,\n options?: O & Partial<SmplrOptions>,\n ): InstrumentInstance<E>;\n\n /**\n * @deprecated Call as a function: `MyInstrument(ctx, opts)` instead of\n * `new MyInstrument(...)`. Kept for compatibility with pre-1.0 examples.\n */\n new (\n ctx: BaseAudioContext,\n options?: O & Partial<SmplrOptions>,\n ): InstrumentInstance<E>;\n};\n\nconst SMPLR_OPTION_KEYS = [\n \"storage\",\n \"destination\",\n \"volume\",\n \"volumeToGain\",\n \"pan\",\n \"velocity\",\n \"loader\",\n \"scheduler\",\n \"onLoadProgress\",\n \"onStart\",\n \"onEnded\",\n] as const;\n\nfunction splitOptions<O>(options: O & Partial<SmplrOptions>): {\n smplrOpts: SmplrOptions;\n pluginOpts: O;\n} {\n // SmplrOptions keys are *copied*, not moved — plugins may also depend on\n // them (e.g. Sampler uses `storage` to fetch URL-loaded buffers in addition\n // to SmplrImpl using it for its internal SampleLoader).\n const src = (options ?? {}) as Record<string, unknown>;\n const smplrOpts: Record<string, unknown> = {};\n for (const key of SMPLR_OPTION_KEYS) {\n if (key in src) smplrOpts[key] = src[key];\n }\n return { smplrOpts: smplrOpts as SmplrOptions, pluginOpts: options as O };\n}\n\nfunction isPromise(x: unknown): x is Promise<unknown> {\n return (\n typeof x === \"object\" &&\n x !== null &&\n typeof (x as { then?: unknown }).then === \"function\"\n );\n}\n\n/**\n * Merge each own property of `extras` onto `target`, preserving property\n * descriptors (so getters stay live). `Object.assign` would *invoke* each\n * getter and copy the result as a data property — that snapshot would lose\n * the closure-captured state plugins use for extras like\n * `Soundfont2Sampler.instrumentNames`.\n */\nfunction mergeExtras(target: object, extras: object): void {\n for (const key of Object.getOwnPropertyNames(extras)) {\n const desc = Object.getOwnPropertyDescriptor(extras, key);\n if (desc) Object.defineProperty(target, key, desc);\n }\n}\n\n/**\n * Builder for smplr instruments. Wraps a plugin function into a dual\n * call/construct factory that produces ready-to-play {@link Smplr} instances\n * augmented with plugin extras.\n *\n * ```ts\n * type MyOptions = { instrument: string };\n *\n * export const MyInstrument = Instrument<MyOptions>((ctx, options, smplr) => {\n * return smplr.loadInstrument(fetchJson(options.instrument));\n * });\n *\n * const inst = MyInstrument(ctx, { instrument: \"piano\", volume: 80 });\n * await inst.ready;\n * inst.start(\"C4\");\n * ```\n */\nexport function Instrument<O, E extends object = {}>(\n plugin: SmplrPlugin<O, E>,\n): InstrumentFactory<O, E> {\n function factory(\n ctx: BaseAudioContext,\n options?: O & Partial<SmplrOptions>,\n ): InstrumentInstance<E> {\n const { smplrOpts, pluginOpts } = splitOptions(\n (options ?? {}) as O & Partial<SmplrOptions>,\n );\n const smplr = new SmplrImpl(ctx, smplrOpts);\n const result: unknown = plugin(ctx, pluginOpts, smplr);\n\n let readyPromise: Promise<void> = Promise.resolve();\n\n if (result != null) {\n if (isPromise(result)) {\n readyPromise = result as Promise<void>;\n } else if (typeof result === \"object\") {\n const maybe = result as { extras?: object; ready?: Promise<void> };\n if (maybe.extras) mergeExtras(smplr, maybe.extras);\n if (isPromise(maybe.ready)) readyPromise = maybe.ready;\n }\n }\n\n smplr._setReady(readyPromise);\n return smplr as unknown as InstrumentInstance<E>;\n }\n\n return factory as unknown as InstrumentFactory<O, E>;\n}\n","import { Storage } from \"../storage\";\n\nexport function isDrumMachineInstrument(\n instrument: any,\n): instrument is DrumMachineInstrument {\n return (\n typeof instrument === \"object\" &&\n typeof instrument.baseUrl === \"string\" &&\n typeof instrument.name === \"string\" &&\n Array.isArray(instrument.samples) &&\n Array.isArray(instrument.groupNames) &&\n typeof instrument.nameToSampleName === \"object\" &&\n typeof instrument.sampleGroupVariations === \"object\"\n );\n}\n\nexport type DrumMachineInstrument = {\n baseUrl: string;\n name: string;\n samples: string[];\n groupNames: string[];\n nameToSampleName: Record<string, string | undefined>;\n sampleGroupVariations: Record<string, string[]>;\n};\nexport const EMPTY_INSTRUMENT: DrumMachineInstrument = {\n baseUrl: \"\",\n name: \"\",\n samples: [],\n groupNames: [],\n nameToSampleName: {},\n sampleGroupVariations: {},\n};\n\nexport async function fetchDrumMachineInstrument(\n url: string,\n storage: Storage,\n): Promise<DrumMachineInstrument> {\n const res = await storage.fetch(url);\n const json = await res.json();\n // need to fix json\n json.baseUrl = url.replace(\"/dm.json\", \"\");\n json.groupNames = [];\n json.nameToSampleName = {};\n json.sampleGroupVariations = {};\n for (const sample of json.samples) {\n json.nameToSampleName[sample] = sample;\n const separator = sample.indexOf(\"/\") !== -1 ? \"/\" : \"-\";\n const [base, variation] = sample.split(separator);\n if (!json.groupNames.includes(base)) {\n json.groupNames.push(base);\n }\n json.nameToSampleName[base] ??= sample;\n json.sampleGroupVariations[base] ??= [];\n if (variation) {\n json.sampleGroupVariations[base].push(`${base}${separator}${variation}`);\n }\n }\n\n return json;\n}\n","import { HttpStorage, Storage } from \"../storage\";\nimport { Instrument } from \"../smplr\";\nimport {\n LoadProgress,\n NoteEvent,\n SmplrGroup,\n SmplrPreset,\n StopFn,\n} from \"../smplr/types\";\nimport {\n DrumMachineInstrument,\n EMPTY_INSTRUMENT,\n fetchDrumMachineInstrument,\n isDrumMachineInstrument,\n} from \"./dm-instrument\";\n\nexport function getDrumMachineNames() {\n return Object.keys(INSTRUMENTS);\n}\n\nconst INSTRUMENTS: Record<string, string> = {\n \"TR-808\": \"https://smpldsnds.github.io/drum-machines/TR-808/dm.json\",\n \"Casio-RZ1\": \"https://smpldsnds.github.io/drum-machines/Casio-RZ1/dm.json\",\n \"LM-2\": \"https://smpldsnds.github.io/drum-machines/LM-2/dm.json\",\n \"MFB-512\": \"https://smpldsnds.github.io/drum-machines/MFB-512/dm.json\",\n \"Roland CR-8000\":\n \"https://smpldsnds.github.io/drum-machines/Roland-CR-8000/dm.json\",\n};\n\ntype DrumMachineConfig = {\n instrument: string | DrumMachineInstrument;\n url: string;\n storage: Storage;\n};\n\nexport type DrumMachineOptions = Partial<\n DrumMachineConfig & {\n destination?: AudioNode;\n volume?: number;\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nfunction getConfig(options?: DrumMachineOptions): DrumMachineConfig {\n const config = {\n instrument: options?.instrument ?? \"TR-808\",\n storage: options?.storage ?? HttpStorage,\n url: options?.url ?? \"\",\n };\n if (typeof config.instrument === \"string\") {\n config.url ||= INSTRUMENTS[config.instrument];\n if (!config.url)\n throw new Error(\"Invalid instrument: \" + config.instrument);\n } else if (!isDrumMachineInstrument(config.instrument)) {\n throw new Error(\"Invalid instrument: \" + config.instrument);\n }\n\n return config;\n}\n\ntype DrumMachineExtras = {\n getSampleNames(): string[];\n getGroupNames(): string[];\n getSampleNamesForGroup(groupName: string): string[];\n start(event: NoteEvent): StopFn;\n};\n\nexport const DrumMachine = Instrument(\n (ctx: BaseAudioContext, options: DrumMachineOptions = {}, smplr) => {\n const config = getConfig(options);\n\n // Mutable closure state — extras read this; the load promise populates it.\n let instrument: DrumMachineInstrument = EMPTY_INSTRUMENT;\n\n // Capture the base `start` *before* Object.assign(smplr, extras) shadows\n // it — otherwise the override below would recurse into itself.\n const baseStart = smplr.start.bind(smplr);\n\n const extras: DrumMachineExtras = {\n getSampleNames: () => instrument.samples.slice(),\n getGroupNames: () => instrument.groupNames.slice(),\n getSampleNamesForGroup: (groupName) =>\n instrument.sampleGroupVariations[groupName] ?? [],\n\n // Override start() to inject stopId so re-triggering the same drum\n // cuts the previous voice (one-shot-per-drum semantic).\n start: (sample) => {\n const s = typeof sample === \"object\" ? sample : { note: sample };\n return baseStart({\n ...s,\n stopId:\n (s as { stopId?: string | number; note: string | number }).stopId ??\n s.note,\n });\n },\n };\n\n const instrumentPromise = isDrumMachineInstrument(config.instrument)\n ? Promise.resolve(config.instrument)\n : fetchDrumMachineInstrument(config.url, config.storage);\n\n const ready = instrumentPromise.then((inst) => {\n instrument = inst;\n return smplr.loadInstrument(drumMachineToPreset(inst));\n });\n\n return { extras, ready };\n },\n);\n\n/** Instance type returned by the {@link DrumMachine} factory. */\nexport type DrumMachine = ReturnType<typeof DrumMachine>;\n\n// ---------------------------------------------------------------------------\n// drumMachineToPreset — pure converter function\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a DrumMachineInstrument to a SmplrPreset descriptor.\n *\n * Each sample gets a sequential MIDI number starting at 36 (GM drum map base).\n * Aliases are created for both the full sample name (\"kick/1\") and the group\n * name (\"kick\") so both forms work with Smplr.start({ note: \"kick\" }).\n */\nexport function drumMachineToPreset(\n instrument: DrumMachineInstrument,\n): SmplrPreset {\n const aliases: Record<string, number> = {};\n const regions: SmplrGroup[\"regions\"] = [];\n\n const BASE_MIDI = 36;\n\n instrument.samples.forEach((sampleName, i) => {\n const midi = BASE_MIDI + i;\n\n // Full sample name alias: \"kick/1\" → midi\n aliases[sampleName] = midi;\n\n regions.push({\n sample: sampleName,\n keyRange: [midi, midi],\n pitch: midi,\n });\n });\n\n // Group name aliases: \"kick\" → first sample MIDI\n for (const [groupName, firstSample] of Object.entries(\n instrument.nameToSampleName,\n )) {\n if (firstSample) {\n const idx = instrument.samples.indexOf(firstSample);\n if (idx >= 0) {\n aliases[groupName] = BASE_MIDI + idx;\n }\n }\n }\n\n return {\n samples: {\n baseUrl: instrument.baseUrl,\n formats: [\"ogg\", \"m4a\"],\n },\n groups: [{ regions }],\n aliases,\n };\n}\n","// DrumAbuse — smplr instrument for the Synthabuse drum-machine sample collection.\n//\nimport { HttpStorage, type Storage } from \"../storage\";\nimport { Instrument } from \"../smplr\";\nimport type {\n LoadProgress,\n NoteEvent,\n SmplrPreset,\n StopFn,\n} from \"../smplr/types\";\n\nconst DEFAULT_BASE_URL = \"https://smpldsnds.github.io\";\nconst MIDI_BASE = 36;\n\nexport const DRUM_ABUSE_PACKS = [\n \"vol1\",\n \"vol2\",\n \"vol3\",\n \"vol4\",\n \"vol5\",\n] as const;\nexport type DrumAbusePackId = (typeof DRUM_ABUSE_PACKS)[number];\n\nconst MACHINES_BY_PACK: Record<DrumAbusePackId, readonly string[]> = {\n vol1: [\n \"4-inthefloor-percussioncombo\",\n \"ace-tone-rhythm-ace-fr-1\",\n \"ace-tone-rhythm-ace-fr-7l\",\n \"ace-tone-rhythm-ace-fr6\",\n \"ace-tone-rhythm-king\",\n \"ace-tone-rhythm-master\",\n \"antonelli-2377\",\n \"arp-axxe\",\n \"conn-min-o-matic\",\n \"eko-compu-rhythm\",\n \"eko-ritmo-12\",\n \"eko-ritmo-20\",\n \"elgam-carousel\",\n \"emu-modular\",\n \"farfisa-pro\",\n \"farfisa-rhythm-10\",\n \"farfisa-rhythm-maker-16\",\n \"gibson-maestro-g-2\",\n \"gibson-maestro-rhythm-jester\",\n \"gibson-maestro-rhythm-king-mrk-1\",\n \"gulbransen-organ\",\n \"hammond-rhythm\",\n \"hammond-rhythm-ii\",\n \"hohner-automatic-rhythm-player\",\n \"jen-sx-1000\",\n \"kay-r-8\",\n \"keio-checkmate\",\n \"kent-k-200\",\n \"kent-rhythm-master\",\n \"korg-kr-33\",\n \"korg-krz\",\n \"korg-minipops-series\",\n \"korg-s-3\",\n \"korg-univox-micro-rhythmer-12\",\n \"korg-univox-sr-120\",\n \"korg-univox-sr-95\",\n \"luxor-passat\",\n \"moog-modular-55\",\n \"roland-arr\",\n \"roland-edp-1\",\n \"roland-sh-3a\",\n \"roland-system-100\",\n \"roland-tr-1-prototype\",\n \"roland-tr-33\",\n \"roland-tr-41-prototype\",\n \"roland-tr-66\",\n \"roland-tr-77\",\n \"seeburg-rhythm-prince\",\n \"seeburg-select-a-rhythm\",\n \"solton-disco-64\",\n \"sonor-mini-mammut-module\",\n \"video-tech-rythmic-10\",\n \"vox-percussion-king\",\n \"whippany-melo-sonic-350\",\n \"wurlitzer-swinging-rhythm\",\n \"yamaha-cs-15d\",\n \"yamaha-cs-5\",\n \"yamaha-cs-6\",\n \"yamaha-ps-1\",\n \"yamaha-ps-2\",\n \"yamaha-ps-3\",\n ],\n vol2: [\n \"bontempi-hf222\",\n \"boss-dr-55\",\n \"casio-mt-18\",\n \"casio-pt-30\",\n \"casio-vl-1\",\n \"chaser-computer-drum-pr-80\",\n \"crb-rhythmboy-480\",\n \"eko-musicbox-12\",\n \"electro-harmonix-drm-15\",\n \"electro-harmonix-drm-16\",\n \"electro-harmonix-spacedrum\",\n \"elka-drumstar-80\",\n \"elka-x-1000\",\n \"emu-e-drum\",\n \"gem-drum-15\",\n \"hammond-autovari-64\",\n \"hohner-rhythm-80k\",\n \"korg-kpr-77\",\n \"korg-kr-55\",\n \"korg-kr-mini\",\n \"korg-monopoly\",\n \"korg-ms-10\",\n \"korg-trident\",\n \"linn-lm-1\",\n \"monacor-rhythmical-choice\",\n \"mti-auto-orchestra-ao-1\",\n \"multi-moog\",\n \"mxr-185\",\n \"new-england-digital-synclavier\",\n \"oberheim-dmx\",\n \"pearl-drum-x\",\n \"pollard-syndrum-178\",\n \"roland-cr-1000\",\n \"roland-cr-68\",\n \"roland-cr-78\",\n \"roland-cr-80\",\n \"roland-cr-8000\",\n \"roland-dr-55\",\n \"roland-jupiter-8\",\n \"roland-pb-300-rhythm-plus\",\n \"roland-rhy-33\",\n \"roland-rhy-55\",\n \"roland-sh-09\",\n \"roland-tr-55\",\n \"roland-tr-606\",\n \"roland-tr-808\",\n \"simmons-drum\",\n \"simmons-sds-1\",\n \"simmons-sds-5\",\n \"solton-programmer-24\",\n \"star-instruments-synare-3\",\n \"star-instruments-synare-ps-1\",\n \"visco-space-drum\",\n \"watford-electronics-rhythm-generator\",\n \"yamaha-cs-40m\",\n \"yamaha-mr-10\",\n \"yamaha-ps-55\",\n ],\n vol3: [\n \"amdek-pck-100\",\n \"austin-arb-6\",\n \"bme-rattlesnake-parametric-percussion-system\",\n \"boss-dr-110\",\n \"casio-mt-100\",\n \"coron-drumsynce-ds-7\",\n \"coron-rds\",\n \"denon-crb-90\",\n \"drumfire-df-2000\",\n \"drumfire-df-500\",\n \"electro-harmonix-drm-32\",\n \"emu-drumulator\",\n \"kay-drm-1\",\n \"korg-ddm-110\",\n \"korg-ddm-220\",\n \"korg-poly-800\",\n \"linn-linndrum-lm-1-vinyl\",\n \"linn-lm-2\",\n \"mattel-electronics-synsonics-drm\",\n \"mattel-electronics-synsonics-pro\",\n \"panasonic-rd-9844\",\n \"pearl-drx-1\",\n \"roland-ddr-30\",\n \"roland-mc-202\",\n \"roland-rhy-77\",\n \"roland-tr-909\",\n \"rsf-dd-30\",\n \"sakata-dpm-48\",\n \"sequential-circuits-drumtraks\",\n \"simmons-clap-trap\",\n \"simmons-sds-200\",\n \"simmons-sds-400\",\n \"soundmaster-sm-8\",\n \"soundmaster-sr-88\",\n \"tama-ts-206\",\n \"tama-ts-305\",\n \"wersi-wm-24\",\n \"yamaha-dx7\",\n ],\n vol4: [\n \"atlantex-mpc-1\",\n \"boss-hc-2\",\n \"boss-pc-2\",\n \"casio-ct-310\",\n \"casio-mt-500\",\n \"casio-mt-800\",\n \"casio-pt-68\",\n \"casio-pt-82\",\n \"casio-sk-1\",\n \"dr-b-hm-digital-drums\",\n \"emu-sp-12\",\n \"ensoniq-mirage\",\n \"hing-hon-ek-001\",\n \"kawai-acr-20\",\n \"kawai-sx-240\",\n \"klone-dual-percussion-synthesiser\",\n \"korg-ddd-1\",\n \"korg-pss-50\",\n \"kurzweil-electrodrum-prototype\",\n \"linn-9000\",\n \"linn-linndrum-lm-2-vinyl\",\n \"nasta-hitstix-2\",\n \"oberheim-dx\",\n \"pearl-sc-40\",\n \"rhodes-polaris\",\n \"roland-juno-106\",\n \"roland-super-quartet-mks-7\",\n \"roland-tr-707\",\n \"roland-tr-727\",\n \"siel-mdp-40\",\n \"simmons-sds-1000\",\n \"simmons-sds-7\",\n \"simmons-sds-8\",\n \"simmons-sds-9\",\n \"sony-drp-1\",\n \"soundmaster-stix-st-305\",\n \"suzuki-rpm-40\",\n \"tama-ts-500\",\n \"technics-ax-5\",\n \"technics-pcm-dp-50\",\n \"wersi-prisma-dx-5\",\n \"yamaha-dd-5\",\n \"yamaha-rx-11\",\n \"yamaha-rx-15\",\n \"yamaha-rx-21\",\n \"yamaha-rx-5\",\n ],\n vol5: [\n \"boss-dr-pad-drp-i\",\n \"casio-ct-403\",\n \"casio-cz-230s\",\n \"casio-ht-700\",\n \"casio-rz-1\",\n \"cheetah-spec-drum\",\n \"forat-f-9000\",\n \"korg-ddd-5\",\n \"korg-dss-1\",\n \"m-p-c-electronics-dsm-1\",\n \"pearl-sy-1\",\n \"roland-tr-505\",\n \"sequential-circuits-studio-440\",\n \"simmons-sds-2000\",\n \"simmons-sdx\",\n \"yamaha-pss-130\",\n \"yamaha-ptx8\",\n \"yamaha-rx-21l\",\n ],\n};\n\nconst machineToPack: ReadonlyMap<string, DrumAbusePackId> = (() => {\n const m = new Map<string, DrumAbusePackId>();\n for (const pack of DRUM_ABUSE_PACKS) {\n for (const id of MACHINES_BY_PACK[pack]) m.set(id, pack);\n }\n return m;\n})();\n\nexport function getDrumAbuseMachineNames(): string[] {\n return [...machineToPack.keys()];\n}\n\nexport function getDrumAbuseMachinesForPack(\n pack: DrumAbusePackId,\n): readonly string[] {\n return MACHINES_BY_PACK[pack];\n}\n\nexport function getDrumAbusePackNames(): readonly DrumAbusePackId[] {\n return DRUM_ABUSE_PACKS;\n}\n\nexport function getDrumAbuseMachinePack(\n id: string,\n): DrumAbusePackId | undefined {\n return machineToPack.get(id);\n}\n\n// ---- URL helpers ------------------------------------------------------------\n\nconst encSeg = (s: string) => s.split(\"/\").map(encodeURIComponent).join(\"/\");\n\nfunction packBase(baseUrl: string, pack: DrumAbusePackId): string {\n return `${baseUrl}/drum-abuse-${pack}`;\n}\n\nfunction sampleBaseUrl(\n baseUrl: string,\n pack: DrumAbusePackId,\n urlPath: string,\n): string {\n return `${packBase(baseUrl, pack)}/samples/${encSeg(urlPath)}/`;\n}\n\n/** Build a full sample URL. Exported so external row-level Sampler use\n * (e.g. the sequencer engine) can share the same URL convention. */\nexport function drumAbuseSampleUrl(\n pack: DrumAbusePackId,\n urlPath: string,\n fileNoExt: string,\n format = \"wav\",\n baseUrl = DEFAULT_BASE_URL,\n): string {\n return `${sampleBaseUrl(baseUrl, pack, urlPath)}${encodeURIComponent(fileNoExt)}.${format}`;\n}\n\nfunction stripExt(filename: string): string {\n return filename.replace(/\\.[^.]+$/, \"\");\n}\n\n// ---- Repo JSON types (private) ---------------------------------------------\n\ntype RepoSampleSet = {\n path: string;\n set: string;\n url_path: string;\n samples: string[];\n sample_instruments: string[];\n};\n\ntype RepoMachine = {\n id: string;\n sample_sets: RepoSampleSet[];\n};\n\ntype RepoPackSample = {\n machine_id: string;\n url_path: string;\n file: string;\n};\n\n// ---- Fetch layer ------------------------------------------------------------\n\nconst jsonCache = new Map<string, Promise<unknown>>();\n\nfunction fetchJSON<T>(url: string, storage: Storage): Promise<T> {\n let p = jsonCache.get(url) as Promise<T> | undefined;\n if (!p) {\n p = storage.fetch(url).then((r) => {\n if (r.status >= 400) throw new Error(`DrumAbuse: ${r.status} ${url}`);\n return r.json() as Promise<T>;\n });\n jsonCache.set(url, p);\n }\n return p;\n}\n\n// ---- Preset builders --------------------------------------------------------\n\ntype BuiltPreset = {\n preset: SmplrPreset;\n sampleNames: string[];\n groupNames: string[];\n sampleNamesForGroup: Record<string, string[]>;\n setPath: string | null;\n};\n\nfunction buildMachinePreset(\n machine: RepoMachine,\n setPath: string | undefined,\n baseUrl: string,\n pack: DrumAbusePackId,\n): BuiltPreset {\n if (machine.sample_sets.length === 0) {\n throw new Error(`DrumAbuse: machine \"${machine.id}\" has no sample sets`);\n }\n const set = setPath\n ? machine.sample_sets.find((s) => s.path === setPath)\n : machine.sample_sets[0];\n if (!set) {\n throw new Error(`DrumAbuse: set \"${setPath}\" not found on \"${machine.id}\"`);\n }\n if (set.samples.length === 0) {\n throw new Error(\n `DrumAbuse: set \"${set.path}\" of \"${machine.id}\" has no samples`,\n );\n }\n\n const sampleNames: string[] = [];\n const groupNames: string[] = [];\n const sampleNamesForGroup: Record<string, string[]> = {};\n const aliases: Record<string, number> = {};\n const regions = set.samples.map((file, i) => {\n const key = stripExt(file);\n const midi = MIDI_BASE + i;\n sampleNames.push(key);\n aliases[key] = midi;\n const group = set.sample_instruments[i] || \"\";\n if (group) {\n if (!sampleNamesForGroup[group]) {\n sampleNamesForGroup[group] = [];\n groupNames.push(group);\n aliases[group] = midi;\n }\n sampleNamesForGroup[group].push(key);\n }\n return {\n sample: key,\n keyRange: [midi, midi] as [number, number],\n pitch: midi,\n };\n });\n\n return {\n preset: {\n samples: {\n baseUrl: sampleBaseUrl(baseUrl, pack, set.url_path),\n formats: [\"wav\"],\n },\n groups: [{ regions }],\n aliases,\n },\n sampleNames,\n groupNames,\n sampleNamesForGroup,\n setPath: set.path,\n };\n}\n\nfunction buildPackPreset(\n list: RepoPackSample[],\n baseUrl: string,\n pack: DrumAbusePackId,\n): BuiltPreset {\n if (list.length === 0) {\n throw new Error(`DrumAbuse: empty pack-instrument list for pack \"${pack}\"`);\n }\n\n // First pass: count filename collisions so unique short aliases stay unique.\n const fileCount: Record<string, number> = {};\n for (const s of list) {\n const f = stripExt(s.file);\n fileCount[f] = (fileCount[f] ?? 0) + 1;\n }\n\n const sampleNames: string[] = [];\n const groupNames: string[] = [];\n const sampleNamesForGroup: Record<string, string[]> = {};\n const map: Record<string, string> = {};\n const aliases: Record<string, number> = {};\n\n const regions = list.map((s, i) => {\n const fileKey = stripExt(s.file);\n const uniqueKey = `${s.machine_id}/${fileKey}`;\n const midi = MIDI_BASE + i;\n sampleNames.push(uniqueKey);\n aliases[uniqueKey] = midi;\n if (fileCount[fileKey] === 1) aliases[fileKey] = midi;\n map[uniqueKey] =\n `${packBase(baseUrl, pack)}/samples/${encSeg(s.url_path)}/${encodeURIComponent(s.file)}`;\n\n if (!sampleNamesForGroup[s.machine_id]) {\n sampleNamesForGroup[s.machine_id] = [];\n groupNames.push(s.machine_id);\n aliases[s.machine_id] = midi;\n }\n sampleNamesForGroup[s.machine_id].push(uniqueKey);\n\n return {\n sample: uniqueKey,\n keyRange: [midi, midi] as [number, number],\n pitch: midi,\n };\n });\n\n return {\n preset: {\n samples: { baseUrl: \"\", formats: [\"wav\"], map },\n groups: [{ regions }],\n aliases,\n },\n sampleNames,\n groupNames,\n sampleNamesForGroup,\n setPath: null,\n };\n}\n\n// ---- DrumAbuse factory ------------------------------------------------------\n\nexport type DrumAbuseSource =\n | { kind: \"machine\"; machine: string; set?: string }\n | { kind: \"pack\"; pack: DrumAbusePackId; instrument: string };\n\nexport type DrumAbuseConfig = {\n source: DrumAbuseSource;\n baseUrl: string;\n storage: Storage;\n};\n\nexport type DrumAbuseOptions = Partial<\n DrumAbuseConfig & {\n destination?: AudioNode;\n volume?: number;\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nexport type DrumAbuseExtras = {\n readonly mode: \"machine\" | \"pack\";\n getSampleNames(): string[];\n getGroupNames(): string[];\n getSampleNamesForGroup(groupName: string): string[];\n getMachineId(): string | null;\n getSetPath(): string | null;\n getPackId(): DrumAbusePackId;\n start(event: NoteEvent): StopFn;\n};\n\nexport const DrumAbuse = Instrument<DrumAbuseOptions, DrumAbuseExtras>(\n (_ctx, options = {}, smplr) => {\n const source = options.source;\n if (!source) {\n throw new Error(\"DrumAbuse: options.source is required\");\n }\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const storage = options.storage ?? HttpStorage;\n\n let sampleNames: string[] = [];\n let groupNames: string[] = [];\n let sampleNamesForGroup: Record<string, string[]> = {};\n let machineId: string | null = null;\n let setPath: string | null = null;\n let packId: DrumAbusePackId;\n let mode: \"machine\" | \"pack\";\n\n let presetPromise: Promise<SmplrPreset>;\n\n if (source.kind === \"machine\") {\n mode = \"machine\";\n const pack = getDrumAbuseMachinePack(source.machine);\n if (!pack) {\n throw new Error(`DrumAbuse: unknown machine \"${source.machine}\"`);\n }\n packId = pack;\n machineId = source.machine;\n const url = `${packBase(baseUrl, pack)}/machines/${encodeURIComponent(source.machine)}.json`;\n presetPromise = fetchJSON<RepoMachine>(url, storage).then((machine) => {\n const built = buildMachinePreset(machine, source.set, baseUrl, pack);\n sampleNames = built.sampleNames;\n groupNames = built.groupNames;\n sampleNamesForGroup = built.sampleNamesForGroup;\n setPath = built.setPath;\n return built.preset;\n });\n } else {\n mode = \"pack\";\n if (!(DRUM_ABUSE_PACKS as readonly string[]).includes(source.pack)) {\n throw new Error(`DrumAbuse: unknown pack \"${source.pack}\"`);\n }\n packId = source.pack;\n const url = `${packBase(baseUrl, source.pack)}/instruments/${encodeURIComponent(source.instrument)}.json`;\n presetPromise = fetchJSON<RepoPackSample[]>(url, storage).then((list) => {\n const built = buildPackPreset(list, baseUrl, source.pack);\n sampleNames = built.sampleNames;\n groupNames = built.groupNames;\n sampleNamesForGroup = built.sampleNamesForGroup;\n return built.preset;\n });\n }\n\n const baseStart = smplr.start.bind(smplr);\n const extras: DrumAbuseExtras = {\n get mode() {\n return mode;\n },\n getSampleNames: () => sampleNames.slice(),\n getGroupNames: () => groupNames.slice(),\n getSampleNamesForGroup: (g) => (sampleNamesForGroup[g] ?? []).slice(),\n getMachineId: () => machineId,\n getSetPath: () => setPath,\n getPackId: () => packId,\n start: (event) => {\n const ev = typeof event === \"object\" ? event : { note: event };\n return baseStart({ ...ev, stopId: ev.stopId ?? ev.note });\n },\n };\n\n const ready = presetPromise.then((preset) => smplr.loadInstrument(preset));\n return { extras, ready };\n },\n);\n\nexport type DrumAbuse = ReturnType<typeof DrumAbuse>;\n","/**\n * Encode an AudioBuffer as a WAV file Blob.\n *\n * Supports 32-bit float (lossless) and 16-bit integer (CD quality) formats.\n */\n\n/** Encode AudioBuffer as 32-bit float WAV. */\nexport function audioBufferToWav(buffer: AudioBuffer): Blob {\n return encodeWav(buffer, 32);\n}\n\n/** Encode AudioBuffer as 16-bit integer WAV. */\nexport function audioBufferToWav16(buffer: AudioBuffer): Blob {\n return encodeWav(buffer, 16);\n}\n\nfunction encodeWav(buffer: AudioBuffer, bitDepth: 16 | 32): Blob {\n const numChannels = buffer.numberOfChannels;\n const sampleRate = buffer.sampleRate;\n const length = buffer.length;\n const bytesPerSample = bitDepth / 8;\n const blockAlign = numChannels * bytesPerSample;\n const dataSize = length * blockAlign;\n const headerSize = 44;\n\n const arrayBuffer = new ArrayBuffer(headerSize + dataSize);\n const view = new DataView(arrayBuffer);\n\n // RIFF header\n writeString(view, 0, \"RIFF\");\n view.setUint32(4, 36 + dataSize, true);\n writeString(view, 8, \"WAVE\");\n\n // fmt chunk\n writeString(view, 12, \"fmt \");\n view.setUint32(16, 16, true); // chunk size\n view.setUint16(20, bitDepth === 32 ? 3 : 1, true); // format: 3 = IEEE float, 1 = PCM\n view.setUint16(22, numChannels, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, sampleRate * blockAlign, true); // byte rate\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, bitDepth, true);\n\n // data chunk\n writeString(view, 36, \"data\");\n view.setUint32(40, dataSize, true);\n\n // Interleave channel data\n const channels: Float32Array[] = [];\n for (let ch = 0; ch < numChannels; ch++) {\n channels.push(buffer.getChannelData(ch));\n }\n\n let offset = headerSize;\n for (let i = 0; i < length; i++) {\n for (let ch = 0; ch < numChannels; ch++) {\n const sample = channels[ch][i];\n if (bitDepth === 32) {\n view.setFloat32(offset, sample, true);\n } else {\n // Clamp to [-1, 1] and scale to 16-bit range\n const clamped = Math.max(-1, Math.min(1, sample));\n view.setInt16(\n offset,\n clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff,\n true,\n );\n }\n offset += bytesPerSample;\n }\n }\n\n return new Blob([arrayBuffer], { type: \"audio/wav\" });\n}\n\nfunction writeString(view: DataView, offset: number, str: string): void {\n for (let i = 0; i < str.length; i++) {\n view.setUint8(offset + i, str.charCodeAt(i));\n }\n}\n","import { audioBufferToWav, audioBufferToWav16 } from \"./wav-encoder\";\n\n/**\n * The result of an offline render. Provides the raw AudioBuffer and\n * lazy WAV encoding / download convenience methods.\n */\nexport class RenderResult {\n readonly audioBuffer: AudioBuffer;\n readonly duration: number;\n readonly sampleRate: number;\n\n #wavCache: Blob | undefined;\n #wav16Cache: Blob | undefined;\n\n constructor(audioBuffer: AudioBuffer) {\n this.audioBuffer = audioBuffer;\n this.duration = audioBuffer.duration;\n this.sampleRate = audioBuffer.sampleRate;\n }\n\n /** Encode as 32-bit float WAV. Cached after first call. */\n toWav(): Blob {\n if (!this.#wavCache) {\n this.#wavCache = audioBufferToWav(this.audioBuffer);\n }\n return this.#wavCache;\n }\n\n /** Encode as 16-bit integer WAV. Cached after first call. */\n toWav16(): Blob {\n if (!this.#wav16Cache) {\n this.#wav16Cache = audioBufferToWav16(this.audioBuffer);\n }\n return this.#wav16Cache;\n }\n\n /** Download as 32-bit float WAV file. */\n downloadWav(filename = \"render.wav\"): void {\n downloadBlob(this.toWav(), filename);\n }\n\n /** Download as 16-bit integer WAV file. */\n downloadWav16(filename = \"render.wav\"): void {\n downloadBlob(this.toWav16(), filename);\n }\n}\n\nfunction downloadBlob(blob: Blob, filename: string): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = filename;\n a.click();\n URL.revokeObjectURL(url);\n}\n","/**\n * Trim trailing silence from an AudioBuffer.\n *\n * Scans all channels from the end to find the last sample above the threshold,\n * then returns a new AudioBuffer trimmed to that length.\n */\n\nconst SILENCE_THRESHOLD = 1e-4; // ~-80dB\n\nexport function trimSilence(buffer: AudioBuffer): AudioBuffer {\n const { numberOfChannels, sampleRate, length } = buffer;\n\n // Find the last non-silent sample across all channels\n let lastNonSilent = 0;\n for (let ch = 0; ch < numberOfChannels; ch++) {\n const data = buffer.getChannelData(ch);\n for (let i = length - 1; i >= 0; i--) {\n if (Math.abs(data[i]) > SILENCE_THRESHOLD) {\n if (i > lastNonSilent) lastNonSilent = i;\n break;\n }\n }\n }\n\n // Keep at least 1 sample\n const trimmedLength = Math.max(1, lastNonSilent + 1);\n\n if (trimmedLength === length) return buffer;\n\n // Create a new trimmed buffer\n // Note: OfflineAudioContext is not available here, so we use the constructor\n const trimmed = new AudioBuffer({\n numberOfChannels,\n length: trimmedLength,\n sampleRate,\n });\n\n for (let ch = 0; ch < numberOfChannels; ch++) {\n const source = buffer.getChannelData(ch);\n trimmed.copyToChannel(source.subarray(0, trimmedLength), ch);\n }\n\n return trimmed;\n}\n","import { RenderResult } from \"./render-result\";\nimport { trimSilence } from \"./trim-silence\";\n\nexport type { RenderResult };\n\nexport interface RenderOfflineOptions {\n /** Total duration in seconds. When omitted, uses 60s max and trims trailing silence. */\n duration?: number;\n /** Sample rate. Default: 48000. */\n sampleRate?: number;\n /** Number of output channels. Default: 2 (stereo). */\n channels?: number;\n}\n\nconst DEFAULT_SAMPLE_RATE = 48000;\nconst DEFAULT_CHANNELS = 2;\nconst DEFAULT_MAX_DURATION = 60;\n\n/**\n * Render audio offline using an OfflineAudioContext.\n *\n * The callback receives an OfflineAudioContext. Create instruments,\n * schedule notes using absolute times (starting from 0), then return.\n * The audio is rendered as fast as possible (not real-time).\n *\n * Returns a RenderResult with the rendered AudioBuffer and\n * convenience methods for WAV encoding and download.\n *\n * @example\n * ```ts\n * const result = await renderOffline(async (context) => {\n * const piano = await new SplendidGrandPiano(context).load;\n * piano.start({ note: \"C4\", time: 0, duration: 1 });\n * });\n * result.downloadWav(\"export.wav\");\n * ```\n */\nexport async function renderOffline(\n callback: (context: OfflineAudioContext) => Promise<void>,\n options?: RenderOfflineOptions,\n): Promise<RenderResult> {\n const sampleRate = options?.sampleRate ?? DEFAULT_SAMPLE_RATE;\n const channels = options?.channels ?? DEFAULT_CHANNELS;\n const explicitDuration = options?.duration;\n const duration = explicitDuration ?? DEFAULT_MAX_DURATION;\n const length = Math.ceil(duration * sampleRate);\n\n const offlineContext = new OfflineAudioContext(channels, length, sampleRate);\n\n await callback(offlineContext);\n\n let buffer = await offlineContext.startRendering();\n\n // Auto-trim trailing silence when duration was not explicitly provided\n if (explicitDuration === undefined) {\n buffer = trimSilence(buffer);\n }\n\n return new RenderResult(buffer);\n}\n","import type { TimeSignature } from \"./sequencer\";\n\n/**\n * Parse a musical time value to ticks.\n *\n * Supported formats:\n * \"4n\" — quarter note (4 * ppq / 4 = ppq ticks)\n * \"8n\" — eighth note (4 * ppq / 8 = ppq/2 ticks)\n * \"16n\" — sixteenth note\n * \"2n\" — half note\n * \"1n\" — whole note (4 * ppq ticks)\n * \"4n.\" — dotted quarter (ppq * 1.5 ticks)\n * \"1m\" — one measure (numerator * ppq * 4 / denominator ticks)\n * \"2m\" — two measures\n * \"1:1\" — bar 1, beat 1 (0 ticks; 1-indexed)\n * \"2:1\" — bar 2, beat 1 (1 measure in)\n * \"1:2\" — bar 1, beat 2 (one denominator-defined beat in)\n * \"1:1:48\" — bar 1, beat 1, +48 raw ticks\n * \"1:1.5\" — bar 1, beat 1.5 (fractional beat)\n * 0, 96, 384 — number passthrough (already in ticks)\n */\nexport function parseTicks(\n time: string | number,\n ppq: number,\n timeSignature: TimeSignature,\n): number {\n if (typeof time === \"number\") return time;\n\n const t = time.trim();\n\n // Bare number string: \"0\", \"96\", \"384.5\"\n if (/^\\d+(\\.\\d+)?$/.test(t)) {\n return parseFloat(t);\n }\n\n const beatTicks = ppq * (4 / timeSignature.denominator);\n const barTicks = beatTicks * timeSignature.numerator;\n\n // Measure: \"1m\", \"2m\", \"0.5m\"\n const measureMatch = /^(\\d+(?:\\.\\d+)?)m$/.exec(t);\n if (measureMatch) {\n return parseFloat(measureMatch[1]) * barTicks;\n }\n\n // Note value: \"4n\", \"8n\", \"4n.\" (dotted)\n // Formula: ticks = (4 * ppq) / denominator\n const noteMatch = /^(\\d+(?:\\.\\d+)?)n(\\.?)$/.exec(t);\n if (noteMatch) {\n const denominator = parseFloat(noteMatch[1]);\n const dotted = noteMatch[2] === \".\";\n let ticks = (4 * ppq) / denominator;\n if (dotted) ticks *= 1.5;\n return ticks;\n }\n\n // Position: \"bar:beat\" or \"bar:beat:tick\" (all 1-indexed, can be fractional)\n const posMatch =\n /^(\\d+(?:\\.\\d+)?):(\\d+(?:\\.\\d+)?)(?::(\\d+(?:\\.\\d+)?))?$/.exec(t);\n if (posMatch) {\n const bar = parseFloat(posMatch[1]);\n const beat = parseFloat(posMatch[2]);\n const tick = posMatch[3] ? parseFloat(posMatch[3]) : 0;\n return (bar - 1) * barTicks + (beat - 1) * beatTicks + tick;\n }\n\n throw new Error(`parseTicks: cannot parse \"${time}\"`);\n}\n","/**\n * TransportClock\n *\n * Converts between musical ticks and AudioContext time with support for:\n * - BPM changes mid-playback (via checkpoints)\n * - Pause / resume\n * - Seek to arbitrary tick position\n * - Loop restart (seekAt a future audio time)\n *\n * All time values are in AudioContext seconds (context.currentTime).\n * Ticks are the internal unit: ppq ticks per quarter note.\n *\n * Principle: a Checkpoint records that at a specific audio time, a specific\n * tick position was reached at a specific BPM. Checkpoints are always ordered\n * by audioTime. The conversion functions find the last checkpoint whose\n * audioTime (or tick) is <= the query value and interpolate from there.\n */\n\nexport type TransportState = \"stopped\" | \"playing\" | \"paused\";\n\ntype Checkpoint = {\n /** Musical tick at this anchor point. */\n tick: number;\n /** AudioContext time (seconds) at this anchor point. */\n audioTime: number;\n /** BPM in effect from this checkpoint forward. */\n bpm: number;\n};\n\nimport type { TimeSignature } from \"./sequencer\";\n\nexport type TransportClockOptions = {\n bpm?: number;\n ppq?: number;\n timeSignature?: TimeSignature;\n};\n\nexport class TransportClock {\n private readonly _context: BaseAudioContext;\n\n private _bpm: number;\n readonly ppq: number;\n private _timeSignature: TimeSignature;\n\n private _state: TransportState = \"stopped\";\n private _checkpoints: Checkpoint[] = [];\n private _pausedAtTick = 0;\n\n constructor(context: BaseAudioContext, options: TransportClockOptions = {}) {\n this._context = context;\n this._bpm = options.bpm ?? 120;\n this.ppq = options.ppq ?? 480;\n this._timeSignature = options.timeSignature ?? {\n numerator: 4,\n denominator: 4,\n };\n }\n\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n\n get state(): TransportState {\n return this._state;\n }\n\n // ---------------------------------------------------------------------------\n // BPM / time signature\n // ---------------------------------------------------------------------------\n\n get bpm(): number {\n return this._bpm;\n }\n\n /**\n * Set BPM. If currently playing, inserts a new checkpoint at the current\n * audio time so that all future tick↔time conversions use the new tempo,\n * while already-converted past events remain unaffected.\n */\n set bpm(value: number) {\n if (this._state === \"playing\") {\n const now = this._context.currentTime;\n const tick = this.audioTimeToTick(now);\n this._checkpoints.push({ tick, audioTime: now, bpm: value });\n }\n this._bpm = value;\n }\n\n get timeSignature(): TimeSignature {\n return this._timeSignature;\n }\n\n set timeSignature(value: TimeSignature) {\n this._timeSignature = value;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Start playback. Records a checkpoint at the current audio time.\n * @param offsetTick Musical tick to start from (default 0).\n */\n start(offsetTick = 0): void {\n const audioTime = this._context.currentTime;\n this._checkpoints = [{ tick: offsetTick, audioTime, bpm: this._bpm }];\n this._state = \"playing\";\n }\n\n /**\n * Pause playback. Saves the current tick position so resume can start from\n * the same place.\n */\n pause(): void {\n if (this._state !== \"playing\") return;\n this._pausedAtTick = this.currentTick;\n this._state = \"paused\";\n }\n\n /**\n * Resume from paused. Creates a new checkpoint at the current audio time\n * anchored to the saved tick position.\n */\n resume(): void {\n if (this._state !== \"paused\") return;\n const audioTime = this._context.currentTime;\n this._checkpoints = [\n { tick: this._pausedAtTick, audioTime, bpm: this._bpm },\n ];\n this._state = \"playing\";\n }\n\n /**\n * Stop playback and reset position to 0.\n */\n stop(): void {\n this._checkpoints = [];\n this._pausedAtTick = 0;\n this._state = \"stopped\";\n }\n\n // ---------------------------------------------------------------------------\n // Seek\n // ---------------------------------------------------------------------------\n\n /**\n * Seek to a tick position immediately (at context.currentTime).\n * Replaces all checkpoints with a single new one.\n * Works while playing or paused.\n */\n seek(tick: number): void {\n if (this._state === \"playing\") {\n const audioTime = this._context.currentTime;\n this._checkpoints = [{ tick, audioTime, bpm: this._bpm }];\n } else {\n this._pausedAtTick = tick;\n }\n }\n\n /**\n * Re-anchor: at a specific future audio time, the tick position will jump to\n * `tick`. Used for sample-accurate loop restarts.\n *\n * Any checkpoints at or after `audioTime` are removed and replaced with this\n * new anchor, preserving the BPM that was in effect at that time.\n *\n * @internal Leaks checkpoint-list semantics; only called by `Sequencer._flush`\n * for loop-boundary re-anchoring. Not safe to share between Sequencers — see\n * thoughts/research/2026-05-17_20-18-43_shared-transport.md §3. Must not be\n * exported from any barrel.\n */\n seekAt(tick: number, audioTime: number): void {\n // Find the BPM that will be in effect at audioTime\n let bpm = this._bpm;\n for (const cp of this._checkpoints) {\n if (cp.audioTime <= audioTime) bpm = cp.bpm;\n }\n this._checkpoints = this._checkpoints.filter(\n (cp) => cp.audioTime < audioTime,\n );\n this._checkpoints.push({ tick, audioTime, bpm });\n }\n\n // ---------------------------------------------------------------------------\n // Position\n // ---------------------------------------------------------------------------\n\n /**\n * Current tick position.\n * - While playing: derived from context.currentTime.\n * - While paused or stopped: the saved tick position.\n */\n get currentTick(): number {\n if (this._state === \"playing\") {\n return this.audioTimeToTick(this._context.currentTime);\n }\n return this._pausedAtTick;\n }\n\n // ---------------------------------------------------------------------------\n // Time conversion\n // ---------------------------------------------------------------------------\n\n /**\n * Convert a tick position to an AudioContext time (seconds).\n *\n * Finds the most recent checkpoint (by audioTime) whose tick <= the target\n * tick, then interpolates forward using that checkpoint's BPM.\n *\n * This correctly handles loop restarts: after `seekAt(0, T)`, a new\n * checkpoint with tick=0 is added, so tick=100 in the new iteration maps\n * to T + 100*spt instead of the first-iteration value.\n */\n tickToAudioTime(tick: number): number {\n const cp = this._findCheckpointForTick(tick);\n return cp.audioTime + (tick - cp.tick) * this._secondsPerTick(cp.bpm);\n }\n\n /**\n * Convert an AudioContext time (seconds) to a tick position.\n *\n * Finds the most recent checkpoint (by audioTime) whose audioTime <= the\n * target time, then interpolates forward.\n */\n audioTimeToTick(audioTime: number): number {\n const cp = this._findCheckpointForAudioTime(audioTime);\n return cp.tick + (audioTime - cp.audioTime) / this._secondsPerTick(cp.bpm);\n }\n\n /**\n * Convert a tick count to seconds at the current (snapshot) BPM.\n *\n * Uses `this._bpm` directly, not the checkpoint history — so after a\n * mid-play BPM change this returns a value based on the *latest* BPM only.\n * For checkpoint-aware durations, use `tickToAudioTime(end) - tickToAudioTime(start)`.\n */\n ticksToSeconds(ticks: number): number {\n return ticks * this._secondsPerTick(this._bpm);\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private _secondsPerTick(bpm: number): number {\n return 60 / (bpm * this.ppq);\n }\n\n /**\n * Find the most recent checkpoint (latest audioTime) whose tick <= targetTick.\n * Falls back to a virtual origin checkpoint if none match.\n */\n private _findCheckpointForTick(targetTick: number): Checkpoint {\n let best: Checkpoint | null = null;\n for (const cp of this._checkpoints) {\n if (cp.tick <= targetTick) {\n best = cp;\n // Keep iterating: checkpoints are audioTime-ordered, so later ones\n // with tick <= targetTick are more recent and should win.\n }\n }\n return best ?? this._origin();\n }\n\n /**\n * Find the most recent checkpoint whose audioTime <= targetTime.\n * Falls back to a virtual origin checkpoint if none match.\n */\n private _findCheckpointForAudioTime(targetTime: number): Checkpoint {\n let best: Checkpoint | null = null;\n for (const cp of this._checkpoints) {\n if (cp.audioTime <= targetTime) {\n best = cp;\n }\n }\n return best ?? this._origin();\n }\n\n /** Virtual origin used before start() is called. */\n private _origin(): Checkpoint {\n return { tick: 0, audioTime: 0, bpm: this._bpm };\n }\n}\n","import { asConstructable } from \"../smplr/as-constructable\";\nimport { parseTicks } from \"./time-parser\";\nimport { TransportClock } from \"./transport-clock\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type SequencerNote = {\n /** Optional identifier for this note. Used as `noteId` in noteOn/noteOff events. Defaults to the note's array index. */\n id?: string | number;\n note: string | number;\n /** Musical position: ticks, \"4n\", \"1m\", \"2:1\", \"1:1.5\", etc. */\n at: string | number;\n /** Note duration: ticks, \"4n\", \"8n\", etc. Omit for a one-shot trigger. */\n duration?: string | number;\n velocity?: number;\n /** Probability (0–100) that this note fires on each pass. Default 100 (always). */\n chance?: number;\n /**\n * Expand into N evenly-spaced sub-notes over `duration`. Requires `duration`;\n * silently ignored if `duration` is omitted. Default 1 (no ratchet). When >1,\n * each sub-note's `noteId` is suffixed with `#0`, `#1`, … so individual\n * ratchet voices can be stopped via `stopNote(\"id#0\")`.\n */\n ratchet?: number;\n /**\n * Multiplicative velocity decay per ratchet step: each step's velocity is\n * scaled by `(1 - decay) ** step_index`. 0 = constant, 1 = silence by last\n * step. Default 0.\n */\n ratchetVelocityDecay?: number;\n};\n\n/**\n * Any instrument the Sequencer can drive.\n * Compatible with SplendidGrandPiano, DrumMachine, Smplr, and any object\n * that has a `start()` method accepting note + optional scheduling params.\n */\nexport type SequencerInstrument = {\n start(event: {\n note: string | number;\n time?: number;\n duration?: number;\n velocity?: number;\n noteId?: string | number;\n onStart?: (event: unknown) => void;\n onEnded?: (event: unknown) => void;\n }): unknown;\n};\n\n/** Emitted with \"noteOn\" and \"noteOff\" events. */\nexport type SequencerNoteEvent = {\n noteId: string | number;\n trackIndex: number;\n noteIndex: number;\n note: SequencerNote;\n};\n\n/**\n * Time signature as a `{ numerator, denominator }` pair (e.g. `{ numerator: 7, denominator: 8 }`\n * for 7/8). The numerator counts beats per bar; the denominator defines the\n * note value of one beat (4 = quarter note, 8 = eighth note, …).\n */\nexport type TimeSignature = { numerator: number; denominator: number };\n\n/** Normalise a raw number / TimeSignature / undefined into a TimeSignature. */\nfunction normaliseTimeSignature(\n input: number | TimeSignature | undefined,\n): TimeSignature {\n if (input === undefined) return { numerator: 4, denominator: 4 };\n if (typeof input === \"number\") return { numerator: input, denominator: 4 };\n return input;\n}\n\nexport type SequencerOptions = {\n bpm?: number;\n ppq?: number;\n /** Time signature. Accepts `4` (interpreted as 4/4) or `{ numerator, denominator }`. */\n timeSignature?: number | TimeSignature;\n loop?: boolean;\n loopStart?: string | number;\n loopEnd?: string | number;\n /** How far ahead (ms) to pre-schedule notes. Default 200. */\n lookaheadMs?: number;\n /** How often (ms) the flush loop runs. Default 50. */\n intervalMs?: number;\n /** Randomise timing (ms) and velocity per note for a human feel. */\n humanize?: { timingMs?: number; velocity?: number };\n /** Emit a \"step\" event at this interval. Accepts musical notation or ticks: \"16n\", \"8n\", ticks, etc. */\n stepSize?: string | number;\n};\n\n/**\n * Per-track options accepted by {@link Sequencer.addTrack} and\n * {@link Sequencer.setPatterns}.\n */\nexport type AddTrackOptions = {\n /**\n * Stable track id. Required to address this track via\n * {@link Sequencer.setTrackVolume}, {@link Sequencer.muteTrack},\n * {@link Sequencer.soloTrack}, etc.\n */\n id?: string;\n /** Per-track humanize. Overrides {@link SequencerOptions.humanize} when set. */\n humanize?: { timingMs?: number; velocity?: number };\n /** Multiplicative velocity scalar in [0, 1+]. Default 1. */\n volume?: number;\n /** When true, this track does not dispatch any notes. Default false. */\n muted?: boolean;\n /**\n * When true, only soloed tracks dispatch notes. If any track in the pattern\n * is soloed, every non-soloed track is silenced. Default false.\n */\n solo?: boolean;\n};\n\n/**\n * Public shape for one pattern accepted by {@link Sequencer.setPatterns}.\n */\nexport type PatternInput = {\n tracks: Array<\n {\n instrument: SequencerInstrument;\n notes: SequencerNote[];\n } & AddTrackOptions\n >;\n /**\n * Pattern length override in ticks or musical time. Defaults to the longest\n * track in this pattern.\n */\n loopEnd?: string | number;\n};\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ntype StopFn = (time?: number) => void;\n\ntype Track = {\n instrument: SequencerInstrument;\n notes: SequencerNote[];\n id?: string;\n /** Per-track humanize override; undefined → fall back to the sequencer's global humanize. */\n humanize?: { timing: number; velocity: number };\n volume: number;\n muted: boolean;\n solo: boolean;\n};\n\ntype RepeatEvent = {\n callback: (time: number) => void;\n intervalTicks: number;\n /** Next tick at which this event should fire. Advances after each firing. */\n nextTick: number;\n /** Original start tick, used to reset on loop/seek. */\n startTick: number;\n};\n\ntype Pattern = {\n tracks: Track[];\n /** Pattern length override in ticks; null = default to longest track. */\n loopEndOverride: number | null;\n /** Cached pattern length: max(at + duration) across all tracks. */\n totalTicks: number;\n};\n\n// ---------------------------------------------------------------------------\n// Sequencer\n// ---------------------------------------------------------------------------\n\nclass SequencerImpl {\n private readonly _context: BaseAudioContext;\n private readonly _clock: TransportClock;\n private readonly _ppq: number;\n\n private _timeSignature: TimeSignature;\n private _stepTicks: number | undefined;\n /**\n * Patterns. Always at least one (the implicit default pattern). Replaced\n * atomically by {@link setPatterns}.\n */\n private _patterns: Pattern[] = [\n { tracks: [], loopEndOverride: null, totalTicks: 0 },\n ];\n /** Indices into {@link _patterns} defining playback order. */\n private _chainOrder: number[] = [0];\n /** Current position within {@link _chainOrder}. */\n private _chainIndex = 0;\n /**\n * True once {@link setPatterns} has been called. After this point,\n * `addTrack` / `removeTrack` / `clearTracks` throw because the chain shape\n * is owned by the patterns array.\n */\n private _patternsExplicit = false;\n private _repeatEvents: RepeatEvent[] = [];\n private _listeners: Map<string, Set<(...args: any[]) => void>> = new Map();\n\n // Loop\n private _loop: boolean;\n private _loopStartTick: number;\n\n // Timing\n private _lookaheadSec: number;\n private _intervalMs: number;\n private _humanize: { timing: number; velocity: number };\n\n // Flush loop state\n private _intervalId: ReturnType<typeof setInterval> | undefined;\n /** AudioContext time high-water mark: notes up to here have been scheduled. */\n private _scheduledThrough = 0;\n /** Guards against scheduling the auto-stop setTimeout more than once. */\n private _endScheduled = false;\n /** Active voices keyed by noteId, so individual notes can be stopped. */\n private _activeVoices: Map<string | number, StopFn> = new Map();\n\n constructor(context: BaseAudioContext, options: SequencerOptions = {}) {\n this._context = context;\n this._ppq = options.ppq ?? 480;\n this._timeSignature = normaliseTimeSignature(options.timeSignature);\n\n this._clock = new TransportClock(context, {\n bpm: options.bpm ?? 120,\n ppq: this._ppq,\n timeSignature: this._timeSignature,\n });\n\n this._loop = options.loop ?? false;\n this._loopStartTick =\n options.loopStart !== undefined\n ? parseTicks(options.loopStart, this._ppq, this._timeSignature)\n : 0;\n\n if (options.loopEnd !== undefined) {\n this._patterns[0].loopEndOverride = parseTicks(\n options.loopEnd,\n this._ppq,\n this._timeSignature,\n );\n }\n\n this._stepTicks =\n options.stepSize !== undefined\n ? parseTicks(options.stepSize, this._ppq, this._timeSignature)\n : undefined;\n\n this._lookaheadSec = (options.lookaheadMs ?? 200) / 1000;\n this._intervalMs = options.intervalMs ?? 50;\n this._humanize = {\n timing: options.humanize?.timingMs ?? 0,\n velocity: options.humanize?.velocity ?? 0,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Tracks\n // ---------------------------------------------------------------------------\n\n /**\n * Add a track to the (implicit, default) pattern. Throws after\n * {@link setPatterns} has been called — use {@link setPatterns} to mutate\n * the chain.\n */\n addTrack(\n instrument: SequencerInstrument,\n notes: SequencerNote[],\n options?: AddTrackOptions,\n ): this {\n this._assertImplicitPattern(\"addTrack\");\n const pattern = this._patterns[0];\n pattern.tracks.push(this._buildTrack(instrument, notes, options));\n pattern.totalTicks = this._computePatternTotalTicks(pattern);\n return this;\n }\n\n removeTrack(instrument: SequencerInstrument): this {\n this._assertImplicitPattern(\"removeTrack\");\n const pattern = this._patterns[0];\n pattern.tracks = pattern.tracks.filter((t) => t.instrument !== instrument);\n pattern.totalTicks = this._computePatternTotalTicks(pattern);\n return this;\n }\n\n clearTracks(): this {\n this._assertImplicitPattern(\"clearTracks\");\n const pattern = this._patterns[0];\n pattern.tracks = [];\n pattern.totalTicks = 0;\n return this;\n }\n\n /**\n * Replace the sequencer's patterns. Each pattern owns its own tracks and\n * optional `loopEnd`. After this call, `addTrack` / `removeTrack` /\n * `clearTracks` throw — the chain is owned by the patterns array.\n *\n * `chainOrder` is reset to `[0, 1, …, patterns.length - 1]`.\n */\n setPatterns(patterns: PatternInput[]): this {\n if (patterns.length === 0) {\n throw new Error(\"setPatterns requires at least one pattern\");\n }\n this._patterns = patterns.map((p) => {\n const built: Pattern = {\n tracks: p.tracks.map((t) => this._buildTrack(t.instrument, t.notes, t)),\n loopEndOverride:\n p.loopEnd !== undefined\n ? parseTicks(p.loopEnd, this._ppq, this._timeSignature)\n : null,\n totalTicks: 0,\n };\n built.totalTicks = this._computePatternTotalTicks(built);\n return built;\n });\n this._chainOrder = this._patterns.map((_, i) => i);\n this._chainIndex = 0;\n this._patternsExplicit = true;\n return this;\n }\n\n /** Current chain order: indices into the patterns array, in playback order. */\n get chainOrder(): number[] {\n return [...this._chainOrder];\n }\n\n /**\n * Set a new chain order. Each entry must be a valid pattern index.\n * Throws if `order` is empty or contains an out-of-range index.\n */\n set chainOrder(order: number[]) {\n if (order.length === 0) {\n throw new Error(\"chainOrder must not be empty\");\n }\n for (const idx of order) {\n if (idx < 0 || idx >= this._patterns.length) {\n throw new Error(`chainOrder index ${idx} out of range`);\n }\n }\n this._chainOrder = [...order];\n if (this._chainIndex >= order.length) this._chainIndex = 0;\n }\n\n /**\n * Set a track's multiplicative volume scalar. Affects every note dispatched\n * by the track from the next flush onwards. No-op if no track has the\n * given id. Search is scoped to the currently-playing pattern.\n */\n setTrackVolume(id: string, volume: number): this {\n const t = this._findTrack(id);\n if (t) t.volume = volume;\n return this;\n }\n\n /** Mute a track by id. No-op if no track has the given id. */\n muteTrack(id: string): this {\n return this._setTrackFlag(id, \"muted\", true);\n }\n\n /** Unmute a track by id. No-op if no track has the given id. */\n unmuteTrack(id: string): this {\n return this._setTrackFlag(id, \"muted\", false);\n }\n\n /** Solo a track by id. While any track is soloed, non-soloed tracks are silenced. */\n soloTrack(id: string): this {\n return this._setTrackFlag(id, \"solo\", true);\n }\n\n /** Remove the solo flag from a track. */\n unsoloTrack(id: string): this {\n return this._setTrackFlag(id, \"solo\", false);\n }\n\n /**\n * Locate a track by id, scoped to the currently-playing pattern.\n */\n private _findTrack(id: string): Track | undefined {\n return this._currentPattern().tracks.find((t) => t.id === id);\n }\n\n private _setTrackFlag(\n id: string,\n flag: \"muted\" | \"solo\",\n value: boolean,\n ): this {\n const t = this._findTrack(id);\n if (t) t[flag] = value;\n return this;\n }\n\n private _buildTrack(\n instrument: SequencerInstrument,\n notes: SequencerNote[],\n options?: AddTrackOptions,\n ): Track {\n return {\n instrument,\n notes,\n id: options?.id,\n humanize: options?.humanize\n ? {\n timing: options.humanize.timingMs ?? 0,\n velocity: options.humanize.velocity ?? 0,\n }\n : undefined,\n volume: options?.volume ?? 1,\n muted: options?.muted ?? false,\n solo: options?.solo ?? false,\n };\n }\n\n private _currentPattern(): Pattern {\n return (\n this._patterns[this._chainOrder[this._chainIndex]] ?? this._patterns[0]\n );\n }\n\n private _assertImplicitPattern(method: string): void {\n if (this._patternsExplicit) {\n throw new Error(\n `${method}() is not available after setPatterns(); use setPatterns() to update the chain.`,\n );\n }\n }\n\n private _computePatternTotalTicks(pattern: Pattern): number {\n let max = 0;\n for (const track of pattern.tracks) {\n for (const note of track.notes) {\n const atTick = parseTicks(note.at, this._ppq, this._timeSignature);\n const durTick =\n note.duration !== undefined\n ? parseTicks(note.duration, this._ppq, this._timeSignature)\n : 0;\n max = Math.max(max, atTick + durTick);\n }\n }\n return max;\n }\n\n // ---------------------------------------------------------------------------\n // Playback\n // ---------------------------------------------------------------------------\n\n get state() {\n return this._clock.state;\n }\n\n /**\n * Start playback from `offsetTick`, or resume from pause if no offset given.\n */\n start(offsetTick?: number): this {\n if (this._clock.state === \"playing\") return this;\n\n if (this._clock.state === \"paused\" && offsetTick === undefined) {\n // Resume\n this._clock.resume();\n this._scheduledThrough = this._context.currentTime;\n this._startLoop();\n this._emitStateChange(\"playing\");\n return this;\n }\n\n const startTick = offsetTick ?? 0;\n this._clock.start(startTick);\n this._scheduledThrough = this._context.currentTime;\n this._endScheduled = false;\n this._chainIndex = 0;\n this._resetRepeatEvents(startTick);\n this._startLoop();\n this._emitStateChange(\"playing\");\n return this;\n }\n\n pause(): this {\n if (this._clock.state !== \"playing\") return this;\n this._clock.pause();\n this._stopLoop();\n this._emitStateChange(\"paused\");\n return this;\n }\n\n stop(): this {\n this._clock.stop();\n this._stopLoop();\n this._endScheduled = false;\n for (const stopFn of this._activeVoices.values()) stopFn();\n this._activeVoices.clear();\n this._emitStateChange(\"stopped\");\n return this;\n }\n\n /**\n * Stop a single note that was scheduled by the sequencer.\n * @param noteId The id of the note (from SequencerNote.id or auto-assigned index).\n * @param time Optional AudioContext time to schedule the stop.\n */\n stopNote(noteId: string | number, time?: number): this {\n const stopFn = this._activeVoices.get(noteId);\n if (stopFn) {\n stopFn(time);\n this._activeVoices.delete(noteId);\n }\n return this;\n }\n\n /**\n * Toggle between playing and paused. If stopped, starts from the beginning.\n */\n togglePlayPause(): this {\n if (this._clock.state === \"playing\") return this.pause();\n return this.start();\n }\n\n // ---------------------------------------------------------------------------\n // Tempo\n // ---------------------------------------------------------------------------\n\n get bpm(): number {\n return this._clock.bpm;\n }\n\n set bpm(value: number) {\n this._clock.bpm = value;\n }\n\n get timeSignature(): TimeSignature {\n return { ...this._timeSignature };\n }\n\n set timeSignature(value: number | TimeSignature) {\n this._timeSignature = normaliseTimeSignature(value);\n this._clock.timeSignature = this._timeSignature;\n for (const p of this._patterns) {\n p.totalTicks = this._computePatternTotalTicks(p);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Position\n // ---------------------------------------------------------------------------\n\n /** Current transport position as \"bar:beat:tick\" (1-indexed). */\n get position(): string {\n return this._tickToPosition(this._clock.currentTick);\n }\n\n /**\n * Seek to a position. Accepts ticks or any time string (\"2:1\", \"4n\", …).\n * Works while playing (seamless) or stopped/paused.\n */\n set position(value: string | number) {\n const targetTick = parseTicks(\n String(value),\n this._ppq,\n this._timeSignature,\n );\n this._clock.seek(targetTick);\n if (this._clock.state === \"playing\") {\n this._scheduledThrough = this._context.currentTime;\n this._endScheduled = false;\n this._resetRepeatEvents(targetTick);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Loop\n // ---------------------------------------------------------------------------\n\n get loop(): boolean {\n return this._loop;\n }\n\n set loop(value: boolean) {\n this._loop = value;\n }\n\n /** Loop start in ticks. */\n get loopStart(): number {\n return this._loopStartTick;\n }\n\n set loopStart(value: string | number) {\n this._loopStartTick = parseTicks(\n String(value),\n this._ppq,\n this._timeSignature,\n );\n }\n\n /**\n * Loop end in ticks for the currently-playing pattern. Defaults to the end\n * of the pattern's longest track.\n */\n get loopEnd(): number {\n const p = this._currentPattern();\n return p.loopEndOverride ?? p.totalTicks;\n }\n\n set loopEnd(value: string | number) {\n this._currentPattern().loopEndOverride = parseTicks(\n String(value),\n this._ppq,\n this._timeSignature,\n );\n }\n\n /**\n * Normalised loop position [0, 1]. Always 0 when loop=false.\n */\n get progress(): number {\n if (!this._loop) return 0;\n const loopEnd = this.loopEnd;\n const duration = loopEnd - this._loopStartTick;\n if (duration <= 0) return 0;\n const tick = this._clock.currentTick;\n return Math.max(0, Math.min(1, (tick - this._loopStartTick) / duration));\n }\n\n // ---------------------------------------------------------------------------\n // Callback scheduling (pattern API)\n // ---------------------------------------------------------------------------\n\n /**\n * Schedule a callback to fire on every `interval` while the sequencer plays.\n * Returns a cancel function.\n *\n * @param callback Called with the exact AudioContext time of each firing.\n * @param interval Musical interval: \"4n\", \"8n\", \"1m\", ticks, etc.\n * @param startAt First firing position (default 0 = beginning).\n */\n scheduleRepeat(\n callback: (time: number) => void,\n interval: string | number,\n startAt: string | number = 0,\n ): () => void {\n const intervalTicks = parseTicks(\n String(interval),\n this._ppq,\n this._timeSignature,\n );\n const startTick = parseTicks(\n String(startAt),\n this._ppq,\n this._timeSignature,\n );\n const event: RepeatEvent = {\n callback,\n intervalTicks,\n nextTick: startTick,\n startTick,\n };\n this._repeatEvents.push(event);\n return () => {\n this._repeatEvents = this._repeatEvents.filter((e) => e !== event);\n };\n }\n\n // ---------------------------------------------------------------------------\n // Events\n // ---------------------------------------------------------------------------\n\n /**\n * Listen to a sequencer event.\n *\n * | Event | Args |\n * |-----------------|---------------------------------------------------|\n * | \"statechange\" | (state: \"playing\" \\| \"paused\" \\| \"stopped\") |\n * | \"start\" | |\n * | \"stop\" | |\n * | \"pause\" | |\n * | \"end\" | |\n * | \"loop\" | |\n * | \"patternChange\" | (patternIndex: number, time: number) |\n * | \"beat\" | (beat: number, time: number) |\n * | \"bar\" | (bar: number, time: number) |\n * | \"step\" | (stepIndex: number, time: number) |\n * | \"noteOn\" | (event: SequencerNoteEvent) |\n * | \"noteOff\" | (event: SequencerNoteEvent) |\n */\n on(event: string, callback: (...args: any[]) => void): this {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n this._listeners.get(event)!.add(callback);\n return this;\n }\n\n off(event: string, callback: (...args: any[]) => void): this {\n this._listeners.get(event)?.delete(callback);\n return this;\n }\n\n // ---------------------------------------------------------------------------\n // Private — interval management\n // ---------------------------------------------------------------------------\n\n private _startLoop(): void {\n if (this._intervalId !== undefined) return;\n this._intervalId = setInterval(() => this._flush(), this._intervalMs);\n }\n\n private _stopLoop(): void {\n if (this._intervalId !== undefined) {\n clearInterval(this._intervalId);\n this._intervalId = undefined;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — flush loop (the timing engine)\n // ---------------------------------------------------------------------------\n\n private _flush(): void {\n const now = this._context.currentTime;\n const windowEnd = now + this._lookaheadSec;\n\n const fromTick = this._clock.audioTimeToTick(this._scheduledThrough);\n const toTick = this._clock.audioTimeToTick(windowEnd);\n\n const pattern = this._currentPattern();\n const isMultiPattern = this._chainOrder.length > 1;\n const patternEndTick = pattern.loopEndOverride ?? pattern.totalTicks;\n const isLastInChain = this._chainIndex === this._chainOrder.length - 1;\n // Single-pattern restart uses the configured loopStart; chain patterns\n // always restart from tick 0 of the next pattern.\n const patternStartTick = isMultiPattern ? 0 : this._loopStartTick;\n\n // Cross-boundary: advance chain (or wrap a looping single pattern).\n // Single-pattern + !loop falls through to the auto-stop path below.\n const willAdvance =\n patternEndTick > patternStartTick &&\n toTick >= patternEndTick &&\n (isMultiPattern || this._loop) &&\n !(isLastInChain && !this._loop);\n\n if (willAdvance) {\n // Part 1: notes up to the pattern boundary.\n this._scheduleWindow(fromTick, patternEndTick);\n\n const restartAudioTime = this._clock.tickToAudioTime(patternEndTick);\n\n if (isMultiPattern) {\n this._chainIndex = (this._chainIndex + 1) % this._chainOrder.length;\n this._emit(\n \"patternChange\",\n this._chainOrder[this._chainIndex],\n restartAudioTime,\n );\n // Wrapping the chain back to index 0 also counts as a loop.\n if (this._chainIndex === 0) {\n this._emit(\"loop\");\n }\n } else {\n this._emit(\"loop\");\n }\n\n const nextStartTick = isMultiPattern ? 0 : this._loopStartTick;\n this._clock.seekAt(nextStartTick, restartAudioTime);\n this._resetRepeatEvents(nextStartTick);\n\n // Part 2: overflow into the new pattern within the same window.\n const overflowToTick = this._clock.audioTimeToTick(windowEnd);\n this._scheduleWindow(nextStartTick, overflowToTick);\n\n this._scheduledThrough = windowEnd;\n return;\n }\n\n this._scheduleWindow(fromTick, toTick);\n this._scheduledThrough = windowEnd;\n\n // Auto-stop once we've passed the end of the last pattern in the chain\n // (or the only pattern in non-loop mode). Uses the pattern's loopEnd\n // override when set; otherwise falls back to the longest-track length.\n if (\n !this._loop &&\n !this._endScheduled &&\n isLastInChain &&\n patternEndTick > 0 &&\n toTick >= patternEndTick\n ) {\n this._endScheduled = true;\n const endAudioTime = this._clock.tickToAudioTime(patternEndTick);\n const delay = Math.max(0, (endAudioTime - now) * 1000);\n setTimeout(() => {\n this._stopLoop();\n this._clock.stop();\n this._emit(\"end\");\n this._emit(\"statechange\", \"stopped\");\n }, delay);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — window scheduling\n // ---------------------------------------------------------------------------\n\n private _scheduleWindow(fromTick: number, toTick: number): void {\n // ---- Track notes (current pattern) ----\n const tracks = this._currentPattern().tracks;\n const anySolo = tracks.some((t) => t.solo);\n\n for (let trackIndex = 0; trackIndex < tracks.length; trackIndex++) {\n const track = tracks[trackIndex];\n if (track.muted) continue;\n if (anySolo && !track.solo) continue;\n\n const trackHumanize = track.humanize ?? this._humanize;\n\n for (let noteIndex = 0; noteIndex < track.notes.length; noteIndex++) {\n const note = track.notes[noteIndex];\n const noteTick = parseTicks(note.at, this._ppq, this._timeSignature);\n if (noteTick < fromTick || noteTick >= toTick) continue;\n\n // Chance gate — re-rolled every pass through the scheduler\n if (note.chance !== undefined && note.chance < 100) {\n if (Math.random() * 100 >= note.chance) continue;\n }\n\n const audioTime = this._clock.tickToAudioTime(noteTick);\n const durationSec =\n note.duration !== undefined\n ? this._clock.ticksToSeconds(\n parseTicks(note.duration, this._ppq, this._timeSignature),\n )\n : undefined;\n\n const timingOffset = trackHumanize.timing\n ? ((Math.random() * 2 - 1) * trackHumanize.timing) / 1000\n : 0;\n const velocityOffset = trackHumanize.velocity\n ? Math.round((Math.random() * 2 - 1) * trackHumanize.velocity)\n : 0;\n\n const baseNoteId = note.id ?? noteIndex;\n const noteEvent: SequencerNoteEvent = {\n noteId: baseNoteId,\n trackIndex,\n noteIndex,\n note,\n };\n\n const ratchetCount =\n note.ratchet && note.ratchet > 1 && durationSec !== undefined\n ? Math.floor(note.ratchet)\n : 1;\n const ratchetDecay = note.ratchetVelocityDecay ?? 0;\n const ratchetStepSec =\n ratchetCount > 1 && durationSec !== undefined\n ? durationSec / ratchetCount\n : 0;\n const ratchetDurationSec =\n ratchetCount > 1 ? ratchetStepSec : durationSec;\n\n for (let r = 0; r < ratchetCount; r++) {\n const ratchetOffsetSec = r * ratchetStepSec;\n const ratchetVelocityScale =\n ratchetCount > 1 ? Math.pow(1 - ratchetDecay, r) : 1;\n const subNoteId =\n ratchetCount > 1 ? `${baseNoteId}#${r}` : baseNoteId;\n\n const result = track.instrument.start({\n note: note.note,\n time: Math.max(0, audioTime + timingOffset + ratchetOffsetSec),\n duration: ratchetDurationSec,\n velocity:\n (note.velocity ?? 100) * track.volume * ratchetVelocityScale +\n velocityOffset,\n noteId: subNoteId,\n onStart: () => this._emit(\"noteOn\", noteEvent),\n onEnded: () => {\n this._activeVoices.delete(subNoteId);\n this._emit(\"noteOff\", noteEvent);\n },\n });\n\n // Capture the stop function if the instrument returns one\n if (typeof result === \"function\") {\n this._activeVoices.set(subNoteId, result as StopFn);\n }\n }\n }\n }\n\n // ---- Repeat events (callback API) ----\n for (const rep of this._repeatEvents) {\n while (rep.nextTick >= fromTick && rep.nextTick < toTick) {\n rep.callback(this._clock.tickToAudioTime(rep.nextTick));\n rep.nextTick += rep.intervalTicks;\n }\n }\n\n // ---- Beat / bar events ----\n this._emitBeatsInWindow(fromTick, toTick);\n\n // ---- Step events ----\n this._emitStepsInWindow(fromTick, toTick);\n }\n\n // ---------------------------------------------------------------------------\n // Private — beat / bar events\n // ---------------------------------------------------------------------------\n\n private _emitStepsInWindow(fromTick: number, toTick: number): void {\n if (!this._stepTicks) return;\n const firstStep =\n Math.ceil((fromTick - 0.001) / this._stepTicks) * this._stepTicks;\n for (let t = firstStep; t < toTick; t += this._stepTicks) {\n if (t < 0) continue;\n const stepIndex = Math.floor(t / this._stepTicks);\n const audioTime = this._clock.tickToAudioTime(t);\n this._emit(\"step\", stepIndex, audioTime);\n }\n }\n\n private _emitBeatsInWindow(fromTick: number, toTick: number): void {\n const beatTicks = this._ppq * (4 / this._timeSignature.denominator);\n const barTicks = beatTicks * this._timeSignature.numerator;\n\n // Small tolerance so floating-point drift doesn't skip a beat at tick=0.\n const firstBeat = Math.ceil((fromTick - 0.001) / beatTicks) * beatTicks;\n\n for (let t = firstBeat; t < toTick; t += beatTicks) {\n if (t < 0) continue;\n const audioTime = this._clock.tickToAudioTime(t);\n // 1-indexed absolute beat number from the start of the score.\n const beat = Math.floor(t / beatTicks) + 1;\n this._emit(\"beat\", beat, audioTime);\n if (t % barTicks === 0) {\n const bar = Math.floor(t / barTicks) + 1;\n this._emit(\"bar\", bar, audioTime);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private — utilities\n // ---------------------------------------------------------------------------\n\n private _emit(event: string, ...args: any[]): void {\n const handlers = this._listeners.get(event);\n if (handlers) {\n for (const fn of handlers) {\n fn(...args);\n }\n }\n }\n\n /** Emit both the specific state event (\"start\"/\"pause\"/\"stop\") and the unified \"statechange\" event. */\n private _emitStateChange(state: \"playing\" | \"paused\" | \"stopped\"): void {\n const eventName =\n state === \"playing\" ? \"start\" : state === \"paused\" ? \"pause\" : \"stop\";\n this._emit(eventName);\n this._emit(\"statechange\", state);\n }\n\n /** Format a raw tick count as \"bar:beat:tick\" (all 1-indexed). */\n private _tickToPosition(tick: number): string {\n const beatTicks = this._ppq * (4 / this._timeSignature.denominator);\n const barTicks = beatTicks * this._timeSignature.numerator;\n const bar = Math.floor(tick / barTicks) + 1;\n const ticksInBar = tick % barTicks;\n const beat = Math.floor(ticksInBar / beatTicks) + 1;\n const ticksInBeat = Math.round(ticksInBar % beatTicks);\n return `${bar}:${beat}:${ticksInBeat}`;\n }\n\n /**\n * Reset all repeat events so their next firing is the first occurrence\n * at or after `fromTick`.\n */\n private _resetRepeatEvents(fromTick: number): void {\n for (const rep of this._repeatEvents) {\n rep.nextTick = rep.startTick;\n if (fromTick > rep.startTick && rep.intervalTicks > 0) {\n const steps = Math.ceil((fromTick - rep.startTick) / rep.intervalTicks);\n rep.nextTick = rep.startTick + steps * rep.intervalTicks;\n }\n }\n }\n}\n\nexport const Sequencer = asConstructable(SequencerImpl);\nexport type Sequencer = ReturnType<typeof Sequencer>;\n","import { toMidi } from \"./midi\";\nimport { SmplrGroup, SmplrPreset, SmplrRegion } from \"./types\";\n\nexport type SfzConvertOptions = {\n /** Base URL prepended to all sample paths. */\n baseUrl: string;\n /**\n * Transform a raw SFZ sample path (e.g. \"Arco\\\\C4.wav\") to a SmplrPreset\n * relative path WITHOUT the audio extension (e.g. \"Arco/C4\").\n * The SampleLoader will append \".<format>\" when building the final URL.\n */\n pathFromSampleName: (name: string) => string;\n /** Audio formats in preference order. Defaults to [\"ogg\", \"m4a\"]. */\n formats?: string[];\n};\n\n/**\n * Parse SFZ text and convert to a SmplrPreset descriptor.\n *\n * Handles both inline format (`<region> sample=foo.wav lokey=60`)\n * and multi-line format (headers on their own line, opcodes below).\n *\n * Fixes the \"dropped final region\" bug present in sfz2.ts by ensuring\n * the last scope is always closed.\n *\n * @internal Not part of the public 1.0 API surface.\n */\nexport function sfzToPreset(\n sfzText: string,\n options: SfzConvertOptions,\n): SmplrPreset {\n const formats = options.formats ?? [\"ogg\", \"m4a\"];\n\n // Resolve #define preprocessor directives before tokenizing\n const tokens = tokenize(resolveDefines(sfzText));\n\n // State machine\n type Mode = \"global\" | \"group\" | \"region\";\n let mode: Mode = \"global\";\n\n const globalProps: Record<string, string | number> = {};\n let groupProps: Record<string, string | number> = {};\n let regionProps: Record<string, string | number> = {};\n\n const groups: SmplrGroup[] = [];\n let currentGroup: SmplrGroup | null = null;\n\n function closeScope() {\n if (mode === \"global\") {\n Object.assign(globalProps, regionProps);\n } else if (mode === \"group\") {\n groupProps = { ...regionProps };\n // Build a new SmplrGroup from groupProps\n currentGroup = buildGroup(groupProps);\n groups.push(currentGroup);\n } else if (mode === \"region\") {\n // Merge: global → group → region\n const merged = { ...globalProps, ...groupProps, ...regionProps };\n const region = buildRegion(merged, options.pathFromSampleName);\n if (region) {\n // Ensure we have a current group\n if (!currentGroup) {\n currentGroup = { regions: [] };\n groups.push(currentGroup);\n }\n currentGroup.regions.push(region);\n }\n }\n regionProps = {};\n }\n\n for (const token of tokens) {\n if (token.type === \"header\") {\n closeScope();\n mode = token.value as Mode;\n if (mode === \"group\") {\n // New group scope\n groupProps = {};\n currentGroup = null;\n }\n } else {\n regionProps[token.key] = token.value;\n }\n }\n\n // Close the final scope\n closeScope();\n\n // Filter out empty groups\n const nonEmptyGroups = groups.filter((g) => g.regions.length > 0);\n\n return {\n samples: {\n baseUrl: options.baseUrl,\n formats,\n },\n groups: nonEmptyGroups,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Group / Region builders\n// ---------------------------------------------------------------------------\n\nfunction buildGroup(props: Record<string, string | number>): SmplrGroup {\n const group: SmplrGroup = { regions: [] };\n\n const lokey = num(props, \"lokey\");\n const hikey = num(props, \"hikey\");\n if (lokey !== undefined && hikey !== undefined) {\n group.keyRange = [lokey, hikey];\n }\n\n const lovel = num(props, \"lovel\");\n const hivel = num(props, \"hivel\");\n if (lovel !== undefined && hivel !== undefined) {\n group.velRange = [lovel, hivel];\n }\n\n const seqLength = num(props, \"seq_length\");\n if (seqLength !== undefined) group.seqLength = seqLength;\n\n const groupNum = num(props, \"group\");\n if (groupNum !== undefined) group.group = groupNum;\n\n const offBy = num(props, \"off_by\");\n if (offBy !== undefined) group.offBy = offBy;\n\n const volume = num(props, \"volume\");\n if (volume !== undefined) group.volume = volume;\n\n const ampRelease = num(props, \"ampeg_release\");\n if (ampRelease !== undefined) group.ampRelease = ampRelease;\n\n const tune = num(props, \"tune\");\n if (tune !== undefined) group.tune = tune / 100; // SFZ tune is in cents, convert to semitones\n\n return group;\n}\n\nfunction buildRegion(\n props: Record<string, string | number>,\n pathFromSampleName: (name: string) => string,\n): SmplrRegion | null {\n const sampleRaw = str(props, \"sample\");\n if (!sampleRaw) return null;\n\n const sample = pathFromSampleName(sampleRaw);\n const region: SmplrRegion = { sample };\n\n // Key range\n const key = num(props, \"key\");\n if (key !== undefined) {\n region.key = key;\n } else {\n const lokey = num(props, \"lokey\");\n const hikey = num(props, \"hikey\");\n if (lokey !== undefined && hikey !== undefined) {\n region.keyRange = [lokey, hikey];\n }\n }\n\n // Pitch\n const pitchKeycenter = num(props, \"pitch_keycenter\");\n if (pitchKeycenter !== undefined) {\n region.pitch = pitchKeycenter;\n } else if (region.keyRange) {\n // Fall back to lokey as pitch if pitch_keycenter absent\n region.pitch = region.keyRange[0];\n } else if (key !== undefined) {\n region.pitch = key;\n }\n\n // Velocity range\n const lovel = num(props, \"lovel\");\n const hivel = num(props, \"hivel\");\n if (lovel !== undefined && hivel !== undefined) {\n region.velRange = [lovel, hivel];\n }\n\n // Round-robin\n const seqPosition = num(props, \"seq_position\");\n if (seqPosition !== undefined) region.seqPosition = seqPosition;\n\n // Exclusive groups\n const groupNum = num(props, \"group\");\n if (groupNum !== undefined) region.group = groupNum;\n\n const offBy = num(props, \"off_by\");\n if (offBy !== undefined) region.offBy = offBy;\n\n // Volume (dB)\n const volume = num(props, \"volume\");\n if (volume !== undefined) region.volume = volume;\n\n // Tune (SFZ cents → semitones)\n const tune = num(props, \"tune\");\n if (tune !== undefined) region.tune = tune / 100;\n\n // Amplitude release\n const ampRelease = num(props, \"ampeg_release\");\n if (ampRelease !== undefined) region.ampRelease = ampRelease;\n\n // Velocity curve\n const ampVelcurve = numArr(props, \"amp_velcurve\");\n if (ampVelcurve) region.ampVelCurve = ampVelcurve;\n\n return region;\n}\n\n// ---------------------------------------------------------------------------\n// Preprocessor — resolve #define directives\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve `#define $VAR value` directives by replacing all `$VAR` occurrences\n * in the text and stripping the directive lines.\n */\nfunction resolveDefines(sfz: string): string {\n const defines: Record<string, string> = {};\n const lines = sfz.split(\"\\n\");\n const output: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n const match = trimmed.match(/^#define\\s+(\\$\\w+)\\s+(.+)$/);\n if (match) {\n defines[match[1]] = match[2].trim();\n } else {\n output.push(line);\n }\n }\n\n let result = output.join(\"\\n\");\n for (const [key, value] of Object.entries(defines)) {\n // Escape $ for regex and replace all occurrences\n result = result.split(key).join(value);\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Tokenizer\n// ---------------------------------------------------------------------------\n\ntype HeaderToken = { type: \"header\"; value: string };\ntype PropToken = { type: \"prop\"; key: string; value: string | number };\ntype Token = HeaderToken | PropToken;\n\n/**\n * Tokenize SFZ text into a flat list of header or prop tokens.\n *\n * Handles:\n * - `// line comments`\n * - `<header>` — may appear inline or on own line\n * - `key=value` pairs — multiple per line, value may be a path (no spaces)\n */\nfunction tokenize(sfz: string): Token[] {\n const tokens: Token[] = [];\n\n for (let line of sfz.split(\"\\n\")) {\n // Strip line comments\n const commentIdx = line.indexOf(\"//\");\n if (commentIdx >= 0) line = line.slice(0, commentIdx);\n line = line.trim();\n if (!line) continue;\n\n // Process the line chunk by chunk\n let pos = 0;\n while (pos < line.length) {\n // Skip leading whitespace\n while (pos < line.length && line[pos] === \" \") pos++;\n if (pos >= line.length) break;\n\n // Header: <something>\n if (line[pos] === \"<\") {\n const end = line.indexOf(\">\", pos);\n if (end < 0) break;\n const headerName = line\n .slice(pos + 1, end)\n .trim()\n .toLowerCase();\n tokens.push({ type: \"header\", value: headerName });\n pos = end + 1;\n continue;\n }\n\n // Key=value: find the next = sign\n const eqIdx = line.indexOf(\"=\", pos);\n if (eqIdx < 0) break;\n\n const key = line.slice(pos, eqIdx).trim();\n\n // Value: read until next whitespace (for simple values) or next key=\n // We read until whitespace, but if the next token also looks like key=,\n // we stop there.\n let valueEnd = eqIdx + 1;\n // Find the end of the value: either end of line or the start of the next key=\n // Strategy: find next whitespace-preceded word that contains '='\n const rest = line.slice(eqIdx + 1);\n const nextKeyMatch = rest.match(/\\s+\\S+=\\S/);\n let rawValue: string;\n if (nextKeyMatch && nextKeyMatch.index !== undefined) {\n rawValue = rest.slice(0, nextKeyMatch.index).trim();\n valueEnd =\n eqIdx +\n 1 +\n nextKeyMatch.index +\n nextKeyMatch[0].length -\n nextKeyMatch[0].trimStart().length;\n } else {\n rawValue = rest.trim();\n valueEnd = line.length;\n }\n\n if (key && rawValue !== undefined) {\n const numVal = Number(rawValue);\n tokens.push({\n type: \"prop\",\n key,\n value: isNaN(numVal) ? rawValue : numVal,\n });\n }\n\n pos = valueEnd;\n }\n }\n\n return tokens;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction num(\n props: Record<string, string | number>,\n key: string,\n): number | undefined {\n const v = props[key];\n if (typeof v === \"number\") return v;\n return undefined;\n}\n\nfunction str(\n props: Record<string, string | number>,\n key: string,\n): string | undefined {\n const v = props[key];\n if (typeof v === \"string\") return v;\n return undefined;\n}\n\nfunction numArr(\n props: Record<string, string | number>,\n _prefix: string,\n): [number, number] | undefined {\n // SFZ amp_velcurve_N=V format: key is amp_velcurve_<velocity>\n for (const [k, v] of Object.entries(props)) {\n if (k.startsWith(\"amp_velcurve_\")) {\n const vel = Number(k.slice(\"amp_velcurve_\".length));\n if (!isNaN(vel) && typeof v === \"number\") {\n return [vel, v];\n }\n }\n }\n return undefined;\n}\n","import { AudioInsert } from \"./smplr/connect\";\nimport { Subscribe } from \"./smplr/signals\";\n\n// @private\nexport function createTremolo(\n context: BaseAudioContext,\n depth: Subscribe<number>,\n): AudioInsert {\n const input = context.createGain();\n const output = context.createGain();\n\n // force mono sources to be stereo\n input.channelCount = 2;\n input.channelCountMode = \"explicit\";\n\n const splitter = context.createChannelSplitter(2);\n const ampL = context.createGain();\n const ampR = context.createGain();\n const merger = context.createChannelMerger(2);\n\n const lfoL = context.createOscillator();\n lfoL.type = \"sine\";\n lfoL.frequency.value = 1;\n lfoL.start();\n const lfoLAmp = context.createGain();\n const lfoR = context.createOscillator();\n lfoR.type = \"sine\";\n lfoR.frequency.value = 1.1;\n lfoR.start();\n const lfoRAmp = context.createGain();\n\n input.connect(splitter);\n splitter.connect(ampL, 0);\n splitter.connect(ampR, 1);\n ampL.connect(merger, 0, 0);\n ampR.connect(merger, 0, 1);\n lfoL.connect(lfoLAmp);\n lfoLAmp.connect(ampL.gain);\n lfoR.connect(lfoRAmp);\n lfoRAmp.connect(ampR.gain);\n merger.connect(output);\n\n const unsubscribe = depth((depth) => {\n lfoLAmp.gain.value = depth;\n lfoRAmp.gain.value = depth;\n });\n\n input.disconnect = () => {\n unsubscribe();\n lfoL.stop();\n lfoR.stop();\n input.disconnect(splitter);\n splitter.disconnect(ampL, 0);\n splitter.disconnect(ampR, 1);\n ampL.disconnect(merger, 0, 0);\n ampR.disconnect(merger, 0, 1);\n lfoL.disconnect(lfoLAmp);\n lfoLAmp.disconnect(ampL.gain);\n lfoR.disconnect(lfoRAmp);\n lfoRAmp.disconnect(ampR.gain);\n merger.disconnect(output);\n };\n\n return { input, output };\n}\n","import { Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress } from \"./smplr/types\";\nimport { sfzToPreset } from \"./smplr/sfz-convert\";\nimport { createControl } from \"./smplr/signals\";\nimport { midiVelToGain } from \"./smplr/volume\";\nimport { createTremolo } from \"./tremolo\";\n\nexport function getElectricPianoNames() {\n return Object.keys(INSTRUMENTS);\n}\n\ntype InstrumentConfig = {\n sfzUrl: string;\n baseUrl: string;\n pathFromSampleName: (name: string) => string;\n};\n\n/** Strip file extension and prepend samples/ (Greg Sullivan pianos) */\nfunction gsPath(name: string): string {\n return \"samples/\" + name.replace(/\\.\\w+$/, \"\");\n}\n\n/** Strip file extension (VCSL instruments) */\nfunction vcslPath(name: string): string {\n return name.replace(/\\.\\w+$/, \"\");\n}\n\nconst GS_BASE =\n \"https://smpldsnds.github.io/sfzinstruments-greg-sullivan-e-pianos\";\n\nconst INSTRUMENTS: Record<string, InstrumentConfig> = {\n CP80: {\n sfzUrl: `${GS_BASE}/cp80/CP80.sfz`,\n baseUrl: `${GS_BASE}/cp80`,\n pathFromSampleName: gsPath,\n },\n PianetT: {\n sfzUrl: `${GS_BASE}/planet-t/Pianet T.sfz`,\n baseUrl: `${GS_BASE}/planet-t`,\n pathFromSampleName: gsPath,\n },\n WurlitzerEP200: {\n sfzUrl: `${GS_BASE}/wurlitzer-ep200/Wurlitzer EP200.sfz`,\n baseUrl: `${GS_BASE}/wurlitzer-ep200`,\n pathFromSampleName: gsPath,\n },\n TX81Z: {\n sfzUrl:\n \"https://smpldsnds.github.io/sgossner-vcsl/Electrophones/TX81Z - FM Piano.sfz\",\n baseUrl: \"https://smpldsnds.github.io/sgossner-vcsl/Electrophones\",\n pathFromSampleName: vcslPath,\n },\n};\n\nexport type ElectricPianoOptions = Partial<{\n instrument: string;\n storage: Storage;\n destination: AudioNode;\n volume: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan: number;\n velocity: number;\n onLoadProgress: (progress: LoadProgress) => void;\n /** Audio formats to try, in order of preference. Defaults to [\"ogg\", \"m4a\"]. */\n formats: string[];\n}>;\n\ntype ElectricPianoExtras = {\n tremolo: Readonly<{ level: (value: number) => void }>;\n};\n\nexport const ElectricPiano = Instrument(\n (\n ctx: BaseAudioContext,\n options: ElectricPianoOptions & { instrument: string },\n smplr,\n ) => {\n const config = INSTRUMENTS[options.instrument];\n if (!config) {\n throw new Error(\n `Unknown electric piano: \"${options.instrument}\". ` +\n `Valid names: ${Object.keys(INSTRUMENTS).join(\", \")}`,\n );\n }\n\n // Tremolo control + insert node — sync, so `tremolo.level(...)` is\n // callable before `await load` resolves.\n const depth = createControl(0);\n const tremolo: ElectricPianoExtras[\"tremolo\"] = {\n level: (level) => depth.set(midiVelToGain(level)),\n };\n const tremoloNode = createTremolo(ctx, depth.subscribe);\n smplr.output.addInsert(tremoloNode);\n\n const ready = fetch(config.sfzUrl)\n .then((r) => r.text())\n .then((sfzText) =>\n smplr.loadInstrument(\n sfzToPreset(sfzText, {\n baseUrl: config.baseUrl,\n pathFromSampleName: config.pathFromSampleName,\n formats: options.formats ?? [\"ogg\", \"m4a\"],\n }),\n ),\n );\n\n return { extras: { tremolo }, ready };\n },\n);\n\n/** Instance type returned by the {@link ElectricPiano} factory. */\nexport type ElectricPiano = ReturnType<typeof ElectricPiano>;\n","import { Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport type { PluginSmplr } from \"./smplr/instrument\";\nimport { LoadProgress } from \"./smplr/types\";\nimport { sfzToPreset } from \"./smplr/sfz-convert\";\n\nconst VCSL_BASE_URL = \"https://smpldsnds.github.io/sgossner-vcsl\";\n\nlet instrumentsPromise: Promise<string[]> | undefined;\n\nexport function getVersilianInstruments(): Promise<string[]> {\n return (instrumentsPromise ??= fetch(\n VCSL_BASE_URL + \"/sfz_files.json\",\n ).then((res) => res.json()));\n}\n\nexport type VersilianConfig = {\n instrument: string;\n storage: Storage;\n};\n\nexport type VersilianOptions = Partial<\n VersilianConfig & {\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\n/**\n * Versilian\n *\n * The Versilian Community Sample Library is an open CC0 general-purpose sample\n * library created by Versilian Studios LLC.\n */\nexport const Versilian = Instrument(\n (ctx: BaseAudioContext, options: VersilianOptions = {}, smplr) =>\n loadVersilianInstrument(smplr, options),\n);\n\n/** Instance type returned by the {@link Versilian} factory. */\nexport type Versilian = ReturnType<typeof Versilian>;\n\n/**\n * Fetch the SFZ for a VCSL instrument and load it into `smplr`. Shared by\n * the {@link Versilian} and {@link Mallet} factories — not exported from the\n * package barrel.\n */\nexport function loadVersilianInstrument(\n smplr: PluginSmplr,\n options: VersilianOptions,\n): Promise<void> {\n const instrument = options.instrument ?? \"Strings/Violin/Violin - Arco\";\n const sfzUrl = `${VCSL_BASE_URL}/${instrument}.sfz`;\n const base = instrument.slice(0, instrument.lastIndexOf(\"/\") + 1);\n const sampleBaseUrl = `${VCSL_BASE_URL}/${base}`;\n\n return fetch(sfzUrl)\n .then((r) => r.text())\n .then((sfzText) =>\n smplr.loadInstrument(\n sfzToPreset(sfzText, {\n baseUrl: sampleBaseUrl,\n pathFromSampleName: (name) => name.replace(/\\.wav$/i, \"\"),\n formats: [\"ogg\", \"m4a\"],\n }),\n ),\n );\n}\n","import { Instrument } from \"./smplr\";\nimport { loadVersilianInstrument, VersilianOptions } from \"./versilian\";\n\nexport function getMalletNames(): string[] {\n return Object.keys(NAME_TO_PATH);\n}\n\nexport const Mallet = Instrument(\n (ctx: BaseAudioContext, options: VersilianOptions = {}, smplr) =>\n loadVersilianInstrument(smplr, {\n ...options,\n instrument: NAME_TO_PATH[options.instrument ?? \"\"],\n }),\n);\n\n/** Instance type returned by the {@link Mallet} factory. */\nexport type Mallet = ReturnType<typeof Mallet>;\n\ntype MalletName = keyof typeof NAME_TO_PATH;\n\nexport const NAME_TO_PATH: Record<string, string | undefined> = {\n \"Balafon - Hard Mallet\": \"Idiophones/Struck Idiophones/Balafon - Hard Mallet\",\n \"Balafon - Keyswitch\": \"Idiophones/Struck Idiophones/Balafon - Keyswitch\",\n \"Balafon - Soft Mallet\": \"Idiophones/Struck Idiophones/Balafon - Soft Mallet\",\n \"Balafon - Traditional Mallet\":\n \"Idiophones/Struck Idiophones/Balafon - Traditional Mallet\",\n\n \"Tubular Bells 1\": \"Idiophones/Struck Idiophones/Tubular Bells 1\",\n \"Tubular Bells 2\": \"Idiophones/Struck Idiophones/Tubular Bells 2\",\n\n \"Vibraphone - Bowed\": \"Idiophones/Struck Idiophones/Vibraphone - Bowed\",\n \"Vibraphone - Hard Mallets\":\n \"Idiophones/Struck Idiophones/Vibraphone - Hard Mallets\",\n \"Vibraphone - Keyswitch\":\n \"Idiophones/Struck Idiophones/Vibraphone - Keyswitch\",\n \"Vibraphone - Soft Mallets\":\n \"Idiophones/Struck Idiophones/Vibraphone - Soft Mallets\",\n\n \"Xylophone - Hard Mallets\":\n \"Idiophones/Struck Idiophones/Xylophone - Hard Mallets\",\n \"Xylophone - Keyswitch\": \"Idiophones/Struck Idiophones/Xylophone - Keyswitch\",\n \"Xylophone - Medium Mallets\":\n \"Idiophones/Struck Idiophones/Xylophone - Medium Mallets\",\n \"Xylophone - Soft Mallets\":\n \"Idiophones/Struck Idiophones/Xylophone - Soft Mallets\",\n} as const;\n","/**\n * Given a list of [midi, sampleName] pairs, return one entry per sample with\n * a keyRange that covers all MIDI notes closer to that sample than to any\n * neighbour. The first sample extends down to 0; the last extends up to 127.\n *\n * The boundary between two adjacent samples A and B (A < B) is placed at\n * `floor((A + B) / 2)`, matching the behaviour of the old `findNearestMidiInLayer`\n * which always resolved ties in favour of the lower sample.\n */\n/** @internal Not part of the public 1.0 API surface. */\nexport type SpreadResult = {\n keyRange: [number, number];\n pitch: number;\n sample: string;\n};\n\n/** @internal Not part of the public 1.0 API surface. */\nexport function spreadKeyRanges(samples: [number, string][]): SpreadResult[] {\n if (samples.length === 0) return [];\n\n // Work on a sorted copy — caller order doesn't matter\n const sorted = [...samples].sort(([a], [b]) => a - b);\n\n return sorted.map(([midi, name], i) => {\n const low = i === 0 ? 0 : Math.floor((sorted[i - 1][0] + midi) / 2) + 1;\n\n const high =\n i === sorted.length - 1 ? 127 : Math.floor((midi + sorted[i + 1][0]) / 2);\n\n return {\n keyRange: [low, high] as [number, number],\n pitch: midi,\n sample: name,\n };\n });\n}\n","import { toMidi } from \"./smplr/midi\";\nimport { Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress, SmplrGroup, SmplrPreset } from \"./smplr/types\";\nimport { spreadKeyRanges } from \"./smplr/utils\";\n\nconst INSTRUMENT_VARIATIONS: Record<string, [string, string]> = {\n \"300 STRINGS CELLO\": [\"300 STRINGS\", \"CELL\"],\n \"300 STRINGS VIOLA\": [\"300 STRINGS\", \"VIOL\"],\n};\n\nexport function getMellotronNames() {\n return [\n \"300 STRINGS CELLO\",\n \"300 STRINGS VIOLA\",\n \"8VOICE CHOIR\",\n \"BASSA+STRNGS\",\n \"BOYS CHOIR\",\n \"CHA CHA FLT\",\n \"CHM CLARINET\",\n \"CHMB 3 VLNS\",\n \"CHMB ALTOSAX\",\n \"CHMB FEMALE\",\n \"CHMB MALE VC\",\n \"CHMB TNR SAX\",\n \"CHMB TRMBONE\",\n \"CHMB TRUMPET\",\n \"CHMBLN CELLO\",\n \"CHMBLN FLUTE\",\n \"CHMBLN OBOE\",\n \"DIXIE+TRMBN\",\n \"FOXTROT+SAX\",\n \"HALFSP.BRASS\",\n \"MIXED STRGS\",\n \"MKII BRASS\",\n \"MKII GUITAR\",\n \"MKII ORGAN\",\n \"MKII SAX\",\n \"MKII VIBES\",\n \"MKII VIOLINS\",\n \"MOVE BS+STGS\",\n \"STRGS+BRASS\",\n \"TROMB+TRMPT\",\n \"TRON 16VLNS\",\n \"TRON CELLO\",\n \"TRON FLUTE\",\n \"TRON VIOLA\",\n ];\n}\n\nexport type MellotronConfig = {\n instrument: string;\n storage: Storage;\n};\n\nexport type MellotronOptions = Partial<\n MellotronConfig & {\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n decayTime?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nexport const Mellotron = Instrument(\n (ctx: BaseAudioContext, options: MellotronOptions = {}, smplr) => {\n const instrument = options.instrument ?? \"MKII VIOLINS\";\n const variation = INSTRUMENT_VARIATIONS[instrument];\n const instrumentName = variation ? variation[0] : instrument;\n const baseUrl = `https://smpldsnds.github.io/archiveorg-mellotron/${instrumentName}/`;\n\n return fetch(baseUrl + \"files.json\")\n .then((r) => r.json() as Promise<string[]>)\n .then((names) =>\n smplr.loadInstrument(\n mellotronToPreset(names, {\n instrument: instrumentName,\n variation: variation?.[1],\n }),\n ),\n );\n },\n);\n\n/** Instance type returned by the {@link Mellotron} factory. */\nexport type Mellotron = ReturnType<typeof Mellotron>;\n\n// ---------------------------------------------------------------------------\n// mellotronToPreset — pure converter function\n// ---------------------------------------------------------------------------\n\ntype MellotronJsonConfig = {\n instrument: string;\n variation?: string;\n};\n\n/**\n * Convert a Mellotron files.json sample list to SmplrPreset.\n *\n * - Filters by variation string if provided.\n * - Extracts MIDI from the first word of each sample name.\n * - Uses spreadKeyRanges so nearby notes pitch-shift to the nearest sample.\n * - All regions get loopAuto to produce tape-loop playback.\n */\nexport function mellotronToPreset(\n sampleNames: string[],\n config: MellotronJsonConfig,\n): SmplrPreset {\n const entries: [number, string][] = [];\n\n for (const sampleName of sampleNames) {\n // Filter by variation (e.g., only \"CELL\" samples for CELLO variation)\n if (config.variation && !sampleName.includes(config.variation)) continue;\n\n const midi = toMidi(sampleName.split(\" \")[0] ?? \"\");\n if (midi === undefined) continue;\n\n entries.push([midi, sampleName]);\n }\n\n const spread = spreadKeyRanges(entries);\n const baseUrl = `https://smpldsnds.github.io/archiveorg-mellotron/${config.instrument}/`;\n\n const regions: SmplrGroup[\"regions\"] = spread.map(\n ({ keyRange, pitch, sample }) => ({\n sample,\n keyRange,\n pitch,\n loopAuto: { startRatio: 0.1, endRatio: 0.9 },\n }),\n );\n\n return {\n samples: {\n baseUrl,\n formats: [\"ogg\", \"m4a\"],\n },\n groups: [{ regions }],\n };\n}\n","export const PROCESSOR = `\"use strict\";(()=>{var f=class extends AudioWorkletProcessor{_pDLength;_preDelay;_pDWrite;_lp1;_lp2;_lp3;_excPhase;_taps;_Delays;sampleRate;static get parameterDescriptors(){return[[\"preDelay\",0,0,sampleRate-1,\"k-rate\"],[\"bandwidth\",.9999,0,1,\"k-rate\"],[\"inputDiffusion1\",.75,0,1,\"k-rate\"],[\"inputDiffusion2\",.625,0,1,\"k-rate\"],[\"decay\",.5,0,1,\"k-rate\"],[\"decayDiffusion1\",.7,0,.999999,\"k-rate\"],[\"decayDiffusion2\",.5,0,.999999,\"k-rate\"],[\"damping\",.005,0,1,\"k-rate\"],[\"excursionRate\",.5,0,2,\"k-rate\"],[\"excursionDepth\",.7,0,2,\"k-rate\"],[\"wet\",1,0,1,\"k-rate\"],[\"dry\",0,0,1,\"k-rate\"]].map(e=>new Object({name:e[0],defaultValue:e[1],minValue:e[2],maxValue:e[3],automationRate:e[4]}))}constructor(e){super(),this.sampleRate=sampleRate,this._Delays=[],this._pDLength=sampleRate+(128-sampleRate%128),this._preDelay=new Float32Array(this._pDLength),this._pDWrite=0,this._lp1=0,this._lp2=0,this._lp3=0,this._excPhase=0,[.004771345,.003595309,.012734787,.009307483,.022579886,.149625349,.060481839,.1249958,.030509727,.141695508,.089244313,.106280031].forEach(a=>this.makeDelay(a,sampleRate)),this._taps=Int16Array.from([.008937872,.099929438,.064278754,.067067639,.066866033,.006283391,.035818689,.011861161,.121870905,.041262054,.08981553,.070931756,.011256342,.004065724],a=>Math.round(a*sampleRate))}makeDelay(e,a){let t=Math.round(e*a),s=2**Math.ceil(Math.log2(t));this._Delays.push([new Float32Array(s),t-1,0,s-1])}writeDelay(e,a){return this._Delays[e][0][this._Delays[e][1]]=a}readDelay(e){return this._Delays[e][0][this._Delays[e][2]]}readDelayAt(e,a){let t=this._Delays[e];return t[0][t[2]+a&t[3]]}readDelayCAt(e,a){let t=this._Delays[e],s=a-~~a,d=~~a+t[2]-1,r=t[3],D=t[0][d++&r],l=t[0][d++&r],h=t[0][d++&r],y=t[0][d&r],u=(3*(l-h)-D+y)/2,m=2*h+D-(5*l+y)/2,c=(h-D)/2;return((u*s+m)*s+c)*s+l}process(e,a,t){let s=~~t.preDelay[0],d=t.bandwidth[0],r=t.inputDiffusion1[0],D=t.inputDiffusion2[0],l=t.decay[0],h=t.decayDiffusion1[0],y=t.decayDiffusion2[0],u=1-t.damping[0],m=t.excursionRate[0]/sampleRate,c=t.excursionDepth[0]*sampleRate/1e3,w=t.wet[0]*.6,A=t.dry[0];if(e[0].length==2)for(let i=127;i>=0;i--)this._preDelay[this._pDWrite+i]=(e[0][0][i]+e[0][1][i])*.5,a[0][0][i]=e[0][0][i]*A,a[0][1][i]=e[0][1][i]*A;else if(e[0].length>0){this._preDelay.set(e[0][0],this._pDWrite);for(let i=127;i>=0;i--)a[0][0][i]=a[0][1][i]=e[0][0][i]*A}else this._preDelay.set(new Float32Array(128),this._pDWrite);let o=0;for(;o<128;){let i=0,b=0;this._lp1+=d*(this._preDelay[(this._pDLength+this._pDWrite-s+o)%this._pDLength]-this._lp1);let p=this.writeDelay(0,this._lp1-r*this.readDelay(0));p=this.writeDelay(1,r*(p-this.readDelay(1))+this.readDelay(0)),p=this.writeDelay(2,r*p+this.readDelay(1)-D*this.readDelay(2)),p=this.writeDelay(3,D*(p-this.readDelay(3))+this.readDelay(2));let k=D*p+this.readDelay(3),g=c*(1+Math.cos(this._excPhase*6.28)),x=c*(1+Math.sin(this._excPhase*6.2847)),_=this.writeDelay(4,k+l*this.readDelay(11)+h*this.readDelayCAt(4,g));this.writeDelay(5,this.readDelayCAt(4,g)-h*_),this._lp2+=u*(this.readDelay(5)-this._lp2),_=this.writeDelay(6,l*this._lp2-y*this.readDelay(6)),this.writeDelay(7,this.readDelay(6)+y*_),_=this.writeDelay(8,k+l*this.readDelay(7)+h*this.readDelayCAt(8,x)),this.writeDelay(9,this.readDelayCAt(8,x)-h*_),this._lp3+=u*(this.readDelay(9)-this._lp3),_=this.writeDelay(10,l*this._lp3-y*this.readDelay(10)),this.writeDelay(11,this.readDelay(10)+y*_),i=this.readDelayAt(9,this._taps[0])+this.readDelayAt(9,this._taps[1])-this.readDelayAt(10,this._taps[2])+this.readDelayAt(11,this._taps[3])-this.readDelayAt(5,this._taps[4])-this.readDelayAt(6,this._taps[5])-this.readDelayAt(7,this._taps[6]),b=this.readDelayAt(5,this._taps[7])+this.readDelayAt(5,this._taps[8])-this.readDelayAt(6,this._taps[9])+this.readDelayAt(7,this._taps[10])-this.readDelayAt(9,this._taps[11])-this.readDelayAt(10,this._taps[12])-this.readDelayAt(11,this._taps[13]),a[0][0][o]+=i*w,a[0][1][o]+=b*w,this._excPhase+=m,o++;for(let R=0,n=this._Delays[0];R<this._Delays.length;n=this._Delays[++R])n[1]=n[1]+1&n[3],n[2]=n[2]+1&n[3]}return this._pDWrite=(this._pDWrite+128)%this._pDLength,!0}};registerProcessor(\"DattorroReverb\",f);})();`;\n","import { asConstructable } from \"../smplr/as-constructable\";\nimport { PROCESSOR } from \"./processor.min\";\n\nconst PARAMS = [\n \"preDelay\",\n \"bandwidth\",\n \"inputDiffusion1\",\n \"inputDiffusion2\",\n \"decay\",\n \"decayDiffusion1\",\n \"decayDiffusion2\",\n \"damping\",\n \"excursionRate\",\n \"excursionDepth\",\n \"wet\",\n \"dry\",\n] as const;\n\nconst init = new WeakMap<AudioContext, Promise<void>>();\n\nasync function createDattorroReverbEffect(\n context: AudioContext,\n): Promise<AudioWorkletNode | undefined> {\n if (!context.audioWorklet) {\n console.warn(\n \"AudioWorklet not supported in this context. Reverb not available.\",\n );\n return undefined;\n }\n let ready = init.get(context);\n if (!ready) {\n const blob = new Blob([PROCESSOR], { type: \"application/javascript\" });\n const url = URL.createObjectURL(blob);\n ready = context.audioWorklet.addModule(url);\n init.set(context, ready);\n }\n await ready;\n\n const reverb = new AudioWorkletNode(context, \"DattorroReverb\", {\n outputChannelCount: [2],\n });\n return reverb;\n}\n\nclass ReverbImpl {\n #effect: AudioWorkletNode | undefined;\n #ready: Promise<this>;\n public readonly input: AudioNode;\n #output: AudioNode;\n\n constructor(context: AudioContext) {\n this.input = context.createGain();\n this.#output = context.destination;\n this.#ready = createDattorroReverbEffect(context).then((reverb) => {\n if (reverb) {\n this.input.connect(reverb);\n reverb.connect(this.#output);\n this.#effect = reverb;\n }\n return this;\n });\n }\n\n get paramNames() {\n return PARAMS;\n }\n\n getParam(name: (typeof PARAMS)[number]): AudioParam | undefined {\n return this.#effect?.parameters.get(name);\n }\n\n get isReady(): boolean {\n return this.#effect !== undefined;\n }\n\n ready(): Promise<this> {\n return this.#ready;\n }\n\n connect(output: AudioNode) {\n if (this.#effect) {\n this.#effect.disconnect(this.#output);\n this.#effect.connect(output);\n }\n this.#output = output;\n }\n}\n\nexport const Reverb = asConstructable(ReverbImpl);\nexport type Reverb = ReturnType<typeof Reverb>;\n","import {\n AudioBuffers,\n AudioBuffersLoader,\n loadAudioBuffer,\n} from \"./smplr/load-audio\";\nimport { toMidi } from \"./smplr/midi\";\nimport { HttpStorage, Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress, SmplrPreset } from \"./smplr/types\";\nimport { spreadKeyRanges } from \"./smplr/utils\";\n\ntype SamplerBase = {\n storage?: Storage;\n detune?: number;\n volume?: number;\n pan?: number;\n velocity?: number;\n decayTime?: number;\n lpfCutoffHz?: number;\n destination?: AudioNode;\n volumeToGain?: (volume: number) => number;\n onLoadProgress?: (progress: LoadProgress) => void;\n};\n\ntype SamplerBuffers =\n | Record<string | number, string | AudioBuffer | AudioBuffers>\n | AudioBuffersLoader;\n\ntype SamplerBuffersInput = {\n buffers?: SamplerBuffers;\n preset?: never;\n};\n\ntype SamplerPresetInput = {\n preset: SmplrPreset;\n buffers?: never;\n};\n\nexport type SamplerConfig = SamplerBase &\n (SamplerBuffersInput | SamplerPresetInput);\n\n/** Input accepted by {@link Sampler.reload}: a `SmplrPreset` schema or a flat buffers record/loader. */\nexport type SamplerReloadInput = SmplrPreset | SamplerBuffers;\n\ntype SamplerExtras = {\n reload: (input: SamplerReloadInput) => Promise<void>;\n};\n\nfunction isSmplrPreset(x: unknown): x is SmplrPreset {\n return (\n typeof x === \"object\" &&\n x !== null &&\n \"groups\" in x &&\n Array.isArray((x as SmplrPreset).groups)\n );\n}\n\n/**\n * A Sampler instrument. Accepts either a flat record of samples\n * (`{ buffers: { C4: \"url\" } }`) or a full `SmplrPreset`\n * (`{ preset: { samples, groups, ... } }`) for advanced use cases including\n * per-region pitch/velocity/round-robin control.\n *\n * Use `sampler.reload(input)` to swap content at runtime. `reload` accepts\n * either shape (flat record or `SmplrPreset`), regardless of which mode was\n * used at construction.\n */\nexport const Sampler = Instrument<SamplerConfig, SamplerExtras>(\n (ctx: BaseAudioContext, options: SamplerConfig = {}, smplr) => {\n const storage = options.storage ?? HttpStorage;\n\n const loadFromInput = (input: SamplerReloadInput): Promise<void> => {\n if (isSmplrPreset(input)) {\n return smplr.loadInstrument(input);\n }\n return getSource(ctx, input)\n .then((source) => buildSamplerBuffers(source, ctx, storage, options))\n .then(({ json, buffers }) => smplr.loadInstrument(json, buffers));\n };\n\n const initialInput: SamplerReloadInput =\n \"preset\" in options && options.preset\n ? options.preset\n : ((options as SamplerBuffersInput).buffers ?? {});\n\n return {\n extras: { reload: loadFromInput },\n ready: loadFromInput(initialInput),\n };\n },\n);\n\nfunction getSource(\n ctx: BaseAudioContext,\n raw: NonNullable<Partial<SamplerConfig>[\"buffers\"]>,\n): Promise<Record<string | number, string | AudioBuffer>> {\n if (typeof raw === \"function\") {\n const ab: AudioBuffers = {};\n return (raw as AudioBuffersLoader)(ctx, ab).then(\n () => ab as Record<string | number, string | AudioBuffer>,\n );\n }\n return Promise.resolve(raw as Record<string | number, string | AudioBuffer>);\n}\n\n// ---------------------------------------------------------------------------\n// samplerToPreset — pure converter function (no async)\n// ---------------------------------------------------------------------------\n\ntype SamplerJsonOptions = Pick<\n SamplerConfig,\n \"decayTime\" | \"lpfCutoffHz\" | \"detune\"\n>;\n\ntype ConvertResult = {\n json: SmplrPreset;\n /** Resolved AudioBuffer instances, including URL-fetched ones. */\n buffers: Map<string, AudioBuffer>;\n};\n\n/**\n * Load all URL samples and build a SmplrPreset + pre-loaded buffers map.\n * All samples (URL-fetched and pre-provided AudioBuffers) are passed as\n * pre-loaded, so SampleLoader never makes network requests.\n */\nasync function buildSamplerBuffers(\n source: Record<string | number, string | AudioBuffer>,\n context: BaseAudioContext,\n storage: Storage,\n options: Partial<SamplerJsonOptions>,\n): Promise<ConvertResult> {\n const { json, urlMap, preloaded } = samplerToPreset(source, options);\n\n // Fetch URL-based samples\n await Promise.all(\n Object.entries(urlMap).map(async ([name, url]) => {\n const buffer = await loadAudioBuffer(context, url, storage);\n if (buffer) preloaded.set(name, buffer);\n }),\n );\n\n return { json, buffers: preloaded };\n}\n\ntype InternalConvertResult = {\n json: SmplrPreset;\n urlMap: Record<string, string>;\n preloaded: Map<string, AudioBuffer>;\n};\n\n/**\n * Convert a flat source Record to SmplrPreset + separated URL map + pre-loaded buffers.\n *\n * - Keys that are valid MIDI names/numbers → MIDI-mapped regions.\n * If ALL keys are MIDI-parseable, spread key ranges (pitch-shifting).\n * Otherwise each MIDI key gets an exact [n, n] range.\n * - Non-MIDI keys are assigned sequential MIDI numbers and added to `aliases`.\n * - AudioBuffer values → pre-loaded map (no fetch).\n * - String URL values → urlMap (fetched asynchronously by caller).\n */\nexport function samplerToPreset(\n source: Record<string | number, string | AudioBuffer>,\n options: Partial<SamplerJsonOptions> = {},\n): InternalConvertResult {\n const keys = Object.keys(source);\n const preloaded = new Map<string, AudioBuffer>();\n const urlMap: Record<string, string> = {};\n const aliases: Record<string, number> = {};\n\n // Separate MIDI-parseable keys from arbitrary string keys\n const midiEntries: [number, string][] = [];\n const nonMidiKeys: string[] = [];\n\n for (const key of keys) {\n const midi = toMidi(key as string | number);\n if (midi !== undefined) {\n midiEntries.push([midi, key]);\n } else {\n nonMidiKeys.push(key);\n }\n }\n\n const allMidi = nonMidiKeys.length === 0;\n\n type Entry = {\n midi: number;\n key: string;\n sampleName: string;\n keyRange: [number, number];\n pitch: number;\n };\n\n const entries: Entry[] = [];\n\n if (allMidi && midiEntries.length > 0) {\n // All keys are MIDI → spread key ranges for pitch-shifting\n const spread = spreadKeyRanges(\n midiEntries.map(([midi, key]) => [midi, key] as [number, string]),\n );\n for (let i = 0; i < midiEntries.length; i++) {\n const [midi, key] = midiEntries[i];\n const { keyRange, pitch } = spread[i];\n entries.push({ midi, key, sampleName: key, keyRange, pitch });\n }\n } else {\n // Mixed or all non-MIDI: exact ranges for MIDI keys, sequential for others\n for (const [midi, key] of midiEntries) {\n entries.push({\n midi,\n key,\n sampleName: key,\n keyRange: [midi, midi],\n pitch: midi,\n });\n }\n\n let seqMidi = 0;\n for (const key of nonMidiKeys) {\n while (entries.some((e) => e.midi === seqMidi)) seqMidi++;\n const midi = seqMidi++;\n aliases[key] = midi;\n entries.push({\n midi,\n key,\n sampleName: key,\n keyRange: [midi, midi],\n pitch: midi,\n });\n }\n }\n\n // Populate pre-loaded map and URL map\n for (const { key, sampleName } of entries) {\n const value = source[key];\n if (value instanceof AudioBuffer) {\n preloaded.set(sampleName, value);\n } else if (typeof value === \"string\") {\n urlMap[sampleName] = value;\n }\n }\n\n const json: SmplrPreset = {\n // baseUrl doesn't matter: all samples will be pre-loaded\n samples: { baseUrl: \"\", formats: [\"ogg\"] },\n groups: [\n {\n regions: entries.map(({ sampleName, keyRange, pitch }) => ({\n sample: sampleName,\n keyRange,\n pitch,\n })),\n },\n ],\n aliases: Object.keys(aliases).length > 0 ? aliases : undefined,\n defaults: {\n ampRelease: options.decayTime,\n lpfCutoffHz: options.lpfCutoffHz,\n detune: options.detune,\n },\n };\n\n return { json, urlMap, preloaded };\n}\n\n/** Instance type returned by the {@link Sampler} factory. */\nexport type Sampler = ReturnType<typeof Sampler>;\n","import { Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress } from \"./smplr/types\";\nimport { sfzToPreset } from \"./smplr/sfz-convert\";\n\nexport function getSmolkenNames() {\n return [\"Pizzicato\", \"Arco\", \"Switched\"];\n}\n\nfunction getSmolkenUrl(instrument: string) {\n const FILES: Record<string, string> = {\n Arco: \"arco\",\n Pizzicato: \"pizz\",\n Switched: \"switched\",\n };\n return `https://smpldsnds.github.io/sfzinstruments-dsmolken-double-bass/d_smolken_rubner_bass_${FILES[instrument]}.sfz`;\n}\n\nexport type SmolkenConfig = {\n instrument: string;\n storage: Storage;\n};\n\nexport type SmolkenOptions = Partial<\n SmolkenConfig & {\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nconst SMOLKEN_BASE_URL =\n \"https://smpldsnds.github.io/sfzinstruments-dsmolken-double-bass\";\n\nexport const Smolken = Instrument(\n (ctx: BaseAudioContext, options: SmolkenOptions = {}, smplr) => {\n const sfzUrl = getSmolkenUrl(options.instrument ?? \"Arco\");\n return fetch(sfzUrl)\n .then((r) => r.text())\n .then((sfzText) =>\n smplr.loadInstrument(\n sfzToPreset(sfzText, {\n baseUrl: SMOLKEN_BASE_URL,\n pathFromSampleName: (name) =>\n name.replace(/\\\\/g, \"/\").replace(/\\.wav$/i, \"\"),\n formats: [\"ogg\", \"m4a\"],\n }),\n ),\n );\n },\n);\n\n/** Instance type returned by the {@link Smolken} factory. */\nexport type Smolken = ReturnType<typeof Smolken>;\n","import { findFirstSupportedFormat } from \"../smplr/load-audio\";\n\nexport function gleitzKitUrl(name: string, kit: string) {\n const format = findFirstSupportedFormat([\"ogg\", \"mp3\"]) ?? \"mp3\";\n console.debug(`Soundfont: using ${format} format for ${name}`);\n return `https://gleitz.github.io/midi-js-soundfonts/${kit}/${name}-${format}.js`;\n}\n\nexport const SOUNDFONT_KITS = [\"MusyngKite\", \"FluidR3_GM\"];\nexport const DEFAULT_SOUNDFONT_KIT = SOUNDFONT_KITS[0];\n\nexport const SOUNDFONT_INSTRUMENTS = [\n \"accordion\",\n \"acoustic_bass\",\n \"acoustic_grand_piano\",\n \"acoustic_guitar_nylon\",\n \"acoustic_guitar_steel\",\n \"agogo\",\n \"alto_sax\",\n \"applause\",\n \"bagpipe\",\n \"banjo\",\n \"baritone_sax\",\n \"bassoon\",\n \"bird_tweet\",\n \"blown_bottle\",\n \"brass_section\",\n \"breath_noise\",\n \"bright_acoustic_piano\",\n \"celesta\",\n \"cello\",\n \"choir_aahs\",\n \"church_organ\",\n \"clarinet\",\n \"clavinet\",\n \"contrabass\",\n \"distortion_guitar\",\n \"drawbar_organ\",\n \"dulcimer\",\n \"electric_bass_finger\",\n \"electric_bass_pick\",\n \"electric_grand_piano\",\n \"electric_guitar_clean\",\n \"electric_guitar_jazz\",\n \"electric_guitar_muted\",\n \"electric_piano_1\",\n \"electric_piano_2\",\n \"english_horn\",\n \"fiddle\",\n \"flute\",\n \"french_horn\",\n \"fretless_bass\",\n \"fx_1_rain\",\n \"fx_2_soundtrack\",\n \"fx_3_crystal\",\n \"fx_4_atmosphere\",\n \"fx_5_brightness\",\n \"fx_6_goblins\",\n \"fx_7_echoes\",\n \"fx_8_scifi\",\n \"glockenspiel\",\n \"guitar_fret_noise\",\n \"guitar_harmonics\",\n \"gunshot\",\n \"harmonica\",\n \"harpsichord\",\n \"helicopter\",\n \"honkytonk_piano\",\n \"kalimba\",\n \"koto\",\n \"lead_1_square\",\n \"lead_2_sawtooth\",\n \"lead_3_calliope\",\n \"lead_4_chiff\",\n \"lead_5_charang\",\n \"lead_6_voice\",\n \"lead_7_fifths\",\n \"lead_8_bass__lead\",\n \"marimba\",\n \"melodic_tom\",\n \"music_box\",\n \"muted_trumpet\",\n \"oboe\",\n \"ocarina\",\n \"orchestra_hit\",\n \"orchestral_harp\",\n \"overdriven_guitar\",\n \"pad_1_new_age\",\n \"pad_2_warm\",\n \"pad_3_polysynth\",\n \"pad_4_choir\",\n \"pad_5_bowed\",\n \"pad_6_metallic\",\n \"pad_7_halo\",\n \"pad_8_sweep\",\n \"pan_flute\",\n \"percussive_organ\",\n \"piccolo\",\n \"pizzicato_strings\",\n \"recorder\",\n \"reed_organ\",\n \"reverse_cymbal\",\n \"rock_organ\",\n \"seashore\",\n \"shakuhachi\",\n \"shamisen\",\n \"shanai\",\n \"sitar\",\n \"slap_bass_1\",\n \"slap_bass_2\",\n \"soprano_sax\",\n \"steel_drums\",\n \"string_ensemble_1\",\n \"string_ensemble_2\",\n \"synth_bass_1\",\n \"synth_bass_2\",\n \"synth_brass_1\",\n \"synth_brass_2\",\n \"synth_choir\",\n \"synth_drum\",\n \"synth_strings_1\",\n \"synth_strings_2\",\n \"taiko_drum\",\n \"tango_accordion\",\n \"telephone_ring\",\n \"tenor_sax\",\n \"timpani\",\n \"tinkle_bell\",\n \"tremolo_strings\",\n \"trombone\",\n \"trumpet\",\n \"tuba\",\n \"tubular_bells\",\n \"vibraphone\",\n \"viola\",\n \"violin\",\n \"voice_oohs\",\n \"whistle\",\n \"woodblock\",\n \"xylophone\",\n];\n","import { toMidi } from \"../smplr/midi\";\n\nexport type LoopData = Record<number, [number, number]>;\n\nexport function getGoldstSoundfontLoopsUrl(instrument: string, kit: string) {\n if (instrument.startsWith(\"http\")) return undefined;\n return `https://goldst.dev/midi-js-soundfonts/${kit}/${instrument}-loop.json`;\n}\n\n/**\n *\n * @see https://github.com/goldst/midi-js-soundfonts\n * @see https://github.com/danigb/smplr/issues/23\n */\nexport async function fetchSoundfontLoopData(\n url?: string,\n sampleRate = 44100,\n): Promise<LoopData | undefined> {\n if (!url) return undefined;\n try {\n const req = await fetch(url);\n if (req.status !== 200) return;\n\n const raw = await req.json();\n const loopData: LoopData = {};\n Object.keys(raw).forEach((key) => {\n const midi = toMidi(key);\n if (midi === undefined) return;\n const offsets = raw[key];\n loopData[midi] = [offsets[0] / sampleRate, offsets[1] / sampleRate];\n });\n return loopData;\n } catch (err) {\n return undefined;\n }\n}\n","import { HttpStorage, Storage } from \"../storage\";\nimport { Instrument } from \"../smplr\";\nimport { LoadProgress, SmplrGroup, SmplrPreset } from \"../smplr/types\";\nimport { spreadKeyRanges } from \"../smplr/utils\";\nimport { toMidi } from \"../smplr/midi\";\nimport {\n SOUNDFONT_INSTRUMENTS,\n SOUNDFONT_KITS,\n DEFAULT_SOUNDFONT_KIT,\n gleitzKitUrl,\n} from \"./soundfont-instrument\";\nimport {\n LoopData,\n fetchSoundfontLoopData,\n getGoldstSoundfontLoopsUrl,\n} from \"./soundfont-loops\";\n\nexport function getSoundfontKits() {\n return SOUNDFONT_KITS;\n}\n\nexport function getSoundfontNames() {\n return SOUNDFONT_INSTRUMENTS;\n}\n\ntype SoundfontConfig = {\n kit: \"FluidR3_GM\" | \"MusyngKite\" | string;\n instrument?: string;\n instrumentUrl: string;\n storage: Storage;\n extraGain: number;\n loadLoopData: boolean;\n loopDataUrl?: string;\n};\n\nexport type SoundfontOptions = Partial<\n SoundfontConfig & {\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n onLoadProgress?: (progress: LoadProgress) => void;\n }\n>;\n\nexport const Soundfont = Instrument(\n (ctx: BaseAudioContext, options: SoundfontOptions = {}, smplr) => {\n const config = getSoundfontConfig(options);\n\n // Apply extra gain insert synchronously, before the first audible note\n // can reach the output.\n const gain = ctx.createGain();\n gain.gain.value = config.extraGain;\n smplr.output.addInsert(gain);\n\n return loadSoundfontData(ctx, config).then(\n ({ buffers, noteNames, loopData }) =>\n smplr.loadInstrument(soundfontToPreset(noteNames, loopData), buffers),\n );\n },\n);\n\n/** Instance type returned by the {@link Soundfont} factory. */\nexport type Soundfont = ReturnType<typeof Soundfont>;\n\n// ---------------------------------------------------------------------------\n// loadSoundfontData — async loader for base64-encoded MIDI.js files\n// ---------------------------------------------------------------------------\n\ntype SoundfontData = {\n buffers: Map<string, AudioBuffer>;\n noteNames: string[];\n loopData?: LoopData;\n};\n\nasync function loadSoundfontData(\n context: BaseAudioContext,\n config: SoundfontConfig,\n): Promise<SoundfontData> {\n const [{ buffers, noteNames }, loopData] = await Promise.all([\n decodeSoundfontFile(context, config),\n fetchSoundfontLoopData(config.loopDataUrl),\n ]);\n\n return { buffers, noteNames, loopData };\n}\n\nasync function decodeSoundfontFile(\n context: BaseAudioContext,\n config: SoundfontConfig,\n): Promise<{ buffers: Map<string, AudioBuffer>; noteNames: string[] }> {\n const sourceFile = await (\n await config.storage.fetch(config.instrumentUrl)\n ).text();\n const json = midiJsToJson(sourceFile);\n\n const noteNames = Object.keys(json);\n const buffers = new Map<string, AudioBuffer>();\n\n await Promise.all(\n noteNames.map(async (noteName) => {\n const midi = toMidi(noteName);\n if (midi === undefined) return;\n try {\n const audioData = base64ToArrayBuffer(\n removeBase64Prefix(json[noteName]),\n );\n const buffer = await context.decodeAudioData(audioData);\n buffers.set(noteName, buffer);\n } catch (error) {\n console.warn(\n `Soundfont: failed to decode note ${noteName}`,\n error instanceof Error ? error.message : error,\n );\n }\n }),\n );\n\n return { buffers, noteNames: [...buffers.keys()] };\n}\n\n// ---------------------------------------------------------------------------\n// soundfontToPreset — pure converter function\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a list of note names (with optional loop data) to SmplrPreset.\n * Uses spreadKeyRanges so notes between recorded pitches pitch-shift correctly.\n */\nexport function soundfontToPreset(\n noteNames: string[],\n loopData?: LoopData,\n): SmplrPreset {\n const entries: [number, string][] = [];\n\n for (const noteName of noteNames) {\n const midi = toMidi(noteName);\n if (midi === undefined) continue;\n entries.push([midi, noteName]);\n }\n\n const spread = spreadKeyRanges(entries);\n\n const regions: SmplrGroup[\"regions\"] = spread.map(\n ({ keyRange, pitch, sample }) => {\n const region: SmplrGroup[\"regions\"][number] = { sample, keyRange, pitch };\n\n // Apply loop data if available\n if (loopData) {\n const loop = loopData[pitch];\n if (loop) {\n region.loop = true;\n region.loopStart = loop[0];\n region.loopEnd = loop[1];\n }\n }\n\n return region;\n },\n );\n\n return {\n // baseUrl doesn't matter — all buffers are pre-loaded\n samples: { baseUrl: \"\", formats: [\"ogg\"] },\n groups: [{ regions }],\n };\n}\n\n// ---------------------------------------------------------------------------\n// getSoundfontConfig\n// ---------------------------------------------------------------------------\n\nfunction getSoundfontConfig(options: SoundfontOptions): SoundfontConfig {\n if (!options.instrument && !options.instrumentUrl) {\n throw Error(\"Soundfont: instrument or instrumentUrl is required\");\n }\n const config = {\n kit: options.kit ?? DEFAULT_SOUNDFONT_KIT,\n instrument: options.instrument,\n storage: options.storage ?? HttpStorage,\n extraGain: options.extraGain ?? 5,\n loadLoopData: options.loadLoopData ?? false,\n loopDataUrl: options.loopDataUrl,\n instrumentUrl: options.instrumentUrl ?? \"\",\n };\n\n if (config.instrument && config.instrument.startsWith(\"http\")) {\n console.warn(\n \"Use 'instrumentUrl' instead of 'instrument' to load from a URL\",\n );\n config.instrumentUrl = config.instrument;\n config.instrument = undefined;\n }\n\n if (!config.instrumentUrl) {\n if (config.instrument) {\n config.instrumentUrl = gleitzKitUrl(config.instrument, config.kit);\n } else {\n throw Error(\n \"Soundfont: 'instrument' or 'instrumentUrl' configuration parameter is required\",\n );\n }\n } else {\n if (config.kit !== DEFAULT_SOUNDFONT_KIT || config.instrument) {\n console.warn(\n \"Soundfont: 'kit' and 'instrument' config parameters are ignored because 'instrumentUrl' is explicitly set.\",\n );\n }\n }\n\n if (config.loadLoopData && config.instrument && !config.loopDataUrl) {\n config.loopDataUrl = getGoldstSoundfontLoopsUrl(\n config.instrument,\n config.kit,\n );\n }\n\n return config;\n}\n\n// ---------------------------------------------------------------------------\n// Base64 / MIDI.js helpers\n// ---------------------------------------------------------------------------\n\nfunction midiJsToJson(source: string): Record<string, string> {\n const header = source.indexOf(\"MIDI.Soundfont.\");\n if (header < 0) throw Error(\"Invalid MIDI.js Soundfont format\");\n const start = source.indexOf(\"=\", header) + 2;\n const end = source.lastIndexOf(\",\");\n return JSON.parse(source.slice(start, end) + \"}\");\n}\n\nfunction removeBase64Prefix(audioBase64: string) {\n return audioBase64.slice(audioBase64.indexOf(\",\") + 1);\n}\n\nfunction base64ToArrayBuffer(base64: string) {\n const decoded = window.atob(base64);\n const len = decoded.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = decoded.charCodeAt(i);\n }\n return bytes.buffer;\n}\n","import { Instrument } from \"./smplr\";\nimport { SmplrGroup, SmplrPreset } from \"./smplr/types\";\n\ntype Sf2 = {\n instruments: Sf2Instrument[];\n};\n\ntype Sf2Instrument = {\n header: {\n name: string;\n };\n zones: Sf2Zone[];\n};\n\ntype Sf2Zone = {\n sample: Sf2Sample;\n keyRange?: { lo: number; hi: number };\n};\n\ntype Sf2Sample = {\n data: Int16Array;\n header: {\n name: string;\n sampleRate: number;\n originalPitch: number;\n pitchCorrection: number;\n start: number;\n end: number;\n startLoop: number;\n endLoop: number;\n };\n};\n\nexport type Soundfont2Options = {\n url: string;\n createSoundfont: (data: Uint8Array) => Sf2;\n destination?: AudioNode;\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n velocity?: number;\n};\n\nexport function sf2InstrumentToPreset(\n sf2Instrument: Sf2Instrument,\n context: BaseAudioContext,\n): { json: SmplrPreset; buffers: Map<string, AudioBuffer> } {\n const buffers = new Map<string, AudioBuffer>();\n const regions: SmplrGroup[\"regions\"] = [];\n\n for (const zone of sf2Instrument.zones) {\n const { sample, keyRange } = zone;\n const { header } = sample;\n const sampleName = header.name;\n\n const float32 = new Float32Array(sample.data.length);\n for (let i = 0; i < sample.data.length; i++)\n float32[i] = sample.data[i] / 32768;\n const audioBuffer = context.createBuffer(\n 1,\n float32.length,\n header.sampleRate,\n );\n audioBuffer.getChannelData(0).set(float32);\n buffers.set(sampleName, audioBuffer);\n\n const hasLoop = header.startLoop >= 0 && header.endLoop > header.startLoop;\n\n regions.push({\n sample: sampleName,\n pitch: header.originalPitch,\n ...(keyRange && {\n keyRange: [keyRange.lo, keyRange.hi] as [number, number],\n }),\n ...(hasLoop && {\n loop: true,\n loopStart: header.startLoop / header.sampleRate,\n loopEnd: header.endLoop / header.sampleRate,\n }),\n });\n }\n\n return {\n json: { samples: { baseUrl: \"\", formats: [] }, groups: [{ regions }] },\n buffers,\n };\n}\n\ntype Soundfont2SamplerExtras = {\n readonly instrumentNames: string[];\n loadInstrument(instrumentName: string): Promise<void> | undefined;\n};\n\nexport const Soundfont2 = Instrument(\n (ctx: BaseAudioContext, options: Soundfont2Options, smplr) => {\n // Mutable closure state — extras read these; parse promise populates them.\n let soundfont: Sf2 | undefined = undefined;\n let instrumentNamesList: string[] = [];\n\n // Capture the base `loadInstrument(json, buffers)` *before* the extras\n // below shadow it on the instance — otherwise the call inside the\n // override would recurse into itself with the wrong arity.\n const baseLoadInstrument = smplr.loadInstrument.bind(smplr);\n\n const extras: Soundfont2SamplerExtras = {\n get instrumentNames(): string[] {\n return instrumentNamesList;\n },\n loadInstrument(instrumentName) {\n const sf2inst = soundfont?.instruments.find(\n (inst: Sf2Instrument) => inst.header.name === instrumentName,\n );\n if (!sf2inst) return undefined;\n const { json, buffers } = sf2InstrumentToPreset(sf2inst, ctx);\n return baseLoadInstrument(json, buffers);\n },\n };\n\n const ready = loadSoundfont(options).then((sf2) => {\n soundfont = sf2;\n instrumentNamesList = sf2.instruments.map(\n (inst: Sf2Instrument) => inst.header.name,\n );\n });\n\n return { extras, ready };\n },\n);\n\n/** Instance type returned by the {@link Soundfont2} factory. */\nexport type Soundfont2 = ReturnType<typeof Soundfont2>;\n\n/** @deprecated Use `Soundfont2` instead. */\nexport const Soundfont2Sampler = Soundfont2;\n/** @deprecated Use `Soundfont2` instead. */\nexport type Soundfont2Sampler = Soundfont2;\n\nasync function loadSoundfont(options: Soundfont2Options) {\n const buffer = await fetch(options.url).then((res) => res.arrayBuffer());\n const data = new Uint8Array(buffer);\n return options.createSoundfont(data);\n}\n","import { HttpStorage, Storage } from \"./storage\";\nimport { Instrument } from \"./smplr\";\nimport { LoadProgress, SmplrGroup, SmplrPreset } from \"./smplr/types\";\nimport { spreadKeyRanges } from \"./smplr/utils\";\n\n/**\n * Configuration options for SplendidGrandPiano.\n */\nexport type SplendidGrandPianoConfig = {\n baseUrl: string;\n storage: Storage;\n /** Global detune in cents, applied to all notes. */\n detune: number;\n /** Default velocity (0–127) when not specified per note. */\n velocity: number;\n /** Release time in seconds. Maps to SmplrPreset defaults.ampRelease. */\n decayTime: number;\n /** Destination audio node. Defaults to context.destination. */\n destination?: AudioNode;\n /** Master volume (0–127 MIDI scale). */\n volume?: number;\n /** Stereo pan position (-1 = full left, 0 = centre, +1 = full right). */\n pan?: number;\n /** Called after each buffer is loaded or served from cache. */\n onLoadProgress?: (progress: LoadProgress) => void;\n /** Audio formats to try, in order of preference. Defaults to [\"ogg\", \"m4a\"]. */\n formats?: string[];\n /** Limit which notes are fetched. Useful for reducing initial load time. */\n notesToLoad?: {\n notes: number[];\n velocityRange: [number, number];\n };\n};\n\nconst BASE_URL =\n \"https://smpldsnds.github.io/sfzinstruments-splendid-grand-piano/samples\";\n\nconst DEFAULTS: SplendidGrandPianoConfig = {\n baseUrl: BASE_URL,\n storage: HttpStorage,\n detune: 0,\n volume: 100,\n velocity: 100,\n decayTime: 0.5,\n};\n\nexport const SplendidGrandPiano = Instrument(\n (\n ctx: BaseAudioContext,\n options: Partial<SplendidGrandPianoConfig> = {},\n smplr,\n ) => smplr.loadInstrument(pianoToPreset({ ...DEFAULTS, ...options })),\n);\n\n/** Instance type returned by the {@link SplendidGrandPiano} factory. */\nexport type SplendidGrandPiano = ReturnType<typeof SplendidGrandPiano>;\n\n// ---------------------------------------------------------------------------\n// pianoToPreset — pure function, independently testable\n// ---------------------------------------------------------------------------\n\ntype PianoJsonOptions = Pick<\n SplendidGrandPianoConfig,\n \"baseUrl\" | \"detune\" | \"decayTime\" | \"notesToLoad\" | \"formats\"\n>;\n\n/**\n * Convert the LAYERS array and user options into a SmplrPreset descriptor.\n *\n * Each layer becomes a SmplrGroup with its velRange. If `notesToLoad` is\n * specified, layers and samples are filtered accordingly. The PPP layer\n * includes a low-pass filter cutoff.\n *\n * `spreadKeyRanges` is used to pre-compute which key range each sample\n * covers, replacing the old on-the-fly `findNearestMidiInLayer` logic.\n */\nexport function pianoToPreset(options: PianoJsonOptions): SmplrPreset {\n const { notesToLoad } = options;\n\n // Filter layers by requested velocity range\n const layers = notesToLoad\n ? LAYERS.filter(\n (layer) =>\n layer.vel_range[0] <= notesToLoad.velocityRange[1] &&\n layer.vel_range[1] >= notesToLoad.velocityRange[0],\n )\n : LAYERS;\n\n const groups: SmplrGroup[] = layers.map((layer) => {\n // Filter samples by requested MIDI notes\n const samples = (\n notesToLoad\n ? layer.samples.filter(([midi]) =>\n notesToLoad.notes.includes(midi as number),\n )\n : layer.samples\n ) as [number, string][];\n\n const regions = spreadKeyRanges(samples).map(\n ({ keyRange, pitch, sample }) => ({\n keyRange,\n pitch,\n sample,\n }),\n );\n\n const group: SmplrGroup = {\n velRange: layer.vel_range as [number, number],\n regions,\n };\n\n if (\"cutoff\" in layer && layer.cutoff !== undefined) {\n group.lpfCutoffHz = layer.cutoff as number;\n }\n\n return group;\n });\n\n return {\n samples: {\n baseUrl: options.baseUrl,\n formats: options.formats ?? [\"ogg\", \"m4a\"],\n },\n defaults: {\n ampRelease: options.decayTime,\n detune: options.detune,\n },\n groups,\n };\n}\n\n// ---------------------------------------------------------------------------\n// LAYERS — piano sample data\n// ---------------------------------------------------------------------------\n\nexport const LAYERS = [\n {\n name: \"PPP\",\n vel_range: [1, 40],\n cutoff: 1000,\n samples: [\n [23, \"PP B-1\"],\n [27, \"PP D#0\"],\n [29, \"PP F0\"],\n [31, \"PP G0\"],\n [33, \"PP A0\"],\n [35, \"PP B0\"],\n [37, \"PP C#1\"],\n [38, \"PP D1\"],\n [40, \"PP E1\"],\n [41, \"PP F1\"],\n [43, \"PP G1\"],\n [45, \"PP A1\"],\n [47, \"PP B1\"],\n [48, \"PP C2\"],\n [50, \"PP D2\"],\n [52, \"PP E2\"],\n [53, \"PP F2\"],\n [55, \"PP G2\"],\n [56, \"PP G#2\"],\n [57, \"PP A2\"],\n [58, \"PP A#2\"],\n [59, \"PP B2\"],\n [60, \"PP C3\"],\n [62, \"PP D3\"],\n [64, \"PP E3\"],\n [65, \"PP F3\"],\n [67, \"PP G3\"],\n [69, \"PP A3\"],\n [71, \"PP B3\"],\n [72, \"PP C4\"],\n [74, \"PP D4\"],\n [76, \"PP E4\"],\n [77, \"PP F4\"],\n [79, \"PP G4\"],\n [80, \"PP G#4\"],\n [81, \"PP A4\"],\n [82, \"PP A#4\"],\n [83, \"PP B4\"],\n [85, \"PP C#5\"],\n [86, \"PP D5\"],\n [87, \"PP D#5\"],\n [89, \"PP F5\"],\n [90, \"PP F#5\"],\n [91, \"PP G5\"],\n [92, \"PP G#5\"],\n [93, \"PP A5\"],\n [94, \"PP A#5\"],\n [95, \"PP B5\"],\n [96, \"PP C6\"],\n [97, \"PP C#6\"],\n [98, \"PP D6\"],\n [99, \"PP D#6\"],\n [100, \"PP E6\"],\n [101, \"PP F6\"],\n [102, \"PP F#6\"],\n [103, \"PP G6\"],\n [104, \"PP G#6\"],\n [105, \"PP A6\"],\n [106, \"PP A#6\"],\n [107, \"PP B6\"],\n [108, \"PP C7\"],\n ],\n },\n {\n name: \"PP\",\n vel_range: [41, 67],\n samples: [\n [23, \"PP B-1\"],\n [27, \"PP D#0\"],\n [29, \"PP F0\"],\n [31, \"PP G0\"],\n [33, \"PP A0\"],\n [35, \"PP B0\"],\n [37, \"PP C#1\"],\n [38, \"PP D1\"],\n [40, \"PP E1\"],\n [41, \"PP F1\"],\n [43, \"PP G1\"],\n [45, \"PP A1\"],\n [47, \"PP B1\"],\n [48, \"PP C2\"],\n [50, \"PP D2\"],\n [52, \"PP E2\"],\n [53, \"PP F2\"],\n [55, \"PP G2\"],\n [56, \"PP G#2\"],\n [57, \"PP A2\"],\n [58, \"PP A#2\"],\n [59, \"PP B2\"],\n [60, \"PP C3\"],\n [62, \"PP D3\"],\n [64, \"PP E3\"],\n [65, \"PP F3\"],\n [67, \"PP G3\"],\n [69, \"PP A3\"],\n [71, \"PP B3\"],\n [72, \"PP C4\"],\n [74, \"PP D4\"],\n [76, \"PP E4\"],\n [77, \"PP F4\"],\n [79, \"PP G4\"],\n [80, \"PP G#4\"],\n [81, \"PP A4\"],\n [82, \"PP A#4\"],\n [83, \"PP B4\"],\n [85, \"PP C#5\"],\n [86, \"PP D5\"],\n [87, \"PP D#5\"],\n [89, \"PP F5\"],\n [90, \"PP F#5\"],\n [91, \"PP G5\"],\n [92, \"PP G#5\"],\n [93, \"PP A5\"],\n [94, \"PP A#5\"],\n [95, \"PP B5\"],\n [96, \"PP C6\"],\n [97, \"PP C#6\"],\n [98, \"PP D6\"],\n [99, \"PP D#6\"],\n [100, \"PP E6\"],\n [101, \"PP F6\"],\n [102, \"PP F#6\"],\n [103, \"PP G6\"],\n [104, \"PP G#6\"],\n [105, \"PP A6\"],\n [106, \"PP A#6\"],\n [107, \"PP B6\"],\n [108, \"PP C7\"],\n ],\n },\n {\n name: \"MP\",\n vel_range: [68, 84],\n samples: [\n [23, \"Mp B-1\"],\n [27, \"Mp D#0\"],\n [29, \"Mp F0\"],\n [31, \"Mp G0\"],\n [33, \"Mp A0\"],\n [35, \"Mp B0\"],\n [37, \"Mp C#1\"],\n [38, \"Mp D1\"],\n [40, \"Mp E1\"],\n [41, \"Mp F1\"],\n [43, \"Mp G1\"],\n [45, \"Mp A1\"],\n [47, \"Mp B1\"],\n [48, \"Mp C2\"],\n [50, \"Mp D2\"],\n [52, \"Mp E2\"],\n [53, \"Mp F2\"],\n [55, \"Mp G2\"],\n [56, \"Mp G#2\"],\n [57, \"Mp A2\"],\n [58, \"Mp A#2\"],\n [59, \"Mp B2\"],\n [60, \"Mp C3\"],\n [62, \"Mp D3\"],\n [64, \"Mp E3\"],\n [65, \"Mp F3\"],\n [67, \"Mp G3\"],\n [69, \"Mp A3\"],\n [71, \"Mp B3\"],\n [72, \"Mp C4\"],\n [74, \"Mp D4\"],\n [76, \"Mp E4\"],\n [77, \"Mp F4\"],\n [79, \"Mp G4\"],\n [80, \"Mp G#4\"],\n [81, \"Mp A4\"],\n [82, \"Mp A#4\"],\n [83, \"Mp B4\"],\n [85, \"Mp C#5\"],\n [86, \"Mp D5\"],\n [87, \"Mp D#5\"],\n [88, \"Mp E5\"],\n [89, \"Mp F5\"],\n [90, \"Mp F#5\"],\n [91, \"Mp G5\"],\n [92, \"Mp G#5\"],\n [93, \"Mp A5\"],\n [94, \"Mp A#5\"],\n [95, \"Mp B5\"],\n [96, \"Mp C6\"],\n [97, \"Mp C#6\"],\n [98, \"Mp D6\"],\n [99, \"Mp D#6\"],\n [100, \"PP E6\"],\n [101, \"Mp F6\"],\n [102, \"Mp F#6\"],\n [103, \"Mp G6\"],\n [104, \"Mp G#6\"],\n [105, \"Mp A6\"],\n [106, \"Mp A#6\"],\n [107, \"PP B6\"],\n [108, \"PP C7\"],\n ],\n },\n {\n name: \"MF\",\n vel_range: [85, 100],\n samples: [\n [23, \"Mf B-1\"],\n [27, \"Mf D#0\"],\n [29, \"Mf F0\"],\n [31, \"Mf G0\"],\n [33, \"Mf A0\"],\n [35, \"Mf B0\"],\n [37, \"MF C#1\"],\n [38, \"MF D1\"],\n [40, \"MF E1\"],\n [41, \"MF F1\"],\n [43, \"MF G1\"],\n [45, \"MF A1\"],\n [47, \"MF B1\"],\n [48, \"MF C2\"],\n [50, \"MF D2\"],\n [52, \"MF E2\"],\n [53, \"MF F2\"],\n [55, \"MF G2\"],\n [56, \"MF G#2\"],\n [57, \"MF A2\"],\n [58, \"MF A#2\"],\n [59, \"MF B2\"],\n [60, \"MF C3\"],\n [62, \"MF D3\"],\n [64, \"MF E3\"],\n [65, \"MF F3\"],\n [67, \"MF G3\"],\n [69, \"MF A3\"],\n [71, \"MF B3\"],\n [72, \"MF C4\"],\n [74, \"Mf D4\"],\n [76, \"Mf E4\"],\n [77, \"Mf F4\"],\n [79, \"Mf G4\"],\n [80, \"Mf G#4\"],\n [81, \"Mf A4\"],\n [82, \"Mf A#4\"],\n [83, \"Mf B4\"],\n [85, \"Mf C#5\"],\n [86, \"Mf D5\"],\n [87, \"Mf D#5\"],\n [88, \"Mf E5\"],\n [89, \"Mf F5\"],\n [90, \"Mf F#5\"],\n [91, \"Mf G5\"],\n [92, \"Mf G#5\"],\n [93, \"Mf A5\"],\n [94, \"Mf A#5\"],\n [95, \"Mf B5\"],\n [96, \"Mf C6\"],\n [97, \"Mf C#6\"],\n [98, \"Mf D6\"],\n [99, \"Mf D#6\"],\n [100, \"Mf E6\"],\n [101, \"Mf F6\"],\n [102, \"Mf F#6\"],\n [103, \"Mf G6\"],\n [104, \"Mf G#6\"],\n [105, \"Mf A6\"],\n [106, \"Mf A#6\"],\n [107, \"Mf B6\"],\n [108, \"PP C7\"],\n ],\n },\n {\n name: \"FF\",\n vel_range: [101, 127],\n samples: [\n [23, \"FF B-1\"],\n [27, \"FF D#0\"],\n [29, \"FF F0\"],\n [31, \"FF G0\"],\n [33, \"FF A0\"],\n [35, \"FF B0\"],\n [37, \"FF C#1\"],\n [38, \"FF D1\"],\n [40, \"FF E1\"],\n [41, \"FF F1\"],\n [43, \"FF G1\"],\n [45, \"FF A1\"],\n [47, \"FF B1\"],\n [48, \"FF C2\"],\n [50, \"FF D2\"],\n [52, \"FF E2\"],\n [53, \"FF F2\"],\n [55, \"FF G2\"],\n [56, \"FF G#2\"],\n [57, \"FF A2\"],\n [58, \"FF A#2\"],\n [59, \"FF B2\"],\n [60, \"FF C3\"],\n [62, \"FF D3\"],\n [64, \"FF E3\"],\n [65, \"FF F3\"],\n [67, \"FF G3\"],\n [69, \"FF A3\"],\n [71, \"FF B3\"],\n [72, \"FF C4\"],\n [74, \"FF D4\"],\n [76, \"FF E4\"],\n [77, \"FF F4\"],\n [79, \"FF G4\"],\n [80, \"FF G#4\"],\n [81, \"FF A4\"],\n [82, \"FF A#4\"],\n [83, \"FF B4\"],\n [85, \"FF C#5\"],\n [86, \"FF D5\"],\n [88, \"FF E5\"],\n [89, \"FF F5\"],\n [91, \"FF G5\"],\n [93, \"FF A5\"],\n [95, \"Mf B5\"],\n [96, \"Mf C6\"],\n [97, \"Mf C#6\"],\n [98, \"Mf D6\"],\n [99, \"Mf D#6\"],\n [100, \"Mf E6\"],\n [102, \"Mf F#6\"],\n [103, \"Mf G6\"],\n [104, \"Mf G#6\"],\n [105, \"Mf A6\"],\n [106, \"Mf A#6\"],\n [107, \"Mf B6\"],\n [108, \"Mf C7\"],\n ],\n },\n];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACiBO,SAAS,gBACd,OACqB;AAKrB,WAAS,WAAW,MAAY;AAC9B,WAAO,IAAI,MAAM,GAAG,IAAI;AAAA,EAC1B;AACA,SAAO;AACT;;;ACfO,IAAM,cAAuB;AAAA,EAClC,MAAM,KAAK;AACT,WAAO,MAAM,GAAG;AAAA,EAClB;AACF;AAjBA;AAmBA,IAAM,mBAAN,MAA0C;AAAA,EAGxC,YAAY,OAAO,SAAS;AAH9B;AACE;AAGE,QAAI,OAAO,WAAW,eAAe,EAAE,YAAY,SAAS;AAC1D,yBAAK,QAAS,QAAQ,OAAO,4BAA4B;AAGzD,yBAAK,QAAO,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC5B,OAAO;AACL,yBAAK,QAAS,OAAO,KAAK,IAAI;AAAA,IAChC;AAAA,EACF;AAAA,EAEM,MAAM,KAAuC;AAAA;AACjD,YAAM,UAAU,IAAI,QAAQ,GAAG;AAC/B,UAAI;AACF,eAAO,MAAM,sBAAK,8CAAL,WAAmB;AAAA,MAClC,SAAS,KAAK;AACZ,cAAM,WAAW,MAAM,MAAM,OAAO;AACpC,cAAM,sBAAK,8CAAL,WAAmB,SAAS;AAClC,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAeF;AArCE;AADF;AAyBQ,kBAAa,SAAC,SAA4C;AAAA;AAC9D,UAAM,QAAQ,MAAM,mBAAK;AACzB,UAAM,WAAW,MAAM,MAAM,MAAM,OAAO;AAC1C,QAAI,SAAU,QAAO;AAAA,QAChB,OAAM,MAAM,WAAW;AAAA,EAC9B;AAAA;AAEM,kBAAa,SAAC,SAAkB,UAAoB;AAAA;AACxD,QAAI;AACF,YAAM,QAAQ,MAAM,mBAAK;AACzB,YAAM,MAAM,IAAI,SAAS,SAAS,MAAM,CAAC;AAAA,IAC3C,SAAS,KAAK;AAAA,IAAC;AAAA,EACjB;AAAA;AAGK,IAAM,eAAe,gBAAgB,gBAAgB;;;ACtDrD,SAAS,cAAc,OAAgD;AAC5E,QAAM,SAAS,MAAM,OAAO,CAAC,MAAoC,CAAC,CAAC,CAAC;AACpE,SAAO,OAAO,CAAC,GAAG,MAAM;AACtB,UAAM,OAAO,YAAY,IAAI,EAAE,SAAS;AACxC,UAAM,QAAQ,WAAW,IAAI,EAAE,QAAQ;AACvC,SAAK,QAAQ,KAAK;AAClB,WAAO;AAAA,EACT,CAAC;AAED,SAAO,MAAM;AACX,WAAO,OAAO,CAAC,GAAG,MAAM;AACtB,YAAM,OAAO,YAAY,IAAI,EAAE,SAAS;AACxC,YAAM,QAAQ,WAAW,IAAI,EAAE,QAAQ;AACvC,WAAK,WAAW,KAAK;AACrB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;;;ACaO,SAAS,cAAiB,cAA6B;AAC5D,MAAI,UAAU;AACd,QAAM,YAAY,oBAAI,IAAiB;AAEvC,WAAS,UAAU,UAAuB;AACxC,cAAU,IAAI,QAAQ;AACtB,aAAS,OAAO;AAChB,WAAO,MAAM;AACX,gBAAU,OAAO,QAAQ;AAAA,IAC3B;AAAA,EACF;AAEA,WAAS,IAAI,OAAU;AACrB,cAAU;AACV,cAAU,QAAQ,CAAC,aAAa,SAAS,OAAO,CAAC;AAAA,EACnD;AAEA,WAAS,MAAS;AAChB,WAAO;AAAA,EACT;AACA,SAAO,EAAE,WAAW,KAAK,IAAI;AAC/B;;;ACtDO,SAAS,cAAc,KAAa;AACzC,SAAQ,MAAM,MAAO;AACvB;AAEO,SAAS,SAAS,UAAkB;AACzC,SAAO,KAAK,IAAI,IAAI,WAAW,EAAE;AACnC;;;ACRA;AAuBO,IAAM,UAAN,MAAc;AAAA,EAenB,YACkB,SAChB,SACA;AAFgB;AAXlB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAgB;AApClB;AA0CI,uBAAK,SAAU;AAAA,MACb,cAAa,wCAAS,gBAAT,YAAwB,QAAQ;AAAA,MAC7C,SAAQ,wCAAS,WAAT,YAAmB;AAAA,MAC3B,eAAc,wCAAS,iBAAT,YAAyB;AAAA,MACvC,MAAK,wCAAS,QAAT,YAAgB;AAAA,IACvB;AAEA,SAAK,QAAQ,QAAQ,WAAW;AAChC,uBAAK,SAAU,QAAQ,WAAW;AAClC,uBAAK,SAAU,QAAQ,mBAAmB;AAC1C,uBAAK,SAAQ,IAAI,QAAQ,mBAAK,SAAQ;AAEtC,uBAAK,aAAc,cAAc;AAAA,MAC/B,KAAK;AAAA,MACL,mBAAK;AAAA,MACL,mBAAK;AAAA,MACL,mBAAK,SAAQ;AAAA,IACf,CAAC;AAED,UAAM,SAAS,cAAc,mBAAK,SAAQ,MAAM;AAChD,uBAAK,gBAAiB;AACtB,SAAK,YAAY,OAAO;AACxB,uBAAK,cAAe,OAAO,UAAU,CAACA,YAAW;AAC/C,yBAAK,SAAQ,KAAK,QAAQ,mBAAK,SAAQ,aAAaA,OAAM;AAAA,IAC5D,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,SAAiB;AACnB,WAAO,mBAAK,gBAAe,IAAI;AAAA,EACjC;AAAA,EAEA,IAAI,OAAO,OAAe;AACxB,uBAAK,gBAAe,IAAI,KAAK;AAAA,EAC/B;AAAA,EAEA,IAAI,MAAc;AAChB,WAAO,mBAAK,SAAQ,IAAI;AAAA,EAC1B;AAAA,EAEA,IAAI,IAAI,OAAe;AACrB,uBAAK,SAAQ,IAAI,QAAQ;AAAA,EAC3B;AAAA,EAEA,UAAU,QAAiC;AArF7C;AAsFI,QAAI,mBAAK,gBAAe;AACtB,YAAM,MAAM,0CAA0C;AAAA,IACxD;AACA,6BAAK,cAAL,+BAAK,UAAa,CAAC;AACnB,uBAAK,UAAS,KAAK,MAAM;AACzB,uBAAK,aAAL;AACA,uBAAK,aAAc,cAAc;AAAA,MAC/B,KAAK;AAAA,MACL,GAAG,mBAAK;AAAA,MACR,mBAAK;AAAA,MACL,mBAAK;AAAA,MACL,mBAAK,SAAQ;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,UACE,MACA,QACA,UACA;AAzGJ;AA0GI,QAAI,mBAAK,gBAAe;AACtB,YAAM,MAAM,0CAA0C;AAAA,IACxD;AACA,UAAM,MAAM,KAAK,QAAQ,WAAW;AACpC,QAAI,KAAK,QAAQ;AACjB,UAAM,QAAQ,WAAW,SAAS,OAAO,QAAQ;AACjD,UAAM,aAAa,cAAc,CAAC,mBAAK,UAAS,KAAK,KAAK,CAAC;AAE3D,6BAAK,YAAL,+BAAK,QAAW,CAAC;AACjB,uBAAK,QAAO,KAAK,EAAE,MAAM,KAAK,WAAW,CAAC;AAAA,EAC5C;AAAA,EAEA,aAAa,MAAc,KAAa;AAtH1C;AAuHI,QAAI,mBAAK,gBAAe;AACtB,YAAM,MAAM,2CAA2C;AAAA,IACzD;AAEA,UAAM,QAAO,wBAAK,YAAL,mBAAa,KAAK,CAACC,UAASA,MAAK,SAAS;AACvD,QAAI,MAAM;AACR,WAAK,IAAI,KAAK,QAAQ;AAAA,IACxB,OAAO;AACL,cAAQ,KAAK,yBAAyB,IAAI;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA,EAGA,WAAW,MAAc,KAAa;AACpC,SAAK,aAAa,MAAM,GAAG;AAAA,EAC7B;AAAA,EAEA,aAAa;AAxIf;AAyII,QAAI,mBAAK,eAAe;AACxB,uBAAK,eAAgB;AACrB,uBAAK,aAAL;AACA,uBAAK,cAAL;AACA,6BAAK,YAAL,mBAAa,QAAQ,CAAC,SAAS,KAAK,WAAW;AAC/C,uBAAK,QAAS;AAAA,EAChB;AACF;AApHE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpCF,SAAS,eAAe,MAAkC;AACxD,QAAM,QAAQ;AACd,QAAM,IAAI,MAAM,KAAK,IAAI;AACzB,MAAI,CAAC,EAAG;AACR,QAAM,SAAS,EAAE,CAAC,EAAE,YAAY;AAChC,MAAI,CAAC,OAAQ;AAEb,QAAM,MAAM,EAAE,CAAC;AACf,QAAM,MAAM,IAAI,CAAC,MAAM,MAAM,CAAC,IAAI,SAAS,IAAI;AAC/C,QAAM,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;AAE3B,QAAM,QAAQ,OAAO,WAAW,CAAC,IAAI,KAAK;AAC1C,SAAO,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,EAAE,IAAI,IAAI,MAAM,MAAM,MAAM;AAC1D;AAGO,SAAS,OAAO,MAAuD;AAC5E,SAAO,SAAS,SACZ,SACA,OAAO,SAAS,WACd,OACA,eAAe,IAAI;AAC3B;;;ACjBO,IAAM,iBAA2C;AAAA,EACtD,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AACX;AAEA,IAAM,gBAAgB,OAAO,KAAK,cAAc;AAMhD,SAAS,mBAAmB,KAAqC;AAC/D,QAAM,SAAyB,CAAC;AAChC,aAAW,OAAO,eAAe;AAC/B,UAAM,QAAQ,IAAI,GAAG;AACrB,QAAI,UAAU,OAAW,CAAC,OAAmC,GAAG,IAAI;AAAA,EACtE;AACA,SAAO;AACT;AA4BO,SAAS,cACd,UACA,OACA,QACA,MACA,UACA,WACa;AAnEf;AAqEE,QAAM,SAAmC,gEACpC,iBACA,WACA,mBAAmB,KAAK,IACxB,mBAAmB,MAAM;AAO9B,QAAM,SAAQ,kBAAO,UAAP,YAAgB,OAAO,QAAvB,YAA8B;AAC5C,QAAM,YAAY,OAAO;AAGzB,MAAI,UAAU,YAAY,OAAO,QAAQ,MAAM,OAAO;AAGtD,OAAI,uCAAW,YAAW,OAAW,WAAU,UAAU;AAEzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,QAAQ,OAAO;AAAA,IACf,aAAY,4CAAW,eAAX,YAAyB,OAAO;AAAA,IAC5C,WAAW,OAAO;AAAA,IAClB,cAAa,4CAAW,gBAAX,YAA0B,OAAO;AAAA,IAC9C,QAAQ,OAAO;AAAA,IACf,OAAM,4CAAW,SAAX,YAAmB,OAAO;AAAA,IAChC,WAAW,OAAO;AAAA,IAClB,SAAS,OAAO;AAAA,IAChB,aAAa,OAAO;AAAA,IACpB,UAAU,OAAO;AAAA,IACjB,UAAS,4CAAW,YAAX,YAAsB,OAAO;AAAA,EACxC;AACF;;;ACtDA,SAAS,cAAc,QAAsC;AAlD7D;AAmDE,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,MAAI,OAAO,QAAQ,QAAW;AAE5B,aAAS,UAAU,OAAO;AAC1B,YAAQ,OAAO;AAAA,EACjB,WAAW,OAAO,UAAU;AAC1B,KAAC,QAAQ,OAAO,IAAI,OAAO;AAC3B,YAAQ,OAAO;AAAA,EACjB,OAAO;AAEL,aAAS;AACT,cAAU;AACV,YAAQ,OAAO;AAAA,EACjB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAQ,kBAAO,aAAP,mBAAkB,OAAlB,YAAwB;AAAA,IAChC,UAAS,kBAAO,aAAP,mBAAkB,OAAlB,YAAwB;AAAA,IACjC,SAAS,OAAO;AAAA,IAChB,cAAa,YAAO,gBAAP,YAAsB;AAAA,IACnC,OAAO,OAAO;AAAA,IACd,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO;AAAA,IACf,KAAK;AAAA,EACP;AACF;AAEA,SAAS,aAAa,OAAmC;AApFzD;AAqFE,SAAO;AAAA,IACL,SAAQ,iBAAM,aAAN,mBAAiB,OAAjB,YAAuB;AAAA,IAC/B,UAAS,iBAAM,aAAN,mBAAiB,OAAjB,YAAuB;AAAA,IAChC,SAAQ,iBAAM,aAAN,mBAAiB,OAAjB,YAAuB;AAAA,IAC/B,UAAS,iBAAM,aAAN,mBAAiB,OAAjB,YAAuB;AAAA,IAChC,SAAS,MAAM;AAAA,IACf,WAAW,MAAM;AAAA,IACjB,OAAO,MAAM;AAAA,IACb,OAAO,MAAM;AAAA,IACb,SAAS,MAAM,QAAQ,IAAI,aAAa;AAAA,IACxC,KAAK;AAAA,EACP;AACF;AAMA,SAAS,UACP,SACA,SACS;AA1GX;AA2GE,MAAI,CAAC,QAAS,QAAO;AACrB,aAAW,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC1D,UAAM,KAAK,SAAS,OAAO,EAAE;AAC7B,UAAM,SAAQ,aAAQ,IAAI,EAAE,MAAd,YAAmB;AACjC,QAAI,QAAQ,OAAO,QAAQ,KAAM,QAAO;AAAA,EAC1C;AACA,SAAO;AACT;AAlHA;AAwHO,IAAM,gBAAN,MAAoB;AAAA;AAAA,EAIzB,YAAY,MAAmB;AAH/B;AACA;AAGE,uBAAK,SAAU,KAAK,OAAO,IAAI,YAAY;AAC3C,uBAAK,cAAe,oBAAI,IAAI;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MACE,MACA,UACA,SACiB;AA/IrB;AAgJI,UAAM,UAA2B,CAAC;AAElC,aAAS,KAAK,GAAG,KAAK,mBAAK,SAAQ,QAAQ,MAAM;AAC/C,YAAM,QAAQ,mBAAK,SAAQ,EAAE;AAG7B,UAAI,OAAO,MAAM,UAAU,OAAO,MAAM,QAAS;AACjD,UAAI,WAAW,MAAM,UAAU,WAAW,MAAM,QAAS;AACzD,UAAI,CAAC,UAAU,SAAS,MAAM,OAAO,EAAG;AAExC,YAAM,WAAU,wBAAK,cAAa,IAAI,EAAE,MAAxB,YAA6B;AAE7C,iBAAW,UAAU,MAAM,SAAS;AAElC,YAAI,OAAO,OAAO,UAAU,OAAO,OAAO,QAAS;AACnD,YAAI,WAAW,OAAO,UAAU,WAAW,OAAO,QAAS;AAC3D,YAAI,CAAC,UAAU,SAAS,OAAO,OAAO,EAAG;AAIzC,YAAI,MAAM,cAAc,QAAW;AACjC,gBAAM,SAAS,OAAO,cAAc;AACpC,cAAI,UAAU,MAAM,cAAc,OAAQ;AAAA,QAC5C;AAEA,gBAAQ,KAAK;AAAA,UACX,QAAQ,OAAO;AAAA;AAAA;AAAA,UAGf,QAAO,YAAO,UAAP,YAAgB;AAAA,UACvB,QAAO,YAAO,UAAP,YAAgB,MAAM;AAAA,UAC7B,QAAO,YAAO,UAAP,YAAgB,MAAM;AAAA,UAC7B,UAAU,MAAM;AAAA,UAChB,WAAW,OAAO;AAAA,QACpB,CAAC;AAAA,MACH;AAIA,UAAI,MAAM,cAAc,QAAW;AACjC,2BAAK,cAAa,IAAI,IAAI,UAAU,CAAC;AAAA,MACvC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AArEE;AACA;;;AC9GF,SAAsB,gBACpB,SACA,KACA,SACkC;AAAA;AAClC,UAAM,IACH,QAAQ,MAAM,KAAK,EACnB,QAAQ,MAAM,KAAK,EACnB,QAAQ,gBAAgB,IAAI;AAC/B,UAAM,WAAW,MAAM,QAAQ,MAAM,GAAG;AACxC,QAAI,SAAS,WAAW,KAAK;AAC3B,cAAQ;AAAA,QACN;AAAA,QACA,SAAS;AAAA,QACT;AAAA,MACF;AACA;AAAA,IACF;AACA,QAAI;AACF,YAAM,YAAY,MAAM,SAAS,YAAY;AAC7C,YAAM,SAAS,MAAM,QAAQ,gBAAgB,SAAS;AACtD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,KAAK,wBAAwB,OAAO,GAAG;AAAA,IACjD;AAAA,EACF;AAAA;AAGA,SAAS,WAAoB;AAC3B,MAAI,OAAO,cAAc,YAAa,QAAO;AAC7C,QAAM,KAAK,UAAU;AACrB,SACE,GAAG,SAAS,QAAQ,KAAK,CAAC,GAAG,SAAS,QAAQ,KAAK,CAAC,GAAG,SAAS,UAAU;AAE9E;AAEO,SAAS,yBAAyB,SAAkC;AACzE,MAAI,OAAO,aAAa,YAAa,QAAO;AAI5C,QAAM,UAAU,SAAS;AAEzB,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,SAAS,QAAQ,CAAC;AACxB,QAAI,WAAW,WAAW,OAAO;AAC/B;AAAA,IACF;AACA,UAAM,UAAU,MAAM,YAAY,SAAS,MAAM,EAAE;AACnD,QAAI,YAAY,cAAc,YAAY,SAAS;AACjD,aAAO;AAAA,IACT;AAEA,QAAI,WAAW,OAAO;AACpB,YAAMC,WAAU,MAAM,YAAY,WAAW;AAC7C,UAAIA,aAAY,cAAcA,aAAY,SAAS;AACjD,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AC1EA,wBAAAC;AAqDA,IAAM,mBAAN,MAA+C;AAAA,EAK7C,YAAY,SAA2B,SAA+B;AAJtE;AACA;AACA,uBAAAA,SAAmC,oBAAI,IAAI;AAxD7C;AA2DI,uBAAK,UAAW;AAChB,uBAAK,WAAW,wCAAS,YAAT,YAAoB;AAAA,EACtC;AAAA,EAEM,KACJ,MACA,qBAGmC;AAAA;AApEvC;AAsEI,YAAM,YACJ,OAAO,wBAAwB,WAC3B,oBAAoB,UACpB;AACN,YAAM,aACJ,OAAO,wBAAwB,aAC3B,sBACA,2DAAqB;AAE3B,YAAM,UACJ,oCAAyB,KAAK,QAAQ,OAAO,MAA7C,YACA,KAAK,QAAQ,QAAQ,CAAC,MADtB,YAEA;AAEF,YAAM,OAAO,KAAK,QAAQ,QAAQ,QAAQ,OAAO,EAAE;AACnD,YAAM,QAAQ,mBAAmB,IAAI;AACrC,YAAM,QAAQ,MAAM;AACpB,UAAI,SAAS;AAEb,YAAM,SAAS,oBAAI,IAAyB;AAE5C,YAAM,QAAQ;AAAA,QACZ,MAAM,IAAI,CAAO,SAAS;AA5FhC,cAAAC,KAAAC;AA8FQ,gBAAM,MAAM,uCAAW,IAAI;AAC3B,cAAI,KAAK;AACP,mBAAO,IAAI,MAAM,GAAG;AACpB;AACA,qDAAa,QAAQ;AACrB;AAAA,UACF;AAGA,gBAAM,QAAOA,OAAAD,MAAA,KAAK,QAAQ,QAAb,gBAAAA,IAAmB,UAAnB,OAAAC,MAA4B;AACzC,gBAAM,MAAM,GAAG,IAAI,IAAI,IAAI,IAAI,MAAM;AAErC,cAAI,SAAS,mBAAKF,SAAO,IAAI,GAAG;AAEhC,cAAI,CAAC,QAAQ;AACX,kBAAM,UAAU,MAAM;AAAA,cACpB,mBAAK;AAAA,cACL;AAAA,cACA,mBAAK;AAAA,YACP;AACA,gBAAI,SAAS;AACX,uBAAS;AACT,iCAAKA,SAAO,IAAI,KAAK,MAAM;AAAA,YAC7B;AAAA,UACF;AAEA,cAAI,OAAQ,QAAO,IAAI,MAAM,MAAM;AAEnC;AACA,mDAAa,QAAQ;AAAA,QACvB,EAAC;AAAA,MACH;AAEA,aAAO;AAAA,IACT;AAAA;AACF;AA3EE;AACA;AACAA,UAAA;AA4EF,SAAS,mBAAmB,MAA6B;AACvD,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,SAAS,KAAK,QAAQ;AAC/B,eAAW,UAAU,MAAM,SAAS;AAClC,WAAK,IAAI,OAAO,MAAM;AAAA,IACxB;AAAA,EACF;AACA,SAAO,CAAC,GAAG,IAAI;AACjB;AAQO,IAAM,eACX,gBAAgB,gBAAgB;;;ACrJlC;AAIO,IAAM,cAAN,MAAqB;AAAA,EAE1B,YAA4B,SAAiC;AAAjC;AAD5B,+BAAc,CAAC;AAAA,EAC+C;AAAA,EAE9D,KAAK,MAAS;AACZ,UAAM,MAAM,mBAAK,QAAO;AAExB,QAAI,OAAO;AACX,QAAI,QAAQ,MAAM;AAClB,QAAI,QAAQ;AAEZ,WAAO,QAAQ,OAAO;AACpB,YAAM,MAAM,KAAK,OAAO,OAAO,SAAS,CAAC;AACzC,UAAI,KAAK,QAAQ,MAAM,mBAAK,QAAO,GAAG,CAAC,IAAI,GAAG;AAC5C,gBAAQ;AACR,gBAAQ,MAAM;AAAA,MAChB,OAAO;AACL,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AAEA,uBAAK,QAAO,OAAO,OAAO,GAAG,IAAI;AAAA,EACnC;AAAA,EAEA,MAAM;AACJ,WAAO,mBAAK,QAAO,MAAM;AAAA,EAC3B;AAAA,EAEA,OAAsB;AACpB,WAAO,mBAAK,QAAO,CAAC;AAAA,EACtB;AAAA,EAEA,UAAU,WAAiC;AACzC,UAAM,MAAM,mBAAK,QAAO;AACxB,uBAAK,QAAS,mBAAK,QAAO,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,CAAC;AAC3D,WAAO,mBAAK,QAAO,WAAW;AAAA,EAChC;AAAA,EAEA,QAAQ;AACN,uBAAK,QAAS,CAAC;AAAA,EACjB;AAAA,EAEA,OAAO;AACL,WAAO,mBAAK,QAAO;AAAA,EACrB;AACF;AA5CE;;;ACDF,IAAM,uBAAuB;AAC7B,IAAM,sBAAsB;AAL5B,IAAAG,WAAA;AAiDA,IAAM,gBAAN,MAAyC;AAAA,EAOvC,YAAY,SAA2B,SAA4B;AAPrE;AACE,uBAAAA;AACA;AACA;AACA;AACA;AAtDF;AAyDI,uBAAKA,WAAW;AAChB,uBAAK,iBAAiB,wCAAS,gBAAT,YAAwB,wBAAwB;AACtE,uBAAK,cAAc,wCAAS,eAAT,YAAuB;AAC1C,uBAAK,QAAS,IAAI,YAAuB,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AAAA,EACpE;AAAA,EAEA,SAAS,OAAkB,UAA8C;AA/D3E;AAgEI,UAAM,MAAM,mBAAKA,WAAS;AAC1B,UAAM,QAAO,kBAAa,KAAK,MAAlB,YAAuB;AAEpC,QAAI,QAAQ,MAAM,mBAAK,gBAAe;AACpC,eAAS,KAAK;AACd,aAAO;AAAA,IACT;AAEA,UAAM,OAAkB,EAAE,MAAM,OAAO,SAAS;AAChD,uBAAK,QAAO,KAAK,IAAI;AACrB,0BAAK,4CAAL;AAEA,WAAO,MAAM;AACX,yBAAK,QAAO,UAAU,CAAC,MAAM,MAAM,IAAI;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,OAAa;AACX,uBAAK,QAAO,MAAM;AAClB,QAAI,mBAAK,iBAAgB,QAAW;AAClC,oBAAc,mBAAK,YAAW;AAC9B,yBAAK,aAAc;AAAA,IACrB;AAAA,EACF;AAuBF;AA5DEA,YAAA;AACA;AACA;AACA;AACA;AALF;AAwCE,mBAAc,WAAS;AACrB,MAAI,mBAAK,iBAAgB,OAAW;AAEpC,qBAAK,aAAc,YAAY,MAAM;AACnC,UAAM,iBAAiB,mBAAKA,WAAS,cAAc,mBAAK;AAExD,WACE,mBAAK,QAAO,KAAK,IAAI,KACrB,mBAAK,QAAO,KAAK,EAAG,QAAQ,gBAC5B;AACA,YAAM,OAAO,mBAAK,QAAO,IAAI;AAC7B,WAAK,SAAS,KAAK,KAAK;AAAA,IAC1B;AAGA,QAAI,mBAAK,QAAO,KAAK,MAAM,GAAG;AAC5B,oBAAc,mBAAK,YAAW;AAC9B,yBAAK,aAAc;AAAA,IACrB;AAAA,EACF,GAAG,mBAAK,YAAW;AACrB;AAGF,SAAS,aAAa,OAAsC;AAC1D,SAAO,OAAO,UAAU,WAAW,MAAM,OAAO;AAClD;AAEA,IAAM,OAAe,MAAM;AAAC;AAQrB,IAAM,YAA8B,gBAAgB,aAAa;;;AC5HxE,IAAAC,WAAA;AAGO,IAAM,QAAN,MAAY;AAAA,EAYjB,YACE,SACA,QACA,QACA,aACA,QACA,OACA,WACA;AAhBF,uBAAAA;AACA;AACA;AACA;AACA;AACA,+BAA6C;AAC7C,wCAAkC,CAAC;AAWjC,uBAAKA,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,QAAQ;AACb,uBAAK,aAAc,OAAO;AAI1B,UAAM,SAAS,QAAQ,mBAAmB;AAC1C,WAAO,SAAS;AAGhB,UAAM,QAAQ,OAAO;AACrB,QAAI,OAAO,QAAQ;AACjB,aAAO,OAAO,QAAQ;AAAA,IACxB,OAAO;AACL,aAAO,aAAa,QAAQ,KAAK,IAAI,GAAG,QAAQ,IAAI;AAAA,IACtD;AAGA,QAAI,OAAO,UAAU;AACnB,aAAO,OAAO;AACd,aAAO,YAAY,OAAO,WAAW,OAAO,SAAS;AACrD,aAAO,UAAU,OAAO,WAAW,OAAO,SAAS;AAAA,IACrD,WAAW,OAAO,MAAM;AACtB,aAAO,OAAO;AACd,aAAO,YAAY,OAAO;AAC1B,aAAO,UAAU,OAAO,WAAW,OAAO;AAAA,IAC5C;AAGA,QAAI;AACJ,QAAI,OAAO,cAAc,KAAO;AAC9B,YAAM,QAAQ,mBAAmB;AACjC,UAAI,OAAO;AACX,UAAI,UAAU,QAAQ,OAAO;AAAA,IAC/B;AAGA,UAAM,OAAO,QAAQ,WAAW;AAChC,SAAK,KAAK,QAAQ,cAAc,OAAO,QAAQ,IAAI,SAAS,OAAO,MAAM;AAGzE,UAAM,WAAW,QAAQ,WAAW;AACpC,aAAS,KAAK,QAAQ;AAGtB,QAAI,KAAK;AACP,aAAO,QAAQ,GAAG;AAClB,UAAI,QAAQ,IAAI;AAAA,IAClB,OAAO;AACL,aAAO,QAAQ,IAAI;AAAA,IACrB;AACA,SAAK,QAAQ,QAAQ;AACrB,aAAS,QAAQ,WAAW;AAG5B,UAAM,UAAU,gCAAa,QAAQ;AACrC,uBAAK,UAAW;AAKhB,QAAI,YAAY;AAChB,QAAI,OAAO,SAAS,GAAG;AACrB,kBAAY,OAAO,WACd,OAAO,SAAS,OAAO,UAAU,OAAO,aACzC,OAAO,SAAS,OAAO;AAAA,IAC7B;AACA,WAAO,MAAM,SAAS,SAAS;AAE/B,uBAAK,SAAU;AACf,uBAAK,WAAY;AAGjB,WAAO,UAAU,MAAM;AACrB,yBAAK,QAAS;AACd,eAAS,WAAW;AACpB,WAAK,WAAW;AAChB,iCAAK;AACL,aAAO,WAAW;AAClB,iBAAW,MAAM,mBAAK,iBAAiB,IAAG;AAC1C,yBAAK,iBAAkB,CAAC;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK,MAAqB;AACxB,QAAI,mBAAK,YAAW,UAAW;AAC/B,uBAAK,QAAS;AAEd,UAAM,IAAI,sBAAQ,mBAAKA,WAAS;AAEhC,QAAI,KAAK,mBAAK,WAAU;AAEtB,yBAAK,SAAQ,KAAK,CAAC;AAAA,IACrB,OAAO;AAEL,YAAM,SAAS,IAAI,mBAAK;AACxB,yBAAK,WAAU,KAAK,sBAAsB,CAAC;AAC3C,yBAAK,WAAU,KAAK,eAAe,GAAK,CAAC;AACzC,yBAAK,WAAU,KAAK,wBAAwB,GAAG,MAAM;AACrD,yBAAK,SAAQ,KAAK,MAAM;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,IAAsB;AAC5B,QAAI,mBAAK,YAAW,WAAW;AAC7B,SAAG;AAAA,IACL,OAAO;AACL,yBAAK,iBAAgB,KAAK,EAAE;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,IAAI,WAAoB;AACtB,WAAO,mBAAK,YAAW;AAAA,EACzB;AACF;AA5IEA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACbF;AAQO,IAAM,eAAN,MAAmB;AAAA,EAAnB;AAAA;AACL,gCAAsB,oBAAI,IAAI;AAC9B,kCAA8C,oBAAI,IAAI;AACtD,iCAAoC,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM5C,IAAI,OAAoB;AACtB,uBAAK,SAAQ,IAAI,KAAK;AAGtB,gBAAY,mBAAK,YAAW,MAAM,MAAM,EAAE,IAAI,KAAK;AAGnD,QAAI,MAAM,UAAU,QAAW;AAC7B,kBAAY,mBAAK,WAAU,MAAM,KAAK,EAAE,IAAI,KAAK;AAAA,IACnD;AAGA,UAAM,QAAQ,MAAM,sBAAK,oCAAL,WAAa,MAAM;AAAA,EACzC;AAAA;AAAA,EAGA,QAAQ,MAAqB;AAG3B,eAAW,SAAS,CAAC,GAAG,mBAAK,QAAO,GAAG;AACrC,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAGA,SAAS,QAAyB,MAAqB;AACrD,UAAM,SAAS,mBAAK,WAAU,IAAI,MAAM;AACxC,QAAI,CAAC,OAAQ;AACb,eAAW,SAAS,CAAC,GAAG,MAAM,GAAG;AAC/B,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAGA,UAAU,OAAe,MAAqB;AAC5C,UAAM,SAAS,mBAAK,UAAS,IAAI,KAAK;AACtC,QAAI,CAAC,OAAQ;AACb,eAAW,SAAS,CAAC,GAAG,MAAM,GAAG;AAC/B,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,cAAsB;AACxB,WAAO,mBAAK,SAAQ;AAAA,EACtB;AASF;AA9DE;AACA;AACA;AAHK;AAwDL,YAAO,SAAC,OAAoB;AAhE9B;AAiEI,qBAAK,SAAQ,OAAO,KAAK;AACzB,2BAAK,WAAU,IAAI,MAAM,MAAM,MAA/B,mBAAkC,OAAO;AACzC,MAAI,MAAM,UAAU,QAAW;AAC7B,6BAAK,UAAS,IAAI,MAAM,KAAK,MAA7B,mBAAgC,OAAO;AAAA,EACzC;AACF;AAGF,SAAS,YAAkB,KAAqB,KAAgB;AAC9D,MAAI,MAAM,IAAI,IAAI,GAAG;AACrB,MAAI,CAAC,KAAK;AACR,UAAM,oBAAI,IAAI;AACd,QAAI,IAAI,KAAK,GAAG;AAAA,EAClB;AACA,SAAO;AACT;;;AChBA,SAAS,QACP,GACA,GAC8B;AAC9B,MAAI,KAAK;AACP,WAAO,CAAC,MAAM;AACZ,QAAE,CAAC;AACH,QAAE,CAAC;AAAA,IACL;AACF,SAAO,gBAAK;AACd;AAGA,IAAM,aAA0B;AAAA,EAC9B,SAAS,EAAE,SAAS,IAAI,SAAS,CAAC,EAAE;AAAA,EACpC,QAAQ,CAAC;AACX;AAMA,SAAS,YAAY,GAA8B;AACjD,SACE,OAAO,MAAM,YACb,MAAM,QACN,YAAY,KACZ,MAAM,QAAS,EAAkB,MAAM;AAE3C;AA7FA,4GAAAC,UAAA;AA4GO,IAAM,YAAN,MAAiC;AAAA,EA2CtC,YACE,SACA,eACA,cACA;AA/CG;AAeL,sCAA8B,EAAE,QAAQ,GAAG,OAAO,EAAE;AACpD,mCAAa;AACb,iCAAqC,oBAAI,IAAI;AAC7C,yCAA6C,oBAAI,IAAI;AACrD;AACA;AACA;AACA;AACA,uBAAAA;AACA;AACA;AACA;AACA;AACA,iCAAgC,oBAAI,IAAI;AACxC,kCAAY;AAzId;AA4JI,UAAM,OAAO,YAAY,aAAa,IAAI,gBAAgB;AAC1D,UAAM,UAAU,YAAY,aAAa,IACrC,eACC;AAEL,SAAK,UAAU;AACf,uBAAK,WAAY,6BAAM;AACvB,uBAAK,mBAAmB,wCAAS,aAAT,YAAqB;AAC7C,uBAAK,iBAAkB,mCAAS;AAChC,uBAAK,UAAW,mCAAS;AACzB,uBAAK,UAAW,mCAAS;AAEzB,QAAI,6BAAM,SAAS;AACjB,yBAAK,UAAW,IAAI,IAAI,OAAO,QAAQ,KAAK,OAAO,CAAC;AAAA,IACtD;AAGA,uBAAK,UAAW,IAAI,QAAQ,SAAS;AAAA,MACnC,aAAa,mCAAS;AAAA,MACtB,QAAQ,mCAAS;AAAA,MACjB,cAAc,mCAAS;AAAA,MACvB,KAAK,mCAAS;AAAA,IAChB,CAAC;AAGD,SAAK,aAAY,wCAAS,cAAT,YAAsB,UAAU,OAAO;AAGxD,uBAAK,UAAW,IAAI,cAAc,sBAAQ,UAAU;AAGpD,uBAAKA,UAAU,IAAI,aAAa;AAGhC,SAAK,UACH,wCAAS,WAAT,YAAmB,aAAa,SAAS,EAAE,SAAS,mCAAS,QAAQ,CAAC;AAExE,QAAI,MAAM;AAER,WAAK,QAAQ,KAAK,OACf,KAAK,MAAM;AAAA,QACV,YAAY,CAAC,QAAQ,UAAU;AArMzC,cAAAC;AAsMY,6BAAK,eAAgB,EAAE,QAAQ,MAAM;AACrC,WAAAA,MAAA,mBAAK,qBAAL,gBAAAA,IAAA,WAAuB,EAAE,QAAQ,MAAM;AAAA,QACzC;AAAA,MACF,CAAC,EACA,KAAK,CAAC,YAAY;AACjB,2BAAK,UAAW;AAAA,MAClB,CAAC;AAAA,IACL,OAAO;AAEL,WAAK,QAAQ,QAAQ,QAAQ;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,OAAsB;AACxB,WAAO,KAAK,MAAM,KAAK,MAAM,IAAI;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,GAAwB;AAChC,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,eACE,MACA,SACe;AACf,0BAAK,4CAAL,WAAwB;AACxB,UAAM,QAAe,EAAL,uBAAK,YAAL;AAEhB,WAAO,KAAK,OACT,KAAK,MAAM;AAAA,MACV;AAAA,MACA,YAAY,CAAC,QAAQ,UAAU;AAvPvC;AAwPU,2BAAK,eAAgB,EAAE,QAAQ,MAAM;AACrC,iCAAK,qBAAL,8BAAuB,EAAE,QAAQ,MAAM;AAAA,MACzC;AAAA,IACF,CAAC,EACA,KAAK,CAAC,eAAe;AACpB,UAAI,UAAU,mBAAK,YAAY;AAC/B,yBAAK,WAAY,KAAK;AACtB,yBAAK,UAAW,KAAK,UACjB,IAAI,IAAI,OAAO,QAAQ,KAAK,OAAO,CAAC,IACpC;AACJ,yBAAK,UAAW,IAAI,cAAc,IAAI;AACtC,yBAAK,kBAAmB,oBAAI,IAAI;AAChC,yBAAK,UAAW;AAAA,IAClB,CAAC;AAAA,EACL;AAAA;AAAA,EAGA,IAAI,eAA6B;AAC/B,WAAO,mBAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,SAAwB;AAC1B,WAAO,mBAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAY,OAAqB;AACrC,0BAAK,4CAAL,WAAwB;AACxB,uBAAK,UAAS,IAAI,IAAI,KAAK;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAoB;AAhS5B;AAiSI,0BAAK,4CAAL,WAAwB;AACxB,YAAO,wBAAK,UAAS,IAAI,EAAE,MAApB,YAAyB;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,OAAqB;AAC7B,0BAAK,4CAAL,WAAwB;AACxB,QAAI,CAAC,mBAAK,WAAW,oBAAK,WAAY,CAAC;AACvC,uBAAK,WAAU,SAAS;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAW,SAAwB;AACjC,0BAAK,4CAAL,WAAwB;AACxB,QAAI,CAAC,mBAAK,WAAW,oBAAK,WAAY,CAAC;AACvC,uBAAK,WAAU,UAAU;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAA0B;AAC9B,0BAAK,4CAAL,WAAwB;AACxB,UAAM,aAAa,sBAAK,6CAAL,WAAyB;AAE5C,UAAM,gBAAgB,KAAK,UAAU;AAAA,MACnC;AAAA,MACA,CAAC,MAAM,sBAAK,mCAAL,WAAe;AAAA,IACxB;AAEA,WAAO,CAAC,SAAkB;AACxB,oBAAc;AACd,yBAAKD,UAAQ,SAAS,WAAW,QAAQ,IAAI;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,KAAK,QAA2B;AAC9B,0BAAK,4CAAL,WAAwB;AACxB,QAAI,WAAW,QAAW;AACxB,yBAAKA,UAAQ,QAAQ;AAAA,IACvB,WAAW,OAAO,WAAW,YAAY,OAAO,WAAW,UAAU;AACnE,yBAAKA,UAAQ,SAAS,MAAM;AAAA,IAC9B,OAAO;AACL,UAAI,OAAO,WAAW,QAAW;AAC/B,2BAAKA,UAAQ,SAAS,OAAO,QAAQ,OAAO,IAAI;AAAA,MAClD,OAAO;AACL,2BAAKA,UAAQ,QAAQ,OAAO,IAAI;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAgB;AACd,QAAI,mBAAK,WAAW;AACpB,uBAAK,WAAY;AACjB,uBAAKA,UAAQ,QAAQ;AACrB,uBAAK,UAAS,WAAW;AACzB,SAAK,UAAU,KAAK;AAAA,EACtB;AAAA;AAAA,EAGA,aAAmB;AACjB,SAAK,QAAQ;AAAA,EACf;AAsHF;AAjXE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AA7BK;AA+BL,uBAAkB,SAAC,QAAsB;AACvC,MAAI,mBAAK,YAAW;AAClB,UAAM,MAAM,UAAU,MAAM,gCAAgC;AAAA,EAC9D;AACF;AAyOA,eAAU,SAAC,QAAgB,SAA2C;AACpE,MAAI,CAAC,QAAS,QAAO,mBAAK,UAAS,IAAI,MAAM;AAC7C,QAAM,SAAS,mBAAK,kBAAiB,IAAI,MAAM;AAC/C,MAAI,OAAQ,QAAO;AACnB,QAAM,WAAW,mBAAK,UAAS,IAAI,MAAM;AACzC,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,WAAW,KAAK,QAAQ;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AACA,WAAS,KAAK,GAAG,KAAK,SAAS,kBAAkB,MAAM;AACrD,UAAM,OAAO,SAAS,eAAe,EAAE,EAAE,MAAM,EAAE,QAAQ;AACzD,aAAS,cAAc,MAAM,EAAE;AAAA,EACjC;AACA,qBAAK,kBAAiB,IAAI,QAAQ,QAAQ;AAC1C,SAAO;AACT;AAEA,cAAS,SAAC,OAAkC;AA3Y9C;AA4YI,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,UAAU,mBAAK,UAAS,MAAM,MAAM,UAAU,mBAAK,SAAQ;AAGjE,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,UAAU,QAAW;AAC7B,yBAAKA,UAAQ,UAAU,MAAM,OAAO,IAAI;AAAA,IAC1C;AAAA,EACF;AAGA,MAAI,eAAe;AACnB,QAAM,oBAAmB,kCAAW,wBAAK,eAAL,mBAAgB,YAA3B,YAAsC;AAC/D,aAAW,SAAS,SAAS;AAC3B,UAAM,SAAS,sBAAK,oCAAL,WAAgB,MAAM,QAAQ;AAC7C,QAAI,CAAC,OAAQ;AAEb,UAAM,SAAS;AAAA,MACb,mBAAK;AAAA,MACL,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,EAAE,QAAQ,aAAa,MAAM,YAAY,QAAQ;AAAA,IACnD;AAEA,UAAM,QAAQ,IAAI;AAAA,MAChB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,mBAAK,UAAS;AAAA,MACd;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF;AAEA,uBAAKA,UAAQ,IAAI,KAAK;AAGtB,QAAI,CAAC,cAAc;AACjB,yCAAU;AACV,qBAAe;AAAA,IACjB;AAGA,QAAI,SAAS;AACX,YAAM,QAAQ,MAAM,QAAQ,KAAK,CAAC;AAAA,IACpC;AAIA,QAAI,YAAY,MAAM;AACpB,YAAM,SAAS,sBAAQ,KAAK,QAAQ;AACpC,YAAM,YAAY,SAAS;AAC3B,YAAM,KAAK,SAAS;AAAA,IACtB;AAAA,EACF;AACF;AAEA,wBAAmB,SAAC,OAAuC;AArd7D;AAsdI,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAC1D,UAAME,SAAO,kBAAO,KAAK,MAAZ,aAAiB,wBAAK,cAAL,mBAAe,IAAI,OAAO,KAAK,OAAhD,YAAsD;AACnE,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAAA;AAAA,MACA,UAAU,mBAAK;AAAA,MACf,QAAQ;AAAA,MACR,SAAS,mBAAK;AAAA,MACd,SAAS,mBAAK;AAAA,IAChB;AAAA,EACF;AACA,QAAM,QACJ,kBAAO,MAAM,IAAI,MAAjB,aAAsB,wBAAK,cAAL,mBAAe,IAAI,OAAO,MAAM,IAAI,OAA1D,YAAgE;AAClE,SAAO,iCACF,QADE;AAAA,IAEL;AAAA,IACA,WAAU,WAAM,aAAN,YAAkB,mBAAK;AAAA,IACjC,SAAQ,WAAM,WAAN,YAAgB,MAAM;AAAA,IAC9B,SAAS,QAAQ,mBAAK,WAAU,MAAM,OAAO;AAAA,IAC7C,SAAS,QAAQ,mBAAK,WAAU,MAAM,OAAO;AAAA,EAC/C;AACF;;;AC5UF,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,aAAgB,SAGvB;AAIA,QAAM,MAAO,4BAAW,CAAC;AACzB,QAAM,YAAqC,CAAC;AAC5C,aAAW,OAAO,mBAAmB;AACnC,QAAI,OAAO,IAAK,WAAU,GAAG,IAAI,IAAI,GAAG;AAAA,EAC1C;AACA,SAAO,EAAE,WAAsC,YAAY,QAAa;AAC1E;AAEA,SAAS,UAAU,GAAmC;AACpD,SACE,OAAO,MAAM,YACb,MAAM,QACN,OAAQ,EAAyB,SAAS;AAE9C;AASA,SAAS,YAAY,QAAgB,QAAsB;AACzD,aAAW,OAAO,OAAO,oBAAoB,MAAM,GAAG;AACpD,UAAM,OAAO,OAAO,yBAAyB,QAAQ,GAAG;AACxD,QAAI,KAAM,QAAO,eAAe,QAAQ,KAAK,IAAI;AAAA,EACnD;AACF;AAmBO,SAAS,WACd,QACyB;AACzB,WAAS,QACP,KACA,SACuB;AACvB,UAAM,EAAE,WAAW,WAAW,IAAI;AAAA,MAC/B,4BAAW,CAAC;AAAA,IACf;AACA,UAAM,QAAQ,IAAI,UAAU,KAAK,SAAS;AAC1C,UAAM,SAAkB,OAAO,KAAK,YAAY,KAAK;AAErD,QAAI,eAA8B,QAAQ,QAAQ;AAElD,QAAI,UAAU,MAAM;AAClB,UAAI,UAAU,MAAM,GAAG;AACrB,uBAAe;AAAA,MACjB,WAAW,OAAO,WAAW,UAAU;AACrC,cAAM,QAAQ;AACd,YAAI,MAAM,OAAQ,aAAY,OAAO,MAAM,MAAM;AACjD,YAAI,UAAU,MAAM,KAAK,EAAG,gBAAe,MAAM;AAAA,MACnD;AAAA,IACF;AAEA,UAAM,UAAU,YAAY;AAC5B,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;AC/PO,SAAS,wBACd,YACqC;AACrC,SACE,OAAO,eAAe,YACtB,OAAO,WAAW,YAAY,YAC9B,OAAO,WAAW,SAAS,YAC3B,MAAM,QAAQ,WAAW,OAAO,KAChC,MAAM,QAAQ,WAAW,UAAU,KACnC,OAAO,WAAW,qBAAqB,YACvC,OAAO,WAAW,0BAA0B;AAEhD;AAUO,IAAM,mBAA0C;AAAA,EACrD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS,CAAC;AAAA,EACV,YAAY,CAAC;AAAA,EACb,kBAAkB,CAAC;AAAA,EACnB,uBAAuB,CAAC;AAC1B;AAEA,SAAsB,2BACpB,KACA,SACgC;AAAA;AApClC;AAqCE,UAAM,MAAM,MAAM,QAAQ,MAAM,GAAG;AACnC,UAAM,OAAO,MAAM,IAAI,KAAK;AAE5B,SAAK,UAAU,IAAI,QAAQ,YAAY,EAAE;AACzC,SAAK,aAAa,CAAC;AACnB,SAAK,mBAAmB,CAAC;AACzB,SAAK,wBAAwB,CAAC;AAC9B,eAAW,UAAU,KAAK,SAAS;AACjC,WAAK,iBAAiB,MAAM,IAAI;AAChC,YAAM,YAAY,OAAO,QAAQ,GAAG,MAAM,KAAK,MAAM;AACrD,YAAM,CAAC,MAAM,SAAS,IAAI,OAAO,MAAM,SAAS;AAChD,UAAI,CAAC,KAAK,WAAW,SAAS,IAAI,GAAG;AACnC,aAAK,WAAW,KAAK,IAAI;AAAA,MAC3B;AACA,uBAAK,kBAAL,iCAAgC;AAChC,uBAAK,uBAAL,iCAAqC,CAAC;AACtC,UAAI,WAAW;AACb,aAAK,sBAAsB,IAAI,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,EAAE;AAAA,MACzE;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;;;AC3CO,SAAS,sBAAsB;AACpC,SAAO,OAAO,KAAK,WAAW;AAChC;AAEA,IAAM,cAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,kBACE;AACJ;AAkBA,SAAS,UAAU,SAAiD;AA7CpE;AA8CE,QAAM,SAAS;AAAA,IACb,aAAY,wCAAS,eAAT,YAAuB;AAAA,IACnC,UAAS,wCAAS,YAAT,YAAoB;AAAA,IAC7B,MAAK,wCAAS,QAAT,YAAgB;AAAA,EACvB;AACA,MAAI,OAAO,OAAO,eAAe,UAAU;AACzC,WAAO,QAAP,OAAO,MAAQ,YAAY,OAAO,UAAU;AAC5C,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,yBAAyB,OAAO,UAAU;AAAA,EAC9D,WAAW,CAAC,wBAAwB,OAAO,UAAU,GAAG;AACtD,UAAM,IAAI,MAAM,yBAAyB,OAAO,UAAU;AAAA,EAC5D;AAEA,SAAO;AACT;AASO,IAAM,cAAc;AAAA,EACzB,CAAC,KAAuB,UAA8B,CAAC,GAAG,UAAU;AAClE,UAAM,SAAS,UAAU,OAAO;AAGhC,QAAI,aAAoC;AAIxC,UAAM,YAAY,MAAM,MAAM,KAAK,KAAK;AAExC,UAAM,SAA4B;AAAA,MAChC,gBAAgB,MAAM,WAAW,QAAQ,MAAM;AAAA,MAC/C,eAAe,MAAM,WAAW,WAAW,MAAM;AAAA,MACjD,wBAAwB,CAAC,cAAW;AAnF1C;AAoFQ,gCAAW,sBAAsB,SAAS,MAA1C,YAA+C,CAAC;AAAA;AAAA;AAAA;AAAA,MAIlD,OAAO,CAAC,WAAW;AAxFzB;AAyFQ,cAAM,IAAI,OAAO,WAAW,WAAW,SAAS,EAAE,MAAM,OAAO;AAC/D,eAAO,UAAU,iCACZ,IADY;AAAA,UAEf,SACG,OAA0D,WAA1D,YACD,EAAE;AAAA,QACN,EAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,oBAAoB,wBAAwB,OAAO,UAAU,IAC/D,QAAQ,QAAQ,OAAO,UAAU,IACjC,2BAA2B,OAAO,KAAK,OAAO,OAAO;AAEzD,UAAM,QAAQ,kBAAkB,KAAK,CAAC,SAAS;AAC7C,mBAAa;AACb,aAAO,MAAM,eAAe,oBAAoB,IAAI,CAAC;AAAA,IACvD,CAAC;AAED,WAAO,EAAE,QAAQ,MAAM;AAAA,EACzB;AACF;AAgBO,SAAS,oBACd,YACa;AACb,QAAM,UAAkC,CAAC;AACzC,QAAM,UAAiC,CAAC;AAExC,QAAM,YAAY;AAElB,aAAW,QAAQ,QAAQ,CAAC,YAAY,MAAM;AAC5C,UAAM,OAAO,YAAY;AAGzB,YAAQ,UAAU,IAAI;AAEtB,YAAQ,KAAK;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,CAAC,MAAM,IAAI;AAAA,MACrB,OAAO;AAAA,IACT,CAAC;AAAA,EACH,CAAC;AAGD,aAAW,CAAC,WAAW,WAAW,KAAK,OAAO;AAAA,IAC5C,WAAW;AAAA,EACb,GAAG;AACD,QAAI,aAAa;AACf,YAAM,MAAM,WAAW,QAAQ,QAAQ,WAAW;AAClD,UAAI,OAAO,GAAG;AACZ,gBAAQ,SAAS,IAAI,YAAY;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,MACP,SAAS,WAAW;AAAA,MACpB,SAAS,CAAC,OAAO,KAAK;AAAA,IACxB;AAAA,IACA,QAAQ,CAAC,EAAE,QAAQ,CAAC;AAAA,IACpB;AAAA,EACF;AACF;;;AC5JA,IAAM,mBAAmB;AACzB,IAAM,YAAY;AAEX,IAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,mBAA+D;AAAA,EACnE,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAC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AA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACxIO,SAAS,2BAA2B,YAAoB,KAAa;AAC1E,MAAI,WAAW,WAAW,MAAM,EAAG,QAAO;AAC1C,SAAO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AA,MACb,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AAAA,MACZ,CAAC,IAAI,QAAQ;AAAA,MACb,CAAC,IAAI,OAAO;AA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","names":["volume","send","canPlay","_cache","_a","_b","_context","_context","_voices","_a","midi","_a","str","depth","INSTRUMENTS","sampleBaseUrl"]}
|