smplr 0.24.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/dist/index.js CHANGED
@@ -74,6 +74,8 @@ var __async = (__this, __arguments, generator) => {
74
74
  var index_exports = {};
75
75
  __export(index_exports, {
76
76
  CacheStorage: () => CacheStorage,
77
+ DRUM_ABUSE_PACKS: () => DRUM_ABUSE_PACKS,
78
+ DrumAbuse: () => DrumAbuse,
77
79
  DrumMachine: () => DrumMachine,
78
80
  ElectricPiano: () => ElectricPiano,
79
81
  HttpStorage: () => HttpStorage,
@@ -95,7 +97,12 @@ __export(index_exports, {
95
97
  Versilian: () => Versilian,
96
98
  audioBufferToWav: () => audioBufferToWav,
97
99
  audioBufferToWav16: () => audioBufferToWav16,
100
+ drumAbuseSampleUrl: () => drumAbuseSampleUrl,
98
101
  drumMachineToPreset: () => drumMachineToPreset,
102
+ getDrumAbuseMachineNames: () => getDrumAbuseMachineNames,
103
+ getDrumAbuseMachinePack: () => getDrumAbuseMachinePack,
104
+ getDrumAbuseMachinesForPack: () => getDrumAbuseMachinesForPack,
105
+ getDrumAbusePackNames: () => getDrumAbusePackNames,
99
106
  getDrumMachineNames: () => getDrumMachineNames,
100
107
  getElectricPianoNames: () => getElectricPianoNames,
101
108
  getMalletNames: () => getMalletNames,
@@ -379,7 +386,7 @@ function pickPlaybackParams(obj) {
379
386
  return result;
380
387
  }
381
388
  function resolveParams(defaults, group, region, midi, velocity, overrides) {
382
- var _a, _b, _c, _d, _e;
389
+ var _a, _b, _c, _d, _e, _f;
383
390
  const merged = __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, PARAM_DEFAULTS), defaults), pickPlaybackParams(group)), pickPlaybackParams(region));
384
391
  const pitch = (_b = (_a = region.pitch) != null ? _a : region.key) != null ? _b : midi;
385
392
  const semitones = midi - pitch;
@@ -398,7 +405,7 @@ function resolveParams(defaults, group, region, midi, velocity, overrides) {
398
405
  loopEnd: merged.loopEnd,
399
406
  ampVelCurve: region.ampVelCurve,
400
407
  loopAuto: region.loopAuto,
401
- reverse: overrides == null ? void 0 : overrides.reverse
408
+ reverse: (_f = overrides == null ? void 0 : overrides.reverse) != null ? _f : merged.reverse
402
409
  };
403
410
  }
404
411
 
@@ -576,14 +583,6 @@ var SampleLoaderImpl = class {
576
583
  __privateSet(this, _context, context);
577
584
  __privateSet(this, _storage, (_a = options == null ? void 0 : options.storage) != null ? _a : HttpStorage);
578
585
  }
579
- /**
580
- * Load all samples referenced in `json`. Returns a Map of sample name →
581
- * AudioBuffer. Progress is reported via `onProgress` callback or via
582
- * options object.
583
- *
584
- * - `buffers` in options: pre-loaded buffers — skips fetch for these names.
585
- * - All samples load in parallel. Failed samples are silently omitted.
586
- */
587
586
  load(json, onProgressOrOptions) {
588
587
  return __async(this, null, function* () {
589
588
  var _a, _b;
@@ -703,14 +702,6 @@ var SchedulerImpl = class {
703
702
  __privateSet(this, _intervalMs, (_b = options == null ? void 0 : options.intervalMs) != null ? _b : INTERVAL_MS_DEFAULT);
704
703
  __privateSet(this, _queue, new SortedQueue((a, b) => a.time - b.time));
705
704
  }
706
- /**
707
- * Schedule a callback for a NoteEvent.
708
- *
709
- * - If the event's time falls within the lookahead window (or has no time), the
710
- * callback is called synchronously and a no-op StopFn is returned.
711
- * - Otherwise the event is queued, the interval is started if needed, and a StopFn
712
- * is returned that removes the event from the queue before it is dispatched.
713
- */
714
705
  schedule(event, callback) {
715
706
  var _a;
716
707
  const now = __privateGet(this, _context2).currentTime;
@@ -726,10 +717,6 @@ var SchedulerImpl = class {
726
717
  __privateGet(this, _queue).removeAll((q) => q === item);
727
718
  };
728
719
  }
729
- /**
730
- * Clear all queued (not-yet-dispatched) events and stop the interval.
731
- * Does not affect voices that are already playing.
732
- */
733
720
  stop() {
734
721
  __privateGet(this, _queue).clear();
735
722
  if (__privateGet(this, _intervalId) !== void 0) {
@@ -1002,10 +989,12 @@ var SmplrImpl = class {
1002
989
  __privateSet(this, _voices2, new VoiceManager());
1003
990
  this.loader = (_c = options == null ? void 0 : options.loader) != null ? _c : SampleLoader(context, { storage: options == null ? void 0 : options.storage });
1004
991
  if (json) {
1005
- this.ready = this.loader.load(json, (loaded, total) => {
1006
- var _a2;
1007
- __privateSet(this, _loadProgress, { loaded, total });
1008
- (_a2 = __privateGet(this, _onLoadProgress)) == null ? void 0 : _a2.call(this, { loaded, total });
992
+ this.ready = this.loader.load(json, {
993
+ onProgress: (loaded, total) => {
994
+ var _a2;
995
+ __privateSet(this, _loadProgress, { loaded, total });
996
+ (_a2 = __privateGet(this, _onLoadProgress)) == null ? void 0 : _a2.call(this, { loaded, total });
997
+ }
1009
998
  }).then((buffers) => {
1010
999
  __privateSet(this, _buffers, buffers);
1011
1000
  });
@@ -1461,6 +1450,465 @@ function drumMachineToPreset(instrument) {
1461
1450
  };
1462
1451
  }
1463
1452
 
1453
+ // src/drum-abuse/index.ts
1454
+ var DEFAULT_BASE_URL = "https://smpldsnds.github.io";
1455
+ var MIDI_BASE = 36;
1456
+ var DRUM_ABUSE_PACKS = [
1457
+ "vol1",
1458
+ "vol2",
1459
+ "vol3",
1460
+ "vol4",
1461
+ "vol5"
1462
+ ];
1463
+ var MACHINES_BY_PACK = {
1464
+ vol1: [
1465
+ "4-inthefloor-percussioncombo",
1466
+ "ace-tone-rhythm-ace-fr-1",
1467
+ "ace-tone-rhythm-ace-fr-7l",
1468
+ "ace-tone-rhythm-ace-fr6",
1469
+ "ace-tone-rhythm-king",
1470
+ "ace-tone-rhythm-master",
1471
+ "antonelli-2377",
1472
+ "arp-axxe",
1473
+ "conn-min-o-matic",
1474
+ "eko-compu-rhythm",
1475
+ "eko-ritmo-12",
1476
+ "eko-ritmo-20",
1477
+ "elgam-carousel",
1478
+ "emu-modular",
1479
+ "farfisa-pro",
1480
+ "farfisa-rhythm-10",
1481
+ "farfisa-rhythm-maker-16",
1482
+ "gibson-maestro-g-2",
1483
+ "gibson-maestro-rhythm-jester",
1484
+ "gibson-maestro-rhythm-king-mrk-1",
1485
+ "gulbransen-organ",
1486
+ "hammond-rhythm",
1487
+ "hammond-rhythm-ii",
1488
+ "hohner-automatic-rhythm-player",
1489
+ "jen-sx-1000",
1490
+ "kay-r-8",
1491
+ "keio-checkmate",
1492
+ "kent-k-200",
1493
+ "kent-rhythm-master",
1494
+ "korg-kr-33",
1495
+ "korg-krz",
1496
+ "korg-minipops-series",
1497
+ "korg-s-3",
1498
+ "korg-univox-micro-rhythmer-12",
1499
+ "korg-univox-sr-120",
1500
+ "korg-univox-sr-95",
1501
+ "luxor-passat",
1502
+ "moog-modular-55",
1503
+ "roland-arr",
1504
+ "roland-edp-1",
1505
+ "roland-sh-3a",
1506
+ "roland-system-100",
1507
+ "roland-tr-1-prototype",
1508
+ "roland-tr-33",
1509
+ "roland-tr-41-prototype",
1510
+ "roland-tr-66",
1511
+ "roland-tr-77",
1512
+ "seeburg-rhythm-prince",
1513
+ "seeburg-select-a-rhythm",
1514
+ "solton-disco-64",
1515
+ "sonor-mini-mammut-module",
1516
+ "video-tech-rythmic-10",
1517
+ "vox-percussion-king",
1518
+ "whippany-melo-sonic-350",
1519
+ "wurlitzer-swinging-rhythm",
1520
+ "yamaha-cs-15d",
1521
+ "yamaha-cs-5",
1522
+ "yamaha-cs-6",
1523
+ "yamaha-ps-1",
1524
+ "yamaha-ps-2",
1525
+ "yamaha-ps-3"
1526
+ ],
1527
+ vol2: [
1528
+ "bontempi-hf222",
1529
+ "boss-dr-55",
1530
+ "casio-mt-18",
1531
+ "casio-pt-30",
1532
+ "casio-vl-1",
1533
+ "chaser-computer-drum-pr-80",
1534
+ "crb-rhythmboy-480",
1535
+ "eko-musicbox-12",
1536
+ "electro-harmonix-drm-15",
1537
+ "electro-harmonix-drm-16",
1538
+ "electro-harmonix-spacedrum",
1539
+ "elka-drumstar-80",
1540
+ "elka-x-1000",
1541
+ "emu-e-drum",
1542
+ "gem-drum-15",
1543
+ "hammond-autovari-64",
1544
+ "hohner-rhythm-80k",
1545
+ "korg-kpr-77",
1546
+ "korg-kr-55",
1547
+ "korg-kr-mini",
1548
+ "korg-monopoly",
1549
+ "korg-ms-10",
1550
+ "korg-trident",
1551
+ "linn-lm-1",
1552
+ "monacor-rhythmical-choice",
1553
+ "mti-auto-orchestra-ao-1",
1554
+ "multi-moog",
1555
+ "mxr-185",
1556
+ "new-england-digital-synclavier",
1557
+ "oberheim-dmx",
1558
+ "pearl-drum-x",
1559
+ "pollard-syndrum-178",
1560
+ "roland-cr-1000",
1561
+ "roland-cr-68",
1562
+ "roland-cr-78",
1563
+ "roland-cr-80",
1564
+ "roland-cr-8000",
1565
+ "roland-dr-55",
1566
+ "roland-jupiter-8",
1567
+ "roland-pb-300-rhythm-plus",
1568
+ "roland-rhy-33",
1569
+ "roland-rhy-55",
1570
+ "roland-sh-09",
1571
+ "roland-tr-55",
1572
+ "roland-tr-606",
1573
+ "roland-tr-808",
1574
+ "simmons-drum",
1575
+ "simmons-sds-1",
1576
+ "simmons-sds-5",
1577
+ "solton-programmer-24",
1578
+ "star-instruments-synare-3",
1579
+ "star-instruments-synare-ps-1",
1580
+ "visco-space-drum",
1581
+ "watford-electronics-rhythm-generator",
1582
+ "yamaha-cs-40m",
1583
+ "yamaha-mr-10",
1584
+ "yamaha-ps-55"
1585
+ ],
1586
+ vol3: [
1587
+ "amdek-pck-100",
1588
+ "austin-arb-6",
1589
+ "bme-rattlesnake-parametric-percussion-system",
1590
+ "boss-dr-110",
1591
+ "casio-mt-100",
1592
+ "coron-drumsynce-ds-7",
1593
+ "coron-rds",
1594
+ "denon-crb-90",
1595
+ "drumfire-df-2000",
1596
+ "drumfire-df-500",
1597
+ "electro-harmonix-drm-32",
1598
+ "emu-drumulator",
1599
+ "kay-drm-1",
1600
+ "korg-ddm-110",
1601
+ "korg-ddm-220",
1602
+ "korg-poly-800",
1603
+ "linn-linndrum-lm-1-vinyl",
1604
+ "linn-lm-2",
1605
+ "mattel-electronics-synsonics-drm",
1606
+ "mattel-electronics-synsonics-pro",
1607
+ "panasonic-rd-9844",
1608
+ "pearl-drx-1",
1609
+ "roland-ddr-30",
1610
+ "roland-mc-202",
1611
+ "roland-rhy-77",
1612
+ "roland-tr-909",
1613
+ "rsf-dd-30",
1614
+ "sakata-dpm-48",
1615
+ "sequential-circuits-drumtraks",
1616
+ "simmons-clap-trap",
1617
+ "simmons-sds-200",
1618
+ "simmons-sds-400",
1619
+ "soundmaster-sm-8",
1620
+ "soundmaster-sr-88",
1621
+ "tama-ts-206",
1622
+ "tama-ts-305",
1623
+ "wersi-wm-24",
1624
+ "yamaha-dx7"
1625
+ ],
1626
+ vol4: [
1627
+ "atlantex-mpc-1",
1628
+ "boss-hc-2",
1629
+ "boss-pc-2",
1630
+ "casio-ct-310",
1631
+ "casio-mt-500",
1632
+ "casio-mt-800",
1633
+ "casio-pt-68",
1634
+ "casio-pt-82",
1635
+ "casio-sk-1",
1636
+ "dr-b-hm-digital-drums",
1637
+ "emu-sp-12",
1638
+ "ensoniq-mirage",
1639
+ "hing-hon-ek-001",
1640
+ "kawai-acr-20",
1641
+ "kawai-sx-240",
1642
+ "klone-dual-percussion-synthesiser",
1643
+ "korg-ddd-1",
1644
+ "korg-pss-50",
1645
+ "kurzweil-electrodrum-prototype",
1646
+ "linn-9000",
1647
+ "linn-linndrum-lm-2-vinyl",
1648
+ "nasta-hitstix-2",
1649
+ "oberheim-dx",
1650
+ "pearl-sc-40",
1651
+ "rhodes-polaris",
1652
+ "roland-juno-106",
1653
+ "roland-super-quartet-mks-7",
1654
+ "roland-tr-707",
1655
+ "roland-tr-727",
1656
+ "siel-mdp-40",
1657
+ "simmons-sds-1000",
1658
+ "simmons-sds-7",
1659
+ "simmons-sds-8",
1660
+ "simmons-sds-9",
1661
+ "sony-drp-1",
1662
+ "soundmaster-stix-st-305",
1663
+ "suzuki-rpm-40",
1664
+ "tama-ts-500",
1665
+ "technics-ax-5",
1666
+ "technics-pcm-dp-50",
1667
+ "wersi-prisma-dx-5",
1668
+ "yamaha-dd-5",
1669
+ "yamaha-rx-11",
1670
+ "yamaha-rx-15",
1671
+ "yamaha-rx-21",
1672
+ "yamaha-rx-5"
1673
+ ],
1674
+ vol5: [
1675
+ "boss-dr-pad-drp-i",
1676
+ "casio-ct-403",
1677
+ "casio-cz-230s",
1678
+ "casio-ht-700",
1679
+ "casio-rz-1",
1680
+ "cheetah-spec-drum",
1681
+ "forat-f-9000",
1682
+ "korg-ddd-5",
1683
+ "korg-dss-1",
1684
+ "m-p-c-electronics-dsm-1",
1685
+ "pearl-sy-1",
1686
+ "roland-tr-505",
1687
+ "sequential-circuits-studio-440",
1688
+ "simmons-sds-2000",
1689
+ "simmons-sdx",
1690
+ "yamaha-pss-130",
1691
+ "yamaha-ptx8",
1692
+ "yamaha-rx-21l"
1693
+ ]
1694
+ };
1695
+ var machineToPack = (() => {
1696
+ const m = /* @__PURE__ */ new Map();
1697
+ for (const pack of DRUM_ABUSE_PACKS) {
1698
+ for (const id of MACHINES_BY_PACK[pack]) m.set(id, pack);
1699
+ }
1700
+ return m;
1701
+ })();
1702
+ function getDrumAbuseMachineNames() {
1703
+ return [...machineToPack.keys()];
1704
+ }
1705
+ function getDrumAbuseMachinesForPack(pack) {
1706
+ return MACHINES_BY_PACK[pack];
1707
+ }
1708
+ function getDrumAbusePackNames() {
1709
+ return DRUM_ABUSE_PACKS;
1710
+ }
1711
+ function getDrumAbuseMachinePack(id) {
1712
+ return machineToPack.get(id);
1713
+ }
1714
+ var encSeg = (s) => s.split("/").map(encodeURIComponent).join("/");
1715
+ function packBase(baseUrl, pack) {
1716
+ return `${baseUrl}/drum-abuse-${pack}`;
1717
+ }
1718
+ function sampleBaseUrl(baseUrl, pack, urlPath) {
1719
+ return `${packBase(baseUrl, pack)}/samples/${encSeg(urlPath)}/`;
1720
+ }
1721
+ function drumAbuseSampleUrl(pack, urlPath, fileNoExt, format = "wav", baseUrl = DEFAULT_BASE_URL) {
1722
+ return `${sampleBaseUrl(baseUrl, pack, urlPath)}${encodeURIComponent(fileNoExt)}.${format}`;
1723
+ }
1724
+ function stripExt(filename) {
1725
+ return filename.replace(/\.[^.]+$/, "");
1726
+ }
1727
+ var jsonCache = /* @__PURE__ */ new Map();
1728
+ function fetchJSON(url, storage) {
1729
+ let p = jsonCache.get(url);
1730
+ if (!p) {
1731
+ p = storage.fetch(url).then((r) => {
1732
+ if (r.status >= 400) throw new Error(`DrumAbuse: ${r.status} ${url}`);
1733
+ return r.json();
1734
+ });
1735
+ jsonCache.set(url, p);
1736
+ }
1737
+ return p;
1738
+ }
1739
+ function buildMachinePreset(machine, setPath, baseUrl, pack) {
1740
+ if (machine.sample_sets.length === 0) {
1741
+ throw new Error(`DrumAbuse: machine "${machine.id}" has no sample sets`);
1742
+ }
1743
+ const set = setPath ? machine.sample_sets.find((s) => s.path === setPath) : machine.sample_sets[0];
1744
+ if (!set) {
1745
+ throw new Error(`DrumAbuse: set "${setPath}" not found on "${machine.id}"`);
1746
+ }
1747
+ if (set.samples.length === 0) {
1748
+ throw new Error(
1749
+ `DrumAbuse: set "${set.path}" of "${machine.id}" has no samples`
1750
+ );
1751
+ }
1752
+ const sampleNames = [];
1753
+ const groupNames = [];
1754
+ const sampleNamesForGroup = {};
1755
+ const aliases = {};
1756
+ const regions = set.samples.map((file, i) => {
1757
+ const key = stripExt(file);
1758
+ const midi = MIDI_BASE + i;
1759
+ sampleNames.push(key);
1760
+ aliases[key] = midi;
1761
+ const group = set.sample_instruments[i] || "";
1762
+ if (group) {
1763
+ if (!sampleNamesForGroup[group]) {
1764
+ sampleNamesForGroup[group] = [];
1765
+ groupNames.push(group);
1766
+ aliases[group] = midi;
1767
+ }
1768
+ sampleNamesForGroup[group].push(key);
1769
+ }
1770
+ return {
1771
+ sample: key,
1772
+ keyRange: [midi, midi],
1773
+ pitch: midi
1774
+ };
1775
+ });
1776
+ return {
1777
+ preset: {
1778
+ samples: {
1779
+ baseUrl: sampleBaseUrl(baseUrl, pack, set.url_path),
1780
+ formats: ["wav"]
1781
+ },
1782
+ groups: [{ regions }],
1783
+ aliases
1784
+ },
1785
+ sampleNames,
1786
+ groupNames,
1787
+ sampleNamesForGroup,
1788
+ setPath: set.path
1789
+ };
1790
+ }
1791
+ function buildPackPreset(list, baseUrl, pack) {
1792
+ var _a;
1793
+ if (list.length === 0) {
1794
+ throw new Error(`DrumAbuse: empty pack-instrument list for pack "${pack}"`);
1795
+ }
1796
+ const fileCount = {};
1797
+ for (const s of list) {
1798
+ const f = stripExt(s.file);
1799
+ fileCount[f] = ((_a = fileCount[f]) != null ? _a : 0) + 1;
1800
+ }
1801
+ const sampleNames = [];
1802
+ const groupNames = [];
1803
+ const sampleNamesForGroup = {};
1804
+ const map = {};
1805
+ const aliases = {};
1806
+ const regions = list.map((s, i) => {
1807
+ const fileKey = stripExt(s.file);
1808
+ const uniqueKey = `${s.machine_id}/${fileKey}`;
1809
+ const midi = MIDI_BASE + i;
1810
+ sampleNames.push(uniqueKey);
1811
+ aliases[uniqueKey] = midi;
1812
+ if (fileCount[fileKey] === 1) aliases[fileKey] = midi;
1813
+ map[uniqueKey] = `${packBase(baseUrl, pack)}/samples/${encSeg(s.url_path)}/${encodeURIComponent(s.file)}`;
1814
+ if (!sampleNamesForGroup[s.machine_id]) {
1815
+ sampleNamesForGroup[s.machine_id] = [];
1816
+ groupNames.push(s.machine_id);
1817
+ aliases[s.machine_id] = midi;
1818
+ }
1819
+ sampleNamesForGroup[s.machine_id].push(uniqueKey);
1820
+ return {
1821
+ sample: uniqueKey,
1822
+ keyRange: [midi, midi],
1823
+ pitch: midi
1824
+ };
1825
+ });
1826
+ return {
1827
+ preset: {
1828
+ samples: { baseUrl: "", formats: ["wav"], map },
1829
+ groups: [{ regions }],
1830
+ aliases
1831
+ },
1832
+ sampleNames,
1833
+ groupNames,
1834
+ sampleNamesForGroup,
1835
+ setPath: null
1836
+ };
1837
+ }
1838
+ var DrumAbuse = Instrument(
1839
+ (_ctx, options = {}, smplr) => {
1840
+ var _a, _b;
1841
+ const source = options.source;
1842
+ if (!source) {
1843
+ throw new Error("DrumAbuse: options.source is required");
1844
+ }
1845
+ const baseUrl = (_a = options.baseUrl) != null ? _a : DEFAULT_BASE_URL;
1846
+ const storage = (_b = options.storage) != null ? _b : HttpStorage;
1847
+ let sampleNames = [];
1848
+ let groupNames = [];
1849
+ let sampleNamesForGroup = {};
1850
+ let machineId = null;
1851
+ let setPath = null;
1852
+ let packId;
1853
+ let mode;
1854
+ let presetPromise;
1855
+ if (source.kind === "machine") {
1856
+ mode = "machine";
1857
+ const pack = getDrumAbuseMachinePack(source.machine);
1858
+ if (!pack) {
1859
+ throw new Error(`DrumAbuse: unknown machine "${source.machine}"`);
1860
+ }
1861
+ packId = pack;
1862
+ machineId = source.machine;
1863
+ const url = `${packBase(baseUrl, pack)}/machines/${encodeURIComponent(source.machine)}.json`;
1864
+ presetPromise = fetchJSON(url, storage).then((machine) => {
1865
+ const built = buildMachinePreset(machine, source.set, baseUrl, pack);
1866
+ sampleNames = built.sampleNames;
1867
+ groupNames = built.groupNames;
1868
+ sampleNamesForGroup = built.sampleNamesForGroup;
1869
+ setPath = built.setPath;
1870
+ return built.preset;
1871
+ });
1872
+ } else {
1873
+ mode = "pack";
1874
+ if (!DRUM_ABUSE_PACKS.includes(source.pack)) {
1875
+ throw new Error(`DrumAbuse: unknown pack "${source.pack}"`);
1876
+ }
1877
+ packId = source.pack;
1878
+ const url = `${packBase(baseUrl, source.pack)}/instruments/${encodeURIComponent(source.instrument)}.json`;
1879
+ presetPromise = fetchJSON(url, storage).then((list) => {
1880
+ const built = buildPackPreset(list, baseUrl, source.pack);
1881
+ sampleNames = built.sampleNames;
1882
+ groupNames = built.groupNames;
1883
+ sampleNamesForGroup = built.sampleNamesForGroup;
1884
+ return built.preset;
1885
+ });
1886
+ }
1887
+ const baseStart = smplr.start.bind(smplr);
1888
+ const extras = {
1889
+ get mode() {
1890
+ return mode;
1891
+ },
1892
+ getSampleNames: () => sampleNames.slice(),
1893
+ getGroupNames: () => groupNames.slice(),
1894
+ getSampleNamesForGroup: (g) => {
1895
+ var _a2;
1896
+ return ((_a2 = sampleNamesForGroup[g]) != null ? _a2 : []).slice();
1897
+ },
1898
+ getMachineId: () => machineId,
1899
+ getSetPath: () => setPath,
1900
+ getPackId: () => packId,
1901
+ start: (event) => {
1902
+ var _a2;
1903
+ const ev = typeof event === "object" ? event : { note: event };
1904
+ return baseStart(__spreadProps(__spreadValues({}, ev), { stopId: (_a2 = ev.stopId) != null ? _a2 : ev.note }));
1905
+ }
1906
+ };
1907
+ const ready = presetPromise.then((preset) => smplr.loadInstrument(preset));
1908
+ return { extras, ready };
1909
+ }
1910
+ );
1911
+
1464
1912
  // src/offline/wav-encoder.ts
1465
1913
  function audioBufferToWav(buffer) {
1466
1914
  return encodeWav(buffer, 32);
@@ -1754,6 +2202,11 @@ var TransportClock = class {
1754
2202
  *
1755
2203
  * Any checkpoints at or after `audioTime` are removed and replaced with this
1756
2204
  * new anchor, preserving the BPM that was in effect at that time.
2205
+ *
2206
+ * @internal Leaks checkpoint-list semantics; only called by `Sequencer._flush`
2207
+ * for loop-boundary re-anchoring. Not safe to share between Sequencers — see
2208
+ * thoughts/research/2026-05-17_20-18-43_shared-transport.md §3. Must not be
2209
+ * exported from any barrel.
1757
2210
  */
1758
2211
  seekAt(tick, audioTime) {
1759
2212
  let bpm = this._bpm;
@@ -1807,9 +2260,13 @@ var TransportClock = class {
1807
2260
  return cp.tick + (audioTime - cp.audioTime) / this._secondsPerTick(cp.bpm);
1808
2261
  }
1809
2262
  /**
1810
- * Duration in seconds for a given number of ticks at the current BPM.
2263
+ * Convert a tick count to seconds at the current (snapshot) BPM.
2264
+ *
2265
+ * Uses `this._bpm` directly, not the checkpoint history — so after a
2266
+ * mid-play BPM change this returns a value based on the *latest* BPM only.
2267
+ * For checkpoint-aware durations, use `tickToAudioTime(end) - tickToAudioTime(start)`.
1811
2268
  */
1812
- tickDuration(ticks) {
2269
+ ticksToSeconds(ticks) {
1813
2270
  return ticks * this._secondsPerTick(this._bpm);
1814
2271
  }
1815
2272
  // ---------------------------------------------------------------------------
@@ -2096,6 +2553,7 @@ var SequencerImpl = class {
2096
2553
  this._clock.stop();
2097
2554
  this._stopLoop();
2098
2555
  this._endScheduled = false;
2556
+ for (const stopFn of this._activeVoices.values()) stopFn();
2099
2557
  this._activeVoices.clear();
2100
2558
  this._emitStateChange("stopped");
2101
2559
  return this;
@@ -2362,7 +2820,7 @@ var SequencerImpl = class {
2362
2820
  if (Math.random() * 100 >= note.chance) continue;
2363
2821
  }
2364
2822
  const audioTime = this._clock.tickToAudioTime(noteTick);
2365
- const durationSec = note.duration !== void 0 ? this._clock.tickDuration(
2823
+ const durationSec = note.duration !== void 0 ? this._clock.ticksToSeconds(
2366
2824
  parseTicks(note.duration, this._ppq, this._timeSignature)
2367
2825
  ) : void 0;
2368
2826
  const timingOffset = trackHumanize.timing ? (Math.random() * 2 - 1) * trackHumanize.timing / 1e3 : 0;
@@ -2733,8 +3191,10 @@ function createTremolo(context, depth) {
2733
3191
  splitter.disconnect(ampR, 1);
2734
3192
  ampL.disconnect(merger, 0, 0);
2735
3193
  ampR.disconnect(merger, 0, 1);
2736
- lfoL.disconnect(ampL);
2737
- lfoR.disconnect(ampR);
3194
+ lfoL.disconnect(lfoLAmp);
3195
+ lfoLAmp.disconnect(ampL.gain);
3196
+ lfoR.disconnect(lfoRAmp);
3197
+ lfoRAmp.disconnect(ampR.gain);
2738
3198
  merger.disconnect(output);
2739
3199
  };
2740
3200
  return { input, output };
@@ -2805,15 +3265,11 @@ var ElectricPiano = Instrument(
2805
3265
 
2806
3266
  // src/versilian.ts
2807
3267
  var VCSL_BASE_URL = "https://smpldsnds.github.io/sgossner-vcsl";
2808
- var instruments = [];
3268
+ var instrumentsPromise;
2809
3269
  function getVersilianInstruments() {
2810
- return __async(this, null, function* () {
2811
- if (instruments.length) return instruments;
2812
- instruments = yield fetch(VCSL_BASE_URL + "/sfz_files.json").then(
2813
- (res) => res.json()
2814
- );
2815
- return instruments;
2816
- });
3270
+ return instrumentsPromise != null ? instrumentsPromise : instrumentsPromise = fetch(
3271
+ VCSL_BASE_URL + "/sfz_files.json"
3272
+ ).then((res) => res.json());
2817
3273
  }
2818
3274
  var Versilian = Instrument(
2819
3275
  (ctx, options = {}, smplr) => loadVersilianInstrument(smplr, options)
@@ -2823,11 +3279,11 @@ function loadVersilianInstrument(smplr, options) {
2823
3279
  const instrument = (_a = options.instrument) != null ? _a : "Strings/Violin/Violin - Arco";
2824
3280
  const sfzUrl = `${VCSL_BASE_URL}/${instrument}.sfz`;
2825
3281
  const base = instrument.slice(0, instrument.lastIndexOf("/") + 1);
2826
- const sampleBaseUrl = `${VCSL_BASE_URL}/${base}`;
3282
+ const sampleBaseUrl2 = `${VCSL_BASE_URL}/${base}`;
2827
3283
  return fetch(sfzUrl).then((r) => r.text()).then(
2828
3284
  (sfzText) => smplr.loadInstrument(
2829
3285
  sfzToPreset(sfzText, {
2830
- baseUrl: sampleBaseUrl,
3286
+ baseUrl: sampleBaseUrl2,
2831
3287
  pathFromSampleName: (name) => name.replace(/\.wav$/i, ""),
2832
3288
  formats: ["ogg", "m4a"]
2833
3289
  })
@@ -2945,7 +3401,7 @@ function mellotronToPreset(sampleNames, config) {
2945
3401
  for (const sampleName of sampleNames) {
2946
3402
  if (config.variation && !sampleName.includes(config.variation)) continue;
2947
3403
  const midi = toMidi((_a = sampleName.split(" ")[0]) != null ? _a : "");
2948
- if (!midi) continue;
3404
+ if (midi === void 0) continue;
2949
3405
  entries.push([midi, sampleName]);
2950
3406
  }
2951
3407
  const spread = spreadKeyRanges(entries);
@@ -3030,7 +3486,7 @@ var ReverbImpl = class {
3030
3486
  }
3031
3487
  getParam(name) {
3032
3488
  var _a;
3033
- return (_a = __privateGet(this, _effect)) == null ? void 0 : _a.parameters.get("preDelay");
3489
+ return (_a = __privateGet(this, _effect)) == null ? void 0 : _a.parameters.get(name);
3034
3490
  }
3035
3491
  get isReady() {
3036
3492
  return __privateGet(this, _effect) !== void 0;
@@ -3357,10 +3813,9 @@ function fetchSoundfontLoopData(url, sampleRate = 44100) {
3357
3813
  const loopData = {};
3358
3814
  Object.keys(raw).forEach((key) => {
3359
3815
  const midi = toMidi(key);
3360
- if (midi) {
3361
- const offsets = raw[key];
3362
- loopData[midi] = [offsets[0] / sampleRate, offsets[1] / sampleRate];
3363
- }
3816
+ if (midi === void 0) return;
3817
+ const offsets = raw[key];
3818
+ loopData[midi] = [offsets[0] / sampleRate, offsets[1] / sampleRate];
3364
3819
  });
3365
3820
  return loopData;
3366
3821
  } catch (err) {
@@ -3405,7 +3860,7 @@ function decodeSoundfontFile(context, config) {
3405
3860
  yield Promise.all(
3406
3861
  noteNames.map((noteName) => __async(null, null, function* () {
3407
3862
  const midi = toMidi(noteName);
3408
- if (!midi) return;
3863
+ if (midi === void 0) return;
3409
3864
  try {
3410
3865
  const audioData = base64ToArrayBuffer(
3411
3866
  removeBase64Prefix(json[noteName])
@@ -3976,6 +4431,8 @@ var LAYERS = [
3976
4431
  // Annotate the CommonJS export names for ESM import in node:
3977
4432
  0 && (module.exports = {
3978
4433
  CacheStorage,
4434
+ DRUM_ABUSE_PACKS,
4435
+ DrumAbuse,
3979
4436
  DrumMachine,
3980
4437
  ElectricPiano,
3981
4438
  HttpStorage,
@@ -3997,7 +4454,12 @@ var LAYERS = [
3997
4454
  Versilian,
3998
4455
  audioBufferToWav,
3999
4456
  audioBufferToWav16,
4457
+ drumAbuseSampleUrl,
4000
4458
  drumMachineToPreset,
4459
+ getDrumAbuseMachineNames,
4460
+ getDrumAbuseMachinePack,
4461
+ getDrumAbuseMachinesForPack,
4462
+ getDrumAbusePackNames,
4001
4463
  getDrumMachineNames,
4002
4464
  getElectricPianoNames,
4003
4465
  getMalletNames,