@jpdutoit/squelchy 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +4 -3
  2. package/{chunk-NDUSYSHF.js → chunk-N7J25N5J.js} +5 -5
  3. package/chunk-N7J25N5J.js.map +7 -0
  4. package/docs/GUIDE.md +58 -13
  5. package/docs/MODULES.md +7 -7
  6. package/docs/modules.json +14 -14
  7. package/index.d.ts +41 -252
  8. package/index.js +136 -276
  9. package/index.js.map +4 -4
  10. package/kits/compu-78/bd.flac +0 -0
  11. package/kits/compu-78/ch.flac +0 -0
  12. package/kits/compu-78/clap.flac +0 -0
  13. package/kits/compu-78/cym.flac +0 -0
  14. package/kits/compu-78/ht.flac +0 -0
  15. package/kits/compu-78/lt.flac +0 -0
  16. package/kits/compu-78/mt.flac +0 -0
  17. package/kits/compu-78/oh.flac +0 -0
  18. package/kits/compu-78/perc.flac +0 -0
  19. package/kits/compu-78/rim.flac +0 -0
  20. package/kits/compu-78/sd.flac +0 -0
  21. package/kits/compu-78.d.ts +7 -0
  22. package/kits/compu-78.js +22 -0
  23. package/kits/deep-analogue/bd.flac +0 -0
  24. package/kits/deep-analogue/ch.flac +0 -0
  25. package/kits/deep-analogue/clap.flac +0 -0
  26. package/kits/deep-analogue/cym.flac +0 -0
  27. package/kits/deep-analogue/ht.flac +0 -0
  28. package/kits/deep-analogue/lt.flac +0 -0
  29. package/kits/deep-analogue/mt.flac +0 -0
  30. package/kits/deep-analogue/oh.flac +0 -0
  31. package/kits/deep-analogue/perc.flac +0 -0
  32. package/kits/deep-analogue/rim.flac +0 -0
  33. package/kits/deep-analogue/sd.flac +0 -0
  34. package/kits/deep-analogue.d.ts +7 -0
  35. package/kits/deep-analogue.js +22 -0
  36. package/kits/dr5-studio/bd.flac +0 -0
  37. package/kits/dr5-studio/ch.flac +0 -0
  38. package/kits/dr5-studio/clap.flac +0 -0
  39. package/kits/dr5-studio/cym.flac +0 -0
  40. package/kits/dr5-studio/ht.flac +0 -0
  41. package/kits/dr5-studio/lt.flac +0 -0
  42. package/kits/dr5-studio/mt.flac +0 -0
  43. package/kits/dr5-studio/oh.flac +0 -0
  44. package/kits/dr5-studio/perc.flac +0 -0
  45. package/kits/dr5-studio/rim.flac +0 -0
  46. package/kits/dr5-studio/sd.flac +0 -0
  47. package/kits/dr5-studio.d.ts +7 -0
  48. package/kits/dr5-studio.js +22 -0
  49. package/kits/hard-cell/bd.flac +0 -0
  50. package/kits/hard-cell/ch.flac +0 -0
  51. package/kits/hard-cell/clap.flac +0 -0
  52. package/kits/hard-cell/cym.flac +0 -0
  53. package/kits/hard-cell/ht.flac +0 -0
  54. package/kits/hard-cell/lt.flac +0 -0
  55. package/kits/hard-cell/mt.flac +0 -0
  56. package/kits/hard-cell/oh.flac +0 -0
  57. package/kits/hard-cell/perc.flac +0 -0
  58. package/kits/hard-cell/rim.flac +0 -0
  59. package/kits/hard-cell/sd.flac +0 -0
  60. package/kits/hard-cell.d.ts +7 -0
  61. package/kits/hard-cell.js +22 -0
  62. package/kits/micro-click/bd.flac +0 -0
  63. package/kits/micro-click/ch.flac +0 -0
  64. package/kits/micro-click/clap.flac +0 -0
  65. package/kits/micro-click/cym.flac +0 -0
  66. package/kits/micro-click/ht.flac +0 -0
  67. package/kits/micro-click/lt.flac +0 -0
  68. package/kits/micro-click/mt.flac +0 -0
  69. package/kits/micro-click/oh.flac +0 -0
  70. package/kits/micro-click/perc.flac +0 -0
  71. package/kits/micro-click/rim.flac +0 -0
  72. package/kits/micro-click/sd.flac +0 -0
  73. package/kits/micro-click.d.ts +7 -0
  74. package/kits/micro-click.js +22 -0
  75. package/kits/roland-808/bd.flac +0 -0
  76. package/kits/roland-808/ch.flac +0 -0
  77. package/kits/roland-808/clap.flac +0 -0
  78. package/kits/roland-808/cym.flac +0 -0
  79. package/kits/roland-808/ht.flac +0 -0
  80. package/kits/roland-808/lt.flac +0 -0
  81. package/kits/roland-808/mt.flac +0 -0
  82. package/kits/roland-808/oh.flac +0 -0
  83. package/kits/roland-808/perc.flac +0 -0
  84. package/kits/roland-808/rim.flac +0 -0
  85. package/kits/roland-808/sd.flac +0 -0
  86. package/kits/roland-808.d.ts +7 -0
  87. package/kits/roland-808.js +22 -0
  88. package/kits/rx5-fm/bd.flac +0 -0
  89. package/kits/rx5-fm/ch.flac +0 -0
  90. package/kits/rx5-fm/clap.flac +0 -0
  91. package/kits/rx5-fm/cym.flac +0 -0
  92. package/kits/rx5-fm/ht.flac +0 -0
  93. package/kits/rx5-fm/lt.flac +0 -0
  94. package/kits/rx5-fm/mt.flac +0 -0
  95. package/kits/rx5-fm/oh.flac +0 -0
  96. package/kits/rx5-fm/perc.flac +0 -0
  97. package/kits/rx5-fm/rim.flac +0 -0
  98. package/kits/rx5-fm/sd.flac +0 -0
  99. package/kits/rx5-fm.d.ts +7 -0
  100. package/kits/rx5-fm.js +22 -0
  101. package/kits/tape-dust/bd.flac +0 -0
  102. package/kits/tape-dust/ch.flac +0 -0
  103. package/kits/tape-dust/clap.flac +0 -0
  104. package/kits/tape-dust/cym.flac +0 -0
  105. package/kits/tape-dust/ht.flac +0 -0
  106. package/kits/tape-dust/lt.flac +0 -0
  107. package/kits/tape-dust/mt.flac +0 -0
  108. package/kits/tape-dust/oh.flac +0 -0
  109. package/kits/tape-dust/perc.flac +0 -0
  110. package/kits/tape-dust/rim.flac +0 -0
  111. package/kits/tape-dust/sd.flac +0 -0
  112. package/kits/tape-dust.d.ts +7 -0
  113. package/kits/tape-dust.js +22 -0
  114. package/kits/tr-606/bd.flac +0 -0
  115. package/kits/tr-606/ch.flac +0 -0
  116. package/kits/tr-606/cym.flac +0 -0
  117. package/kits/tr-606/ht.flac +0 -0
  118. package/kits/tr-606/lt.flac +0 -0
  119. package/kits/tr-606/mt.flac +0 -0
  120. package/kits/tr-606/oh.flac +0 -0
  121. package/kits/tr-606/sd.flac +0 -0
  122. package/kits/tr-606.d.ts +7 -0
  123. package/kits/tr-606.js +19 -0
  124. package/kits/tr-707/bd.flac +0 -0
  125. package/kits/tr-707/ch.flac +0 -0
  126. package/kits/tr-707/clap.flac +0 -0
  127. package/kits/tr-707/cym.flac +0 -0
  128. package/kits/tr-707/ht.flac +0 -0
  129. package/kits/tr-707/lt.flac +0 -0
  130. package/kits/tr-707/mt.flac +0 -0
  131. package/kits/tr-707/oh.flac +0 -0
  132. package/kits/tr-707/perc.flac +0 -0
  133. package/kits/tr-707/rim.flac +0 -0
  134. package/kits/tr-707/sd.flac +0 -0
  135. package/kits/tr-707.d.ts +7 -0
  136. package/kits/tr-707.js +22 -0
  137. package/kits/tr-909/bd.flac +0 -0
  138. package/kits/tr-909/ch.flac +0 -0
  139. package/kits/tr-909/clap.flac +0 -0
  140. package/kits/tr-909/cym.flac +0 -0
  141. package/kits/tr-909/ht.flac +0 -0
  142. package/kits/tr-909/lt.flac +0 -0
  143. package/kits/tr-909/mt.flac +0 -0
  144. package/kits/tr-909/oh.flac +0 -0
  145. package/kits/tr-909/perc.flac +0 -0
  146. package/kits/tr-909/rim.flac +0 -0
  147. package/kits/tr-909/sd.flac +0 -0
  148. package/kits/tr-909.d.ts +7 -0
  149. package/kits/tr-909.js +22 -0
  150. package/package.json +6 -3
  151. package/{worklets-inline-MUVFLGPY.js → worklets-inline-EF3OTQ4D.js} +2 -2
  152. package/chunk-NDUSYSHF.js.map +0 -7
  153. package/meta.json +0 -4492
  154. /package/{worklets-inline-MUVFLGPY.js.map → worklets-inline-EF3OTQ4D.js.map} +0 -0
package/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  tape_stop_default,
21
21
  vca_default,
22
22
  waveshaper_default
23
- } from "./chunk-NDUSYSHF.js";
23
+ } from "./chunk-N7J25N5J.js";
24
24
 
25
25
  // src/lib-runtime/core.ts
26
26
  var pendingSources = {};
@@ -28,7 +28,7 @@ var registrations = /* @__PURE__ */ new WeakMap();
28
28
  function preload(ctx, opts) {
29
29
  const existing = registrations.get(ctx);
30
30
  if (existing) return existing;
31
- const sources = opts?.allWorklets ? import("./worklets-inline-MUVFLGPY.js").then((m) => m.WORKLET_SOURCES) : Promise.resolve(pendingSources);
31
+ const sources = opts?.allWorklets ? import("./worklets-inline-EF3OTQ4D.js").then((m) => m.WORKLET_SOURCES) : Promise.resolve(pendingSources);
32
32
  const promise = sources.then(
33
33
  (map) => Promise.all(Object.entries(map).map(async ([name, src]) => {
34
34
  const url = URL.createObjectURL(new Blob([src], { type: "text/javascript" }));
@@ -141,7 +141,7 @@ var Instance = class {
141
141
  // src/lib-runtime/time/transport.ts
142
142
  var EPS = 1e-9;
143
143
  function isRest(v) {
144
- return v == null || v === false || v === 0 || v === "." || v === "-";
144
+ return v == null || v === false;
145
145
  }
146
146
  function normStep(s) {
147
147
  if (isRest(s)) return null;
@@ -356,8 +356,13 @@ function createTransport(ctx, opts = {}) {
356
356
  };
357
357
  return t;
358
358
  }
359
- function steps(s) {
360
- return [...s.replace(/[\s|]/g, "")].map((c) => c === "x" || c === "X");
359
+ function steps(s, levels = {}) {
360
+ const velocity = { X: levels.accent ?? 1, x: levels.normal ?? 0.75, o: levels.ghost ?? 0.4 };
361
+ return [...s.replace(/[\s|]/g, "")].map((c) => {
362
+ if (c === "." || c === "-") return null;
363
+ if (!(c in velocity)) throw new Error(`steps(): unknown character "${c}" in "${s}" (X accent, x hit, o ghost, . or - rest)`);
364
+ return { value: true, velocity: velocity[c] };
365
+ });
361
366
  }
362
367
  var NOTE_RE = /^([A-Ga-g])([#b]?)(-?\d+)$/;
363
368
  var PC = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 };
@@ -526,16 +531,28 @@ var asPitch = (n) => n;
526
531
 
527
532
  // src/lib/dsp/pulse.ts
528
533
  var PULSE_S = 1e-3;
529
- function pulse(target, when) {
530
- const ctx = target.context;
531
- const at = Math.max(when ?? 0, ctx.currentTime);
532
- const src = ctx.createConstantSource();
533
- src.offset.value = 1;
534
+ var pulseBuffers = /* @__PURE__ */ new WeakMap();
535
+ function filled(ctx, samples, level) {
536
+ const buf = ctx.createBuffer(1, samples, ctx.sampleRate);
537
+ buf.getChannelData(0).fill(level);
538
+ return buf;
539
+ }
540
+ function play(ctx, buf, target, when) {
541
+ const src = ctx.createBufferSource();
542
+ src.buffer = buf;
534
543
  src.connect(target);
535
- src.start(at);
536
- src.stop(at + PULSE_S);
544
+ src.start(Math.max(0, when ?? 0));
537
545
  src.onended = () => src.disconnect();
538
546
  }
547
+ function pulse(target, when) {
548
+ const ctx = target.context;
549
+ let buf = pulseBuffers.get(ctx);
550
+ if (!buf) {
551
+ buf = filled(ctx, Math.max(1, Math.ceil(ctx.sampleRate * PULSE_S)), 1);
552
+ pulseBuffers.set(ctx, buf);
553
+ }
554
+ play(ctx, buf, target, when);
555
+ }
539
556
 
540
557
  // src/lib/samples/types.ts
541
558
  var VOICE_KEYS = [
@@ -566,17 +583,12 @@ var VOICE_FALLBACKS = {
566
583
  };
567
584
 
568
585
  // src/lib-runtime/samples.ts
569
- var DEFAULT_SAMPLE_BASE_URL = "https://squelchy.studio";
570
- function defineSampleSets(sets) {
571
- return sets;
572
- }
573
586
  async function loadSampleSet(ctx, set, opts = {}) {
574
- const base = opts.baseUrl ?? DEFAULT_SAMPLE_BASE_URL;
575
587
  const f = opts.fetch ?? fetch;
576
588
  const buffers = {};
577
589
  await Promise.all(
578
- Object.entries(set.voices).map(async ([key, path]) => {
579
- const res = await f(new URL(path, base).href);
590
+ Object.entries(set.voices).map(async ([key, url]) => {
591
+ const res = await f(url);
580
592
  if (!res.ok) throw new Error(`loadSampleSet: ${key} ${res.status}`);
581
593
  buffers[key] = await ctx.decodeAudioData(await res.arrayBuffer());
582
594
  })
@@ -590,19 +602,19 @@ async function loadSampleSet(ctx, set, opts = {}) {
590
602
  };
591
603
  }
592
604
  var SampleVoice = {
593
- create(ctx, kit, key) {
605
+ create(ctx, kit, key, opts = {}) {
594
606
  const out = ctx.createGain();
595
607
  const buf = kit.buffer(key);
608
+ const root = opts.root ?? 60;
596
609
  const trigger = (when, h) => {
597
610
  if (!buf) return;
598
611
  const src = ctx.createBufferSource();
599
612
  const g = ctx.createGain();
600
613
  src.buffer = buf;
601
- if (typeof h?.value === "number") src.playbackRate.value = 2 ** (h.value / 12);
614
+ if (typeof h?.value === "number") src.playbackRate.value = 2 ** ((h.value - root) / 12);
602
615
  g.gain.value = Math.max(0, Math.min(1, h?.velocity ?? 1));
603
616
  src.connect(g).connect(out);
604
617
  src.start(when);
605
- if (h?.duration) src.stop(when + h.duration);
606
618
  };
607
619
  return {
608
620
  output: out,
@@ -616,238 +628,6 @@ var SampleVoice = {
616
628
  }
617
629
  };
618
630
 
619
- // src/lib-runtime/generated/sample-sets.ts
620
- var SampleSets = /* @__PURE__ */ defineSampleSets({
621
- "roland-808": {
622
- "name": "Roland TR-808",
623
- "blurb": "The original machine, sampled from hardware. Deep sub kick, ticking hats.",
624
- "family": "Machines",
625
- "credit": "Michael Fischer / Technopolis TR-808 sample set, released to the public domain",
626
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
627
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
628
- "voices": {
629
- "bd": "/__l5e/assets-v1/c4b2fc55-dcf1-4248-a7fb-2cd3653a659b/roland-808-bd.flac",
630
- "ch": "/__l5e/assets-v1/c1ec3b3d-571f-46a6-9d05-12b2fe5f6fc5/roland-808-ch.flac",
631
- "clap": "/__l5e/assets-v1/8bd15e4b-96b7-46b6-b26a-35283c816f1e/roland-808-clap.flac",
632
- "cym": "/__l5e/assets-v1/033f0719-913a-4a7a-998e-92a7319d806f/roland-808-cym.flac",
633
- "ht": "/__l5e/assets-v1/ca555782-7544-446a-a461-9b56b4d30072/roland-808-ht.flac",
634
- "lt": "/__l5e/assets-v1/8e100e1c-3844-42aa-bbe7-9eb52b9d704e/roland-808-lt.flac",
635
- "mt": "/__l5e/assets-v1/93dd309f-9347-4ea1-909f-56196b08dc88/roland-808-mt.flac",
636
- "oh": "/__l5e/assets-v1/4881941c-b558-4159-babd-fe224b0f1543/roland-808-oh.flac",
637
- "perc": "/__l5e/assets-v1/d13076b5-50ca-4675-9d4e-70afd6e6203d/roland-808-perc.flac",
638
- "rim": "/__l5e/assets-v1/ce82e0e9-402d-4a5e-bf01-59dfb922d1ba/roland-808-rim.flac",
639
- "sd": "/__l5e/assets-v1/67a799c9-e019-442b-8025-99d69bc493b9/roland-808-sd.flac"
640
- }
641
- },
642
- "tr-909": {
643
- "name": "Roland TR-909",
644
- "blurb": "Punchy transistor kick, snappy sampled snare, sizzling metal hats. House and techno.",
645
- "family": "Machines",
646
- "credit": "MckAudio TR8 sample pack, dedicated to the public domain (CC0)",
647
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
648
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
649
- "voices": {
650
- "bd": "/__l5e/assets-v1/fd3911bb-6783-4db6-bee2-bb8c5a589f26/tr-909-bd.flac",
651
- "ch": "/__l5e/assets-v1/6f795c20-fb89-4cd5-b696-3a505d487baa/tr-909-ch.flac",
652
- "clap": "/__l5e/assets-v1/7b1ccf8e-0dd6-4189-82d7-03a910e895f2/tr-909-clap.flac",
653
- "cym": "/__l5e/assets-v1/f0d5ce25-3238-4e89-bb09-f5b7118fa0a7/tr-909-cym.flac",
654
- "ht": "/__l5e/assets-v1/5f9b4c37-25a7-492c-aaed-f7fe24fbfe2c/tr-909-ht.flac",
655
- "lt": "/__l5e/assets-v1/8477dddd-b9ed-4957-9a48-b5501bc77056/tr-909-lt.flac",
656
- "mt": "/__l5e/assets-v1/92d461e5-d74a-4ba2-a899-4dea1ad06d13/tr-909-mt.flac",
657
- "oh": "/__l5e/assets-v1/20c51259-d8d1-4ee3-a1d6-e850c3227b1a/tr-909-oh.flac",
658
- "perc": "/__l5e/assets-v1/147d346e-9ae7-4413-a50a-de4f03ef7342/tr-909-perc.flac",
659
- "rim": "/__l5e/assets-v1/0c9f157d-1329-4804-aa12-6819651d69fb/tr-909-rim.flac",
660
- "sd": "/__l5e/assets-v1/bd8069c2-e07c-4d5c-b05a-fb5b9a31eadb/tr-909-sd.flac"
661
- }
662
- },
663
- "tr-707": {
664
- "name": "Roland TR-707",
665
- "blurb": "Twelve-bit sampled kit with early-digital crunch. Big eighties snare and claps.",
666
- "family": "Machines",
667
- "credit": "MckAudio TR8 sample pack, dedicated to the public domain (CC0)",
668
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
669
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
670
- "voices": {
671
- "bd": "/__l5e/assets-v1/825b2c7c-5c5f-411c-8191-306549ee26f2/tr-707-bd.flac",
672
- "ch": "/__l5e/assets-v1/6b35b393-7e9c-462d-8d2f-dc834417062b/tr-707-ch.flac",
673
- "clap": "/__l5e/assets-v1/efbe819a-b13e-4bf2-a6bd-9bc15a09ff3f/tr-707-clap.flac",
674
- "cym": "/__l5e/assets-v1/4a34902b-8592-46d8-b339-05a0648cac4f/tr-707-cym.flac",
675
- "ht": "/__l5e/assets-v1/e58beee9-45e5-4b65-af99-a05fcb96f55b/tr-707-ht.flac",
676
- "lt": "/__l5e/assets-v1/a0d6f499-4af6-4d34-96de-5ad7c2397229/tr-707-lt.flac",
677
- "mt": "/__l5e/assets-v1/6c4bd12b-78ff-4f70-863b-cd482f684eb6/tr-707-mt.flac",
678
- "oh": "/__l5e/assets-v1/c07159f3-d763-4698-a786-aeae60d38ac9/tr-707-oh.flac",
679
- "perc": "/__l5e/assets-v1/2f8cffcb-8e86-4f65-99db-a705727ed3ab/tr-707-perc.flac",
680
- "rim": "/__l5e/assets-v1/3d6445b1-38bd-4e9f-b048-db8c079b3c03/tr-707-rim.flac",
681
- "sd": "/__l5e/assets-v1/aaf70dd8-c740-4b05-9369-feb80f3e26be/tr-707-sd.flac"
682
- }
683
- },
684
- "tr-606": {
685
- "name": "Roland TR-606",
686
- "blurb": "Tiny Drumatix voices \u2014 thin kick, spitty snare, ticking hats. Perfect with a 303.",
687
- "family": "Machines",
688
- "credit": "MckAudio TR8 sample pack, dedicated to the public domain (CC0)",
689
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
690
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
691
- "voices": {
692
- "bd": "/__l5e/assets-v1/f46ec897-9319-4c25-b63b-74df979de508/tr-606-bd.flac",
693
- "ch": "/__l5e/assets-v1/f4c57254-c711-43b0-82c6-52b011e205ba/tr-606-ch.flac",
694
- "cym": "/__l5e/assets-v1/db524ec1-36d3-43db-bfc4-fd84a1ddd2ac/tr-606-cym.flac",
695
- "ht": "/__l5e/assets-v1/74b486cf-c1f1-45c7-bd2a-4fd0c3794e1a/tr-606-ht.flac",
696
- "lt": "/__l5e/assets-v1/6b1a564f-6388-40c1-8028-3ea9b6824256/tr-606-lt.flac",
697
- "mt": "/__l5e/assets-v1/d871a86a-fcc8-45a6-b5a4-83977a689593/tr-606-mt.flac",
698
- "oh": "/__l5e/assets-v1/a4c607d2-d62c-49b5-ac99-549fd6262468/tr-606-oh.flac",
699
- "sd": "/__l5e/assets-v1/2062f1d4-e34f-406f-911b-2eb2ec523a89/tr-606-sd.flac"
700
- }
701
- },
702
- "compu-78": {
703
- "name": "Compu-78",
704
- "blurb": "Tiny, dry preset-box percussion. Bossa nova organ rhythm energy.",
705
- "family": "Machines",
706
- "credit": "Synthesised for Squelchy",
707
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
708
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
709
- "voices": {
710
- "bd": "/__l5e/assets-v1/150a91e2-8b92-40f2-80e0-10b30f10976b/compu-78-bd.flac",
711
- "ch": "/__l5e/assets-v1/da9dcfc4-5f29-43b9-979f-9679edeb09ed/compu-78-ch.flac",
712
- "clap": "/__l5e/assets-v1/f3b5d485-44bc-4b34-b2bc-d37f436dffc2/compu-78-clap.flac",
713
- "cym": "/__l5e/assets-v1/627db2bf-08d5-4054-8de9-b8ec0ca4436a/compu-78-cym.flac",
714
- "ht": "/__l5e/assets-v1/1323f20c-3c98-45fb-abd1-e4b1e4be158f/compu-78-ht.flac",
715
- "lt": "/__l5e/assets-v1/ba67ce5c-3f01-4e1b-9fd8-a96bb5428cf4/compu-78-lt.flac",
716
- "mt": "/__l5e/assets-v1/f8cd42d6-2f98-4e9d-9428-ba091ec125cf/compu-78-mt.flac",
717
- "oh": "/__l5e/assets-v1/b4a1d5b2-0022-4f1b-ac52-1618ba03ea67/compu-78-oh.flac",
718
- "perc": "/__l5e/assets-v1/55e15a92-ba17-48cb-aec0-47e5198f073f/compu-78-perc.flac",
719
- "rim": "/__l5e/assets-v1/698aaf24-8e84-4b3b-8f13-dc95f2b3f157/compu-78-rim.flac",
720
- "sd": "/__l5e/assets-v1/41357245-d767-410e-8415-08dbb9e7503e/compu-78-sd.flac"
721
- }
722
- },
723
- "dr5-studio": {
724
- "name": "Studio Kit",
725
- "blurb": "Acoustic drums in a small dry room. Skin, air and a little ambience.",
726
- "family": "Acoustic",
727
- "credit": "MckAudio DR5 sample pack, dedicated to the public domain (CC0)",
728
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
729
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
730
- "voices": {
731
- "bd": "/__l5e/assets-v1/9bc4c40f-432c-4fd1-98f8-dc3343b5dd31/dr5-studio-bd.flac",
732
- "ch": "/__l5e/assets-v1/862411a4-6d87-45e7-a3a2-2c4062f8e79b/dr5-studio-ch.flac",
733
- "clap": "/__l5e/assets-v1/2feebc4f-49d2-4ea0-9b5a-890059c24a9c/dr5-studio-clap.flac",
734
- "cym": "/__l5e/assets-v1/5abff1b5-b403-403b-b681-9ac37a394442/dr5-studio-cym.flac",
735
- "ht": "/__l5e/assets-v1/4e6883a5-e310-4035-a6ae-ee4033c7a0a1/dr5-studio-ht.flac",
736
- "lt": "/__l5e/assets-v1/faf35ae9-f89f-4ceb-ad5e-c562dd5d261a/dr5-studio-lt.flac",
737
- "mt": "/__l5e/assets-v1/4b923b44-9e79-4aa0-a9ef-4178a9f0279b/dr5-studio-mt.flac",
738
- "oh": "/__l5e/assets-v1/5a5e6d0c-4c8f-4dc5-9dea-55f90083a55a/dr5-studio-oh.flac",
739
- "perc": "/__l5e/assets-v1/8d286dd0-4201-49f6-9738-0a39e3a3d860/dr5-studio-perc.flac",
740
- "rim": "/__l5e/assets-v1/1d139e86-288e-48bd-baba-f7d2502271a5/dr5-studio-rim.flac",
741
- "sd": "/__l5e/assets-v1/eb7b02d6-7063-4350-9515-40010dd583cb/dr5-studio-sd.flac"
742
- }
743
- },
744
- "tape-dust": {
745
- "name": "Tape Dust",
746
- "blurb": "Wobbly, hissy and rolled-off. Everything through a tired cassette.",
747
- "family": "Character",
748
- "credit": "Synthesised for Squelchy",
749
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
750
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
751
- "voices": {
752
- "bd": "/__l5e/assets-v1/7e90ada0-1da8-4930-9c05-48c395e8a863/tape-dust-bd.flac",
753
- "ch": "/__l5e/assets-v1/538fd73f-f7ee-408e-ab69-f8865506f4f5/tape-dust-ch.flac",
754
- "clap": "/__l5e/assets-v1/21b5b5ea-6dce-495d-b740-e7162941c972/tape-dust-clap.flac",
755
- "cym": "/__l5e/assets-v1/ac1a7f2d-9a96-4f61-b2ec-743854f15bbe/tape-dust-cym.flac",
756
- "ht": "/__l5e/assets-v1/93dd3f9c-8267-4f4e-b292-807cf0022c9e/tape-dust-ht.flac",
757
- "lt": "/__l5e/assets-v1/7a51ff67-62ec-408b-b6c3-4a0cae248eaf/tape-dust-lt.flac",
758
- "mt": "/__l5e/assets-v1/ba3340c5-6ead-419a-836a-a041448f06da/tape-dust-mt.flac",
759
- "oh": "/__l5e/assets-v1/e924553d-ac9a-427e-a69a-2939032ee618/tape-dust-oh.flac",
760
- "perc": "/__l5e/assets-v1/abfad1e6-998b-47a8-8c98-6f511c151143/tape-dust-perc.flac",
761
- "rim": "/__l5e/assets-v1/c86262d8-9711-41d4-b866-19a1ffcaf443/tape-dust-rim.flac",
762
- "sd": "/__l5e/assets-v1/2d1090cf-0284-4c33-9ba2-430c5c7b4730/tape-dust-sd.flac"
763
- }
764
- },
765
- "hard-cell": {
766
- "name": "Hard Cell",
767
- "blurb": "Overdriven and bit-crushed. Industrial techno with no headroom left.",
768
- "family": "Character",
769
- "credit": "Synthesised for Squelchy",
770
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
771
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
772
- "voices": {
773
- "bd": "/__l5e/assets-v1/d8f1c5cf-8e07-4a1e-a519-d7f69781329b/hard-cell-bd.flac",
774
- "ch": "/__l5e/assets-v1/c3275e9a-dd79-4ac8-b4b9-84ebe25b5529/hard-cell-ch.flac",
775
- "clap": "/__l5e/assets-v1/160a5d2c-01e0-49da-a998-149a0cf08317/hard-cell-clap.flac",
776
- "cym": "/__l5e/assets-v1/910f3623-0209-439f-9e34-0c0f842bc78f/hard-cell-cym.flac",
777
- "ht": "/__l5e/assets-v1/36f5b37b-9d44-49b8-a57b-bf5d2a1aa523/hard-cell-ht.flac",
778
- "lt": "/__l5e/assets-v1/6065e512-578b-477f-88d9-49b3ccccacea/hard-cell-lt.flac",
779
- "mt": "/__l5e/assets-v1/4e33c147-b8da-4b03-abca-4fd254d5006d/hard-cell-mt.flac",
780
- "oh": "/__l5e/assets-v1/3e5b3bce-f21b-4ecb-8f28-375ce871427f/hard-cell-oh.flac",
781
- "perc": "/__l5e/assets-v1/ab27e781-3d41-4e04-8f44-f7a568543586/hard-cell-perc.flac",
782
- "rim": "/__l5e/assets-v1/ea2989c5-2354-4574-ae38-4786deeee151/hard-cell-rim.flac",
783
- "sd": "/__l5e/assets-v1/5bd3dca9-bdb7-4618-8e0b-9ed1c0b062c7/hard-cell-sd.flac"
784
- }
785
- },
786
- "rx5-fm": {
787
- "name": "Yamaha RX5",
788
- "blurb": "FM percussion \u2014 glassy, bell-like, unmistakably late-eighties digital.",
789
- "family": "Digital",
790
- "credit": "MckAudio RX5 sample pack, dedicated to the public domain (CC0)",
791
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
792
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
793
- "voices": {
794
- "bd": "/__l5e/assets-v1/22b27f9f-d301-48e2-a0e4-e6b6e538ec31/rx5-fm-bd.flac",
795
- "ch": "/__l5e/assets-v1/236fb4f5-7d2a-48c0-be18-bc3777a6be91/rx5-fm-ch.flac",
796
- "clap": "/__l5e/assets-v1/58402fc0-996c-4577-9074-bb40b585c26e/rx5-fm-clap.flac",
797
- "cym": "/__l5e/assets-v1/d3e6ba9b-a2b8-4467-8923-97594723720e/rx5-fm-cym.flac",
798
- "ht": "/__l5e/assets-v1/a5edef5d-7861-4b3a-99bc-10ece111ca64/rx5-fm-ht.flac",
799
- "lt": "/__l5e/assets-v1/7151d30d-fe90-4ac5-9c9f-e91a808a1efa/rx5-fm-lt.flac",
800
- "mt": "/__l5e/assets-v1/46119925-9ecd-431a-94ee-2135c8ce4382/rx5-fm-mt.flac",
801
- "oh": "/__l5e/assets-v1/9fe4938f-fda7-43f8-84c6-c53325fd674c/rx5-fm-oh.flac",
802
- "perc": "/__l5e/assets-v1/1aa471d4-4737-45e6-9070-6301892dcdfa/rx5-fm-perc.flac",
803
- "rim": "/__l5e/assets-v1/2b0409a0-1aa6-41a4-9593-553247a2e624/rx5-fm-rim.flac",
804
- "sd": "/__l5e/assets-v1/3d9c426c-7783-4106-940f-1e6b6405bdd5/rx5-fm-sd.flac"
805
- }
806
- },
807
- "micro-click": {
808
- "name": "Micro Click",
809
- "blurb": "Clicks, ticks and pops. Minimal and micro-house, nothing sustains.",
810
- "family": "Digital",
811
- "credit": "Synthesised for Squelchy",
812
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
813
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
814
- "voices": {
815
- "bd": "/__l5e/assets-v1/58e3ce80-d300-47c6-8d79-52b00376550f/micro-click-bd.flac",
816
- "ch": "/__l5e/assets-v1/1c12e400-5c5f-4aae-b006-5a3fe3c6ef2c/micro-click-ch.flac",
817
- "clap": "/__l5e/assets-v1/b1f402f6-a85d-421b-9684-4b78719726d5/micro-click-clap.flac",
818
- "cym": "/__l5e/assets-v1/fe501055-43d7-427f-9ab4-5efd0423292e/micro-click-cym.flac",
819
- "ht": "/__l5e/assets-v1/3aab93cb-cd84-4600-a3e5-458fa74a2a86/micro-click-ht.flac",
820
- "lt": "/__l5e/assets-v1/b09a0d61-c9a2-4b31-b0f2-10d3c10ef83c/micro-click-lt.flac",
821
- "mt": "/__l5e/assets-v1/988e7a56-e914-43ad-aff1-71ec3a04b8e4/micro-click-mt.flac",
822
- "oh": "/__l5e/assets-v1/122a3f93-4542-471b-b390-996665248653/micro-click-oh.flac",
823
- "perc": "/__l5e/assets-v1/cae413d7-a68c-411a-a4b4-b7c20a83946d/micro-click-perc.flac",
824
- "rim": "/__l5e/assets-v1/41922292-1c6e-4bef-ac8e-fa1ce09eefca/micro-click-rim.flac",
825
- "sd": "/__l5e/assets-v1/6218ccdd-cba1-466e-af8b-665d7a2d4640/micro-click-sd.flac"
826
- }
827
- },
828
- "deep-analogue": {
829
- "name": "Deep Analogue",
830
- "blurb": "Long sub kick, soft snare, warm hats. Deep house at three in the morning.",
831
- "family": "Acoustic",
832
- "credit": "Synthesised for Squelchy",
833
- "license": "CC0 1.0 / public domain \u2014 free to use, no attribution required",
834
- "licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
835
- "voices": {
836
- "bd": "/__l5e/assets-v1/93c55e12-44f1-4cf9-8b19-82833257a68f/deep-analogue-bd.flac",
837
- "ch": "/__l5e/assets-v1/7c881111-83d8-4c1a-b4af-4f09d2a09f4b/deep-analogue-ch.flac",
838
- "clap": "/__l5e/assets-v1/e8b67bb8-8f7f-4b87-9ee4-d9cb7bc43efe/deep-analogue-clap.flac",
839
- "cym": "/__l5e/assets-v1/b329f9e1-3eb0-471c-b7c7-8ad7f639323f/deep-analogue-cym.flac",
840
- "ht": "/__l5e/assets-v1/a381a6b5-fd09-4fa6-b88e-86a29b8f25d9/deep-analogue-ht.flac",
841
- "lt": "/__l5e/assets-v1/c9ebc90a-20aa-4f76-9e79-f440258d4bac/deep-analogue-lt.flac",
842
- "mt": "/__l5e/assets-v1/5e1b803c-748e-4f09-bed7-c7b4511dc8b0/deep-analogue-mt.flac",
843
- "oh": "/__l5e/assets-v1/289d67f2-6d55-4a04-8607-302442465e81/deep-analogue-oh.flac",
844
- "perc": "/__l5e/assets-v1/8ef1f592-a3a4-45a5-9ea4-80362953aee4/deep-analogue-perc.flac",
845
- "rim": "/__l5e/assets-v1/102a1c23-6e5f-468e-95c8-e414ce849884/deep-analogue-rim.flac",
846
- "sd": "/__l5e/assets-v1/9be98c57-13c4-4337-bb2f-53c0b2ff7150/deep-analogue-sd.flac"
847
- }
848
- }
849
- });
850
-
851
631
  // src/modules/ModuleDescriptor.ts
852
632
  function paramDefaults(params50) {
853
633
  const out = {};
@@ -968,7 +748,7 @@ function createFdnReverbNode(ctx, opts) {
968
748
  parameterData: { rt60: opts.rt60, damping: opts.damping },
969
749
  processorOptions: {
970
750
  size: opts.size ?? 1,
971
- feedbackCeiling: opts.feedbackCeiling ?? 0.97
751
+ feedbackCeiling: opts.feedbackCeiling ?? 0.995
972
752
  }
973
753
  });
974
754
  }
@@ -987,14 +767,15 @@ function createOctaverDividerNode(ctx) {
987
767
  outputChannelCount: [1, 2, 1]
988
768
  });
989
769
  }
990
- function createPitchShifterNode(ctx, semitones2 = 12) {
770
+ function createPitchShifterNode(ctx, semitones2 = 12, seed = 2654435769) {
991
771
  return new AudioWorkletNode(ctx, "pitch-shifter", {
992
772
  numberOfInputs: 1,
993
773
  numberOfOutputs: 1,
994
774
  outputChannelCount: [1],
995
775
  channelCount: 1,
996
776
  channelCountMode: "explicit",
997
- parameterData: { semitones: semitones2 }
777
+ parameterData: { semitones: semitones2 },
778
+ processorOptions: { seed }
998
779
  });
999
780
  }
1000
781
  function createVcaNode(ctx, gain = 0.5, cvAmount = 1) {
@@ -1064,6 +845,16 @@ function createPingPongNode(ctx, opts) {
1064
845
  });
1065
846
  }
1066
847
 
848
+ // src/lib/dsp/keepAlive.ts
849
+ var KEEP_ALIVE_DC = 1e-12;
850
+ function createKeepAlive(ctx, ...targets) {
851
+ const src = ctx.createConstantSource();
852
+ src.offset.value = KEEP_ALIVE_DC;
853
+ for (const t of targets) src.connect(t);
854
+ src.start();
855
+ return src;
856
+ }
857
+
1067
858
  // src/lib-runtime/generated/modules/303-filter.tsx
1068
859
  var params = {
1069
860
  note: { node: "_cutoffVoct", field: "transpose", unit: "note", default: 67, min: 15, max: 135 },
@@ -1072,7 +863,7 @@ var params = {
1072
863
  resonance: { unit: "factor", default: 8, min: 0, max: 15, scale: "sqrt" },
1073
864
  envMod: { unit: "factor", default: 0.7, min: 0, max: 1 },
1074
865
  accent: { unit: "factor", default: 0.5, min: 0, max: 1 },
1075
- decay: { node: "envSmoother", field: "decay", unit: "s", default: 0.2, min: 0.05, max: 1, scale: "log" }
866
+ decay: { node: "envSmoother", field: "decay", unit: "s", default: 0.92, min: 0.2, max: 5, scale: "log" }
1076
867
  };
1077
868
  var filter303Descriptor = /* @__PURE__ */ defineDescriptor({
1078
869
  type: "303-filter",
@@ -1084,7 +875,7 @@ var filter303Descriptor = /* @__PURE__ */ defineDescriptor({
1084
875
  "modFreq": { type: "modulation", signal: "modulation", node: "_cutoffVoct" }
1085
876
  },
1086
877
  createModule(id, position) {
1087
- return { id, type: "303-filter", position, ...paramDefaults(params) };
878
+ return { id, type: "303-filter", position, timeUnit: "t60", ...paramDefaults(params) };
1088
879
  },
1089
880
  createNodes(ctx, module) {
1090
881
  const input = ctx.createGain();
@@ -1127,7 +918,8 @@ var filter303Descriptor = /* @__PURE__ */ defineDescriptor({
1127
918
  envDepth.connect(_cutoffVoct);
1128
919
  envSmoother.connect(accentEnvGain);
1129
920
  accentEnvGain.connect(accentVCA.gain);
1130
- return { input, output, trigInput, filter1, filter2, accentVCA, accentEnvGain, envSmoother, envDepth, _cutoffVoct, _cutoffBase };
921
+ const _alive = createKeepAlive(ctx, filter1);
922
+ return { input, output, trigInput, filter1, filter2, accentVCA, accentEnvGain, envSmoother, envDepth, _cutoffVoct, _cutoffBase, _alive };
1131
923
  },
1132
924
  updateParam(nodes, module, param, value) {
1133
925
  switch (param) {
@@ -1158,6 +950,7 @@ var filter303Descriptor = /* @__PURE__ */ defineDescriptor({
1158
950
  },
1159
951
  dispose(nodes) {
1160
952
  nodes._cutoffBase.stop();
953
+ nodes._alive.stop();
1161
954
  }
1162
955
  });
1163
956
 
@@ -2000,9 +1793,9 @@ var EnvelopeFollower = /* @__PURE__ */ defineModule(envFollowDescriptor, {
2000
1793
  // src/lib-runtime/generated/modules/envelope.tsx
2001
1794
  var params13 = {
2002
1795
  attack: { node: "adsrNode", field: "attack", default: 0.01, min: 1e-3, max: 2, scale: "log", unit: "s" },
2003
- decay: { node: "adsrNode", field: "decay", default: 0.1, min: 1e-3, max: 2, scale: "log", unit: "s" },
1796
+ decay: { node: "adsrNode", field: "decay", default: 0.46, min: 1e-3, max: 10, scale: "log", unit: "s" },
2004
1797
  sustain: { node: "adsrNode", field: "sustain", unit: "factor", default: 0.7, min: 0, max: 1 },
2005
- release: { node: "adsrNode", field: "release", default: 0.3, min: 1e-3, max: 3, scale: "log", unit: "s" },
1798
+ release: { node: "adsrNode", field: "release", default: 2.1, min: 1e-3, max: 20, scale: "log", unit: "s" },
2006
1799
  depth: { node: "envOut", field: "gain", default: 48, min: 0, max: 96, scale: "sqrt", unit: "semitone" }
2007
1800
  };
2008
1801
  var envelopeDescriptor = /* @__PURE__ */ defineDescriptor({
@@ -2015,7 +1808,7 @@ var envelopeDescriptor = /* @__PURE__ */ defineDescriptor({
2015
1808
  "trigger": { type: "input", signal: "gate", node: "adsrNode" }
2016
1809
  },
2017
1810
  createModule(id, position) {
2018
- return { id, type: "envelope", position, ...paramDefaults(params13) };
1811
+ return { id, type: "envelope", position, timeUnit: "t60", ...paramDefaults(params13) };
2019
1812
  },
2020
1813
  createNodes(ctx, module) {
2021
1814
  const mainGain = ctx.createGain();
@@ -2339,7 +2132,8 @@ var formantDescriptor = /* @__PURE__ */ defineDescriptor({
2339
2132
  formantMix.connect(wetGain);
2340
2133
  dryGain.connect(output);
2341
2134
  wetGain.connect(output);
2342
- return { input, output, vowelCV, f1, f2, f3, f4, f5, f4Gain, f5Gain, dryGain, wetGain, formantWorklet };
2135
+ const _alive = createKeepAlive(ctx, f1, f2, f3, f4, f5);
2136
+ return { input, output, vowelCV, f1, f2, f3, f4, f5, f4Gain, f5Gain, dryGain, wetGain, formantWorklet, _alive };
2343
2137
  },
2344
2138
  updateParam(nodes, _module, param, value) {
2345
2139
  if (param === "morph") {
@@ -2355,6 +2149,9 @@ var formantDescriptor = /* @__PURE__ */ defineDescriptor({
2355
2149
  nodes.dryGain.gain.value = 1 - value;
2356
2150
  nodes.wetGain.gain.value = value;
2357
2151
  }
2152
+ },
2153
+ dispose(nodes) {
2154
+ nodes._alive.stop();
2358
2155
  }
2359
2156
  });
2360
2157
 
@@ -3408,6 +3205,7 @@ var resonatorDescriptor = /* @__PURE__ */ defineDescriptor({
3408
3205
  partialGain.connect(wetGain);
3409
3206
  partialGains.push(partialGain);
3410
3207
  }
3208
+ const _alive = createKeepAlive(ctx, ...filters);
3411
3209
  const _mix = createMix(ctx, dryGain, wetGain, module.mix, "linear", 0.6);
3412
3210
  input.connect(dryGain);
3413
3211
  dryGain.connect(output);
@@ -3420,6 +3218,7 @@ var resonatorDescriptor = /* @__PURE__ */ defineDescriptor({
3420
3218
  _mix,
3421
3219
  _root,
3422
3220
  _pitch,
3221
+ _alive,
3423
3222
  v1: voct[0],
3424
3223
  v2: voct[1],
3425
3224
  v3: voct[2],
@@ -3484,6 +3283,7 @@ var resonatorDescriptor = /* @__PURE__ */ defineDescriptor({
3484
3283
  },
3485
3284
  dispose(nodes) {
3486
3285
  nodes._root.stop();
3286
+ nodes._alive.stop();
3487
3287
  }
3488
3288
  });
3489
3289
 
@@ -3495,6 +3295,14 @@ var Resonator = /* @__PURE__ */ defineModule(resonatorDescriptor, {
3495
3295
  });
3496
3296
 
3497
3297
  // src/lib/dsp/fdnTank.ts
3298
+ var COMB_TIMES_MS = [29.7, 37.1, 41.1, 43.7];
3299
+ function tankEnergyGain500(rt60, size = 1) {
3300
+ let g2 = 0;
3301
+ for (const ms2 of COMB_TIMES_MS) g2 += Math.pow(10, -6 * (ms2 / 1e3) * size / Math.max(rt60, 0.05));
3302
+ g2 /= COMB_TIMES_MS.length;
3303
+ const loss = 1 - g2;
3304
+ return Math.max(0.05, 0.6422 / loss - 0.2406 - 11e-4 * loss);
3305
+ }
3498
3306
  function createFdnTank(ctx, opts) {
3499
3307
  const input = ctx.createGain();
3500
3308
  const output = ctx.createGain();
@@ -3868,6 +3676,46 @@ var saturatorDescriptor = /* @__PURE__ */ defineDescriptor({
3868
3676
  // src/lib-runtime/generated/modules/saturator.wrapper.ts
3869
3677
  var Saturator = /* @__PURE__ */ defineModule(saturatorDescriptor);
3870
3678
 
3679
+ // src/lib/dsp/shimmerRegen.ts
3680
+ var REGEN_HP_HZ = 300;
3681
+ var REGEN_HP_Q_DB = 20 * Math.log10(Math.SQRT1_2);
3682
+ var HP_AT_500 = 1 / Math.sqrt(1 + Math.pow(REGEN_HP_HZ / 500, 4));
3683
+ var SHIFTER_ENERGY = 0.75;
3684
+ var REGEN_DELAY_S = 0.02;
3685
+ var SHIFTER_SEEDS = [5370206, 739982445];
3686
+ var UNISON_FLOOR = [
3687
+ [0.5, 0.68],
3688
+ [1, 0.75],
3689
+ [2, 0.76],
3690
+ [3, 0.8],
3691
+ [5, 0.84],
3692
+ [7, 0.75],
3693
+ [10, 0.6]
3694
+ ];
3695
+ var UNISON_PITCH_SPAN = 0.75;
3696
+ function unisonFloor(decay) {
3697
+ const x = Math.log2(Math.max(0.05, decay));
3698
+ const first = UNISON_FLOOR[0], last = UNISON_FLOOR[UNISON_FLOOR.length - 1];
3699
+ if (x <= Math.log2(first[0])) return first[1];
3700
+ if (x >= Math.log2(last[0])) return last[1];
3701
+ for (let i = 1; i < UNISON_FLOOR.length; i++) {
3702
+ const [d1, k1] = UNISON_FLOOR[i];
3703
+ if (x <= Math.log2(d1)) {
3704
+ const [d0, k0] = UNISON_FLOOR[i - 1];
3705
+ const t = (x - Math.log2(d0)) / (Math.log2(d1) - Math.log2(d0));
3706
+ return k0 + (k1 - k0) * t;
3707
+ }
3708
+ }
3709
+ return last[1];
3710
+ }
3711
+ function unisonCoherence(decay, pitch) {
3712
+ const a = unisonFloor(decay);
3713
+ return Math.min(1, a + (1 - a) * (pitch / UNISON_PITCH_SPAN) ** 2);
3714
+ }
3715
+ function shimmerRegenNorm(decay, pitch) {
3716
+ return unisonCoherence(decay, pitch) / (Math.sqrt(tankEnergyGain500(decay)) * HP_AT_500 * Math.sqrt(SHIFTER_ENERGY));
3717
+ }
3718
+
3871
3719
  // src/lib-runtime/generated/modules/shimmer.tsx
3872
3720
  var params36 = {
3873
3721
  decay: { unit: "s", default: 3, min: 0.5, max: 10, scale: "log" },
@@ -3891,22 +3739,25 @@ var shimmerDescriptor = /* @__PURE__ */ defineDescriptor({
3891
3739
  const dryGain = ctx.createGain();
3892
3740
  const wetGain = ctx.createGain();
3893
3741
  const _mix = createMix(ctx, dryGain, wetGain, module.mix, "equal-power");
3894
- const tank = createFdnTank(ctx, { rt60: module.decay, damping: 0.5, feedbackCeiling: 0.93 });
3742
+ const tank = createFdnTank(ctx, { rt60: module.decay, damping: 0.5 });
3895
3743
  const splitter = ctx.createChannelSplitter(2);
3896
3744
  const merger = ctx.createChannelMerger(2);
3897
- const mkRegenTap = () => {
3745
+ const mkRegenTap = (seed) => {
3898
3746
  const hp = ctx.createBiquadFilter();
3899
3747
  hp.type = "highpass";
3900
- hp.frequency.value = 300;
3901
- const shifter = createPitchShifterNode(ctx, module.pitch);
3748
+ hp.frequency.value = REGEN_HP_HZ;
3749
+ hp.Q.value = REGEN_HP_Q_DB;
3750
+ const shifter = createPitchShifterNode(ctx, module.pitch, seed);
3902
3751
  return { hp, shifter };
3903
3752
  };
3904
- const tapL = mkRegenTap();
3905
- const tapR = mkRegenTap();
3753
+ const tapL = mkRegenTap(SHIFTER_SEEDS[0]);
3754
+ const tapR = mkRegenTap(SHIFTER_SEEDS[1]);
3755
+ const regenNorm = ctx.createGain();
3756
+ regenNorm.gain.value = shimmerRegenNorm(module.decay, module.pitch);
3906
3757
  const regenGain = ctx.createGain();
3907
3758
  regenGain.gain.value = module.shimmer;
3908
3759
  const regenDelay = ctx.createDelay(0.1);
3909
- regenDelay.delayTime.value = 0.02;
3760
+ regenDelay.delayTime.value = REGEN_DELAY_S;
3910
3761
  tank.output.connect(splitter);
3911
3762
  splitter.connect(tapL.hp, 0);
3912
3763
  splitter.connect(tapR.hp, 1);
@@ -3914,7 +3765,8 @@ var shimmerDescriptor = /* @__PURE__ */ defineDescriptor({
3914
3765
  tapR.hp.connect(tapR.shifter);
3915
3766
  tapL.shifter.connect(merger, 0, 0);
3916
3767
  tapR.shifter.connect(merger, 0, 1);
3917
- merger.connect(regenGain);
3768
+ merger.connect(regenNorm);
3769
+ regenNorm.connect(regenGain);
3918
3770
  regenGain.connect(regenDelay);
3919
3771
  regenDelay.connect(tank.input);
3920
3772
  input.connect(dryGain);
@@ -3934,6 +3786,7 @@ var shimmerDescriptor = /* @__PURE__ */ defineDescriptor({
3934
3786
  highpassR: tapR.hp,
3935
3787
  pitchShifterL: tapL.shifter,
3936
3788
  pitchShifterR: tapR.shifter,
3789
+ regenNorm,
3937
3790
  regenGain,
3938
3791
  regenDelay,
3939
3792
  tankInput: tank.input,
@@ -3951,8 +3804,10 @@ var shimmerDescriptor = /* @__PURE__ */ defineDescriptor({
3951
3804
  for (const key of ["pitchShifterL", "pitchShifterR"]) {
3952
3805
  nodes[key].parameters.get("semitones").setTargetAtTime(value, now2, 0.02);
3953
3806
  }
3807
+ nodes.regenNorm.gain.setTargetAtTime(shimmerRegenNorm(_m.decay, value), now2, 0.02);
3954
3808
  } else if (param === "decay") {
3955
3809
  setTankDecay({ node: nodes.tankNode }, value, now2);
3810
+ nodes.regenNorm.gain.setTargetAtTime(shimmerRegenNorm(value, _m.pitch), now2, 0.02);
3956
3811
  }
3957
3812
  }
3958
3813
  });
@@ -4487,13 +4342,18 @@ var filterDescriptor = /* @__PURE__ */ defineDescriptor({
4487
4342
  dbOut: qIsDb(module.filterType)
4488
4343
  });
4489
4344
  _resMap.connect(filter.Q);
4490
- return { filter, output, _cutoffVoct, _cutoffBase, _resMap };
4345
+ const _alive = createKeepAlive(ctx, filter);
4346
+ return { filter, output, _cutoffVoct, _cutoffBase, _resMap, _alive };
4491
4347
  },
4492
4348
  dispose(nodes) {
4493
4349
  try {
4494
4350
  nodes._cutoffBase.stop();
4495
4351
  } catch (_) {
4496
4352
  }
4353
+ try {
4354
+ nodes._alive.stop();
4355
+ } catch (_) {
4356
+ }
4497
4357
  },
4498
4358
  updateParam(nodes, module, param, value) {
4499
4359
  switch (param) {
@@ -4669,7 +4529,8 @@ var wahDescriptor = /* @__PURE__ */ defineDescriptor({
4669
4529
  input.connect(filter);
4670
4530
  filter.connect(makeup);
4671
4531
  makeup.connect(output);
4672
- return { input, output, filter, makeup, lfo, lfoGain, _cutoffVoct, _cutoffBase };
4532
+ const _alive = createKeepAlive(ctx, filter);
4533
+ return { input, output, filter, makeup, lfo, lfoGain, _cutoffVoct, _cutoffBase, _alive };
4673
4534
  },
4674
4535
  updateParam(nodes, _module, param, value) {
4675
4536
  if (param === "note") {
@@ -4686,6 +4547,7 @@ var wahDescriptor = /* @__PURE__ */ defineDescriptor({
4686
4547
  dispose(nodes) {
4687
4548
  nodes.lfo.stop();
4688
4549
  nodes._cutoffBase.stop();
4550
+ nodes._alive.stop();
4689
4551
  }
4690
4552
  });
4691
4553
 
@@ -4767,7 +4629,6 @@ export {
4767
4629
  CombFilter,
4768
4630
  Compressor,
4769
4631
  Crossfade,
4770
- DEFAULT_SAMPLE_BASE_URL,
4771
4632
  Delay,
4772
4633
  Dimension,
4773
4634
  Distortion,
@@ -4797,7 +4658,6 @@ export {
4797
4658
  Reverb,
4798
4659
  RingModulator,
4799
4660
  Rotary,
4800
- SampleSets,
4801
4661
  SampleVoice,
4802
4662
  Saturator,
4803
4663
  Shimmer,