@jpdutoit/squelchy 0.0.3 → 0.0.5
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 +3 -1
- package/{chunk-MEZE4P3U.js → chunk-N7J25N5J.js} +2 -2
- package/chunk-N7J25N5J.js.map +7 -0
- package/docs/GUIDE.md +90 -12
- package/docs/MODULES.md +3 -3
- package/docs/modules.json +6 -6
- package/index.d.ts +58 -16
- package/index.js +109 -38
- package/index.js.map +3 -3
- package/package.json +1 -3
- package/{worklets-inline-DFWINMCS.js → worklets-inline-EF3OTQ4D.js} +2 -2
- package/chunk-MEZE4P3U.js.map +0 -7
- package/meta.json +0 -4492
- /package/{worklets-inline-DFWINMCS.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-
|
|
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-
|
|
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
|
|
144
|
+
return v == null || v === false;
|
|
145
145
|
}
|
|
146
146
|
function normStep(s) {
|
|
147
147
|
if (isRest(s)) return null;
|
|
@@ -180,26 +180,29 @@ function createTransport(ctx, opts = {}) {
|
|
|
180
180
|
if (at === "now") return now2;
|
|
181
181
|
if (at === "beat") return Math.ceil(now2 - EPS);
|
|
182
182
|
if (at === "bar") return Math.ceil(now2 / beatsPerBar - EPS) * beatsPerBar;
|
|
183
|
-
if ("bar" in at) return at.bar * beatsPerBar;
|
|
183
|
+
if ("bar" in at) return at.bar * beatsPerBar + (at.beat ?? 0);
|
|
184
184
|
return at.beat;
|
|
185
185
|
}
|
|
186
186
|
const latency = () => ctx.outputLatency || ctx.baseLatency || 0;
|
|
187
|
-
function
|
|
188
|
-
if (!local && taps.size === 0) return;
|
|
189
|
-
const fire = () => {
|
|
190
|
-
local?.(hit);
|
|
191
|
-
for (const cb of taps) cb(hit);
|
|
192
|
-
};
|
|
187
|
+
function whenAudible(time, fire) {
|
|
193
188
|
if (offline) {
|
|
194
189
|
fire();
|
|
195
|
-
return;
|
|
190
|
+
return void 0;
|
|
196
191
|
}
|
|
197
|
-
const delay = Math.max(0, (
|
|
192
|
+
const delay = Math.max(0, (time - ctx.currentTime + latency()) * 1e3);
|
|
198
193
|
const id = setTimeout(() => {
|
|
199
194
|
tapTimers.delete(id);
|
|
200
195
|
fire();
|
|
201
196
|
}, delay);
|
|
202
197
|
tapTimers.add(id);
|
|
198
|
+
return id;
|
|
199
|
+
}
|
|
200
|
+
function emitTap(hit, local) {
|
|
201
|
+
if (!local && taps.size === 0) return;
|
|
202
|
+
whenAudible(hit.time, () => {
|
|
203
|
+
local?.(hit);
|
|
204
|
+
for (const cb of taps) cb(hit);
|
|
205
|
+
});
|
|
203
206
|
}
|
|
204
207
|
function horizonBeat() {
|
|
205
208
|
if (offline) return beatAt(ctx.length / ctx.sampleRate);
|
|
@@ -320,16 +323,20 @@ function createTransport(ctx, opts = {}) {
|
|
|
320
323
|
}
|
|
321
324
|
};
|
|
322
325
|
},
|
|
323
|
-
at(when, fn) {
|
|
326
|
+
at(when, fn, o = {}) {
|
|
324
327
|
const b = typeof when === "number" ? when : resolve(when);
|
|
325
328
|
let fired = false;
|
|
329
|
+
let audibleTimer;
|
|
326
330
|
const job = {
|
|
327
331
|
nextBeat: () => b,
|
|
328
332
|
run(until) {
|
|
329
333
|
if (fired) return false;
|
|
330
334
|
if (b < until) {
|
|
331
335
|
fired = true;
|
|
332
|
-
|
|
336
|
+
const time = timeAt(b);
|
|
337
|
+
fn(time);
|
|
338
|
+
const onAudible = o.onAudible;
|
|
339
|
+
if (onAudible) audibleTimer = whenAudible(time, () => onAudible(time));
|
|
333
340
|
return false;
|
|
334
341
|
}
|
|
335
342
|
return true;
|
|
@@ -340,6 +347,10 @@ function createTransport(ctx, opts = {}) {
|
|
|
340
347
|
return () => {
|
|
341
348
|
fired = true;
|
|
342
349
|
jobs.delete(job);
|
|
350
|
+
if (audibleTimer !== void 0) {
|
|
351
|
+
clearTimeout(audibleTimer);
|
|
352
|
+
tapTimers.delete(audibleTimer);
|
|
353
|
+
}
|
|
343
354
|
};
|
|
344
355
|
},
|
|
345
356
|
onHit(cb) {
|
|
@@ -356,8 +367,13 @@ function createTransport(ctx, opts = {}) {
|
|
|
356
367
|
};
|
|
357
368
|
return t;
|
|
358
369
|
}
|
|
359
|
-
function steps(s) {
|
|
360
|
-
|
|
370
|
+
function steps(s, levels = {}) {
|
|
371
|
+
const velocity = { X: levels.accent ?? 1, x: levels.normal ?? 0.75, o: levels.ghost ?? 0.4 };
|
|
372
|
+
return [...s.replace(/[\s|]/g, "")].map((c) => {
|
|
373
|
+
if (c === "." || c === "-") return null;
|
|
374
|
+
if (!(c in velocity)) throw new Error(`steps(): unknown character "${c}" in "${s}" (X accent, x hit, o ghost, . or - rest)`);
|
|
375
|
+
return { value: true, velocity: velocity[c] };
|
|
376
|
+
});
|
|
361
377
|
}
|
|
362
378
|
var NOTE_RE = /^([A-Ga-g])([#b]?)(-?\d+)$/;
|
|
363
379
|
var PC = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 };
|
|
@@ -526,16 +542,28 @@ var asPitch = (n) => n;
|
|
|
526
542
|
|
|
527
543
|
// src/lib/dsp/pulse.ts
|
|
528
544
|
var PULSE_S = 1e-3;
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
545
|
+
var pulseBuffers = /* @__PURE__ */ new WeakMap();
|
|
546
|
+
function filled(ctx, samples, level) {
|
|
547
|
+
const buf = ctx.createBuffer(1, samples, ctx.sampleRate);
|
|
548
|
+
buf.getChannelData(0).fill(level);
|
|
549
|
+
return buf;
|
|
550
|
+
}
|
|
551
|
+
function play(ctx, buf, target, when) {
|
|
552
|
+
const src = ctx.createBufferSource();
|
|
553
|
+
src.buffer = buf;
|
|
534
554
|
src.connect(target);
|
|
535
|
-
src.start(
|
|
536
|
-
src.stop(at + PULSE_S);
|
|
555
|
+
src.start(Math.max(0, when ?? 0));
|
|
537
556
|
src.onended = () => src.disconnect();
|
|
538
557
|
}
|
|
558
|
+
function pulse(target, when) {
|
|
559
|
+
const ctx = target.context;
|
|
560
|
+
let buf = pulseBuffers.get(ctx);
|
|
561
|
+
if (!buf) {
|
|
562
|
+
buf = filled(ctx, Math.max(1, Math.ceil(ctx.sampleRate * PULSE_S)), 1);
|
|
563
|
+
pulseBuffers.set(ctx, buf);
|
|
564
|
+
}
|
|
565
|
+
play(ctx, buf, target, when);
|
|
566
|
+
}
|
|
539
567
|
|
|
540
568
|
// src/lib/samples/types.ts
|
|
541
569
|
var VOICE_KEYS = [
|
|
@@ -585,23 +613,31 @@ async function loadSampleSet(ctx, set, opts = {}) {
|
|
|
585
613
|
};
|
|
586
614
|
}
|
|
587
615
|
var SampleVoice = {
|
|
588
|
-
create(ctx, kit, key) {
|
|
616
|
+
create(ctx, kit, key, opts = {}) {
|
|
589
617
|
const out = ctx.createGain();
|
|
590
|
-
const
|
|
618
|
+
const root = opts.root ?? 60;
|
|
619
|
+
let current = kit;
|
|
620
|
+
let buf = kit.buffer(key);
|
|
591
621
|
const trigger = (when, h) => {
|
|
592
622
|
if (!buf) return;
|
|
593
623
|
const src = ctx.createBufferSource();
|
|
594
624
|
const g = ctx.createGain();
|
|
595
625
|
src.buffer = buf;
|
|
596
|
-
if (typeof h?.value === "number") src.playbackRate.value = 2 ** (h.value / 12);
|
|
626
|
+
if (typeof h?.value === "number") src.playbackRate.value = 2 ** ((h.value - root) / 12);
|
|
597
627
|
g.gain.value = Math.max(0, Math.min(1, h?.velocity ?? 1));
|
|
598
628
|
src.connect(g).connect(out);
|
|
599
629
|
src.start(when);
|
|
600
|
-
if (h?.duration) src.stop(when + h.duration);
|
|
601
630
|
};
|
|
602
631
|
return {
|
|
603
632
|
output: out,
|
|
604
633
|
trigger,
|
|
634
|
+
get kit() {
|
|
635
|
+
return current;
|
|
636
|
+
},
|
|
637
|
+
setKit(next) {
|
|
638
|
+
current = next;
|
|
639
|
+
buf = next.buffer(key);
|
|
640
|
+
},
|
|
605
641
|
connect: (d) => {
|
|
606
642
|
out.connect(d);
|
|
607
643
|
return d;
|
|
@@ -846,7 +882,7 @@ var params = {
|
|
|
846
882
|
resonance: { unit: "factor", default: 8, min: 0, max: 15, scale: "sqrt" },
|
|
847
883
|
envMod: { unit: "factor", default: 0.7, min: 0, max: 1 },
|
|
848
884
|
accent: { unit: "factor", default: 0.5, min: 0, max: 1 },
|
|
849
|
-
decay: { node: "envSmoother", field: "decay", unit: "s", default: 0.
|
|
885
|
+
decay: { node: "envSmoother", field: "decay", unit: "s", default: 0.92, min: 0.2, max: 5, scale: "log" }
|
|
850
886
|
};
|
|
851
887
|
var filter303Descriptor = /* @__PURE__ */ defineDescriptor({
|
|
852
888
|
type: "303-filter",
|
|
@@ -858,7 +894,7 @@ var filter303Descriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
858
894
|
"modFreq": { type: "modulation", signal: "modulation", node: "_cutoffVoct" }
|
|
859
895
|
},
|
|
860
896
|
createModule(id, position) {
|
|
861
|
-
return { id, type: "303-filter", position, ...paramDefaults(params) };
|
|
897
|
+
return { id, type: "303-filter", position, timeUnit: "t60", ...paramDefaults(params) };
|
|
862
898
|
},
|
|
863
899
|
createNodes(ctx, module) {
|
|
864
900
|
const input = ctx.createGain();
|
|
@@ -3283,7 +3319,8 @@ function tankEnergyGain500(rt60, size = 1) {
|
|
|
3283
3319
|
let g2 = 0;
|
|
3284
3320
|
for (const ms2 of COMB_TIMES_MS) g2 += Math.pow(10, -6 * (ms2 / 1e3) * size / Math.max(rt60, 0.05));
|
|
3285
3321
|
g2 /= COMB_TIMES_MS.length;
|
|
3286
|
-
|
|
3322
|
+
const loss = 1 - g2;
|
|
3323
|
+
return Math.max(0.05, 0.6422 / loss - 0.2406 - 11e-4 * loss);
|
|
3287
3324
|
}
|
|
3288
3325
|
function createFdnTank(ctx, opts) {
|
|
3289
3326
|
const input = ctx.createGain();
|
|
@@ -3658,14 +3695,47 @@ var saturatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3658
3695
|
// src/lib-runtime/generated/modules/saturator.wrapper.ts
|
|
3659
3696
|
var Saturator = /* @__PURE__ */ defineModule(saturatorDescriptor);
|
|
3660
3697
|
|
|
3661
|
-
// src/lib
|
|
3698
|
+
// src/lib/dsp/shimmerRegen.ts
|
|
3662
3699
|
var REGEN_HP_HZ = 300;
|
|
3663
3700
|
var REGEN_HP_Q_DB = 20 * Math.log10(Math.SQRT1_2);
|
|
3664
3701
|
var HP_AT_500 = 1 / Math.sqrt(1 + Math.pow(REGEN_HP_HZ / 500, 4));
|
|
3665
3702
|
var SHIFTER_ENERGY = 0.75;
|
|
3666
|
-
|
|
3667
|
-
|
|
3703
|
+
var REGEN_DELAY_S = 0.02;
|
|
3704
|
+
var SHIFTER_SEEDS = [5370206, 739982445];
|
|
3705
|
+
var UNISON_FLOOR = [
|
|
3706
|
+
[0.5, 0.68],
|
|
3707
|
+
[1, 0.75],
|
|
3708
|
+
[2, 0.76],
|
|
3709
|
+
[3, 0.8],
|
|
3710
|
+
[5, 0.84],
|
|
3711
|
+
[7, 0.75],
|
|
3712
|
+
[10, 0.6]
|
|
3713
|
+
];
|
|
3714
|
+
var UNISON_PITCH_SPAN = 0.75;
|
|
3715
|
+
function unisonFloor(decay) {
|
|
3716
|
+
const x = Math.log2(Math.max(0.05, decay));
|
|
3717
|
+
const first = UNISON_FLOOR[0], last = UNISON_FLOOR[UNISON_FLOOR.length - 1];
|
|
3718
|
+
if (x <= Math.log2(first[0])) return first[1];
|
|
3719
|
+
if (x >= Math.log2(last[0])) return last[1];
|
|
3720
|
+
for (let i = 1; i < UNISON_FLOOR.length; i++) {
|
|
3721
|
+
const [d1, k1] = UNISON_FLOOR[i];
|
|
3722
|
+
if (x <= Math.log2(d1)) {
|
|
3723
|
+
const [d0, k0] = UNISON_FLOOR[i - 1];
|
|
3724
|
+
const t = (x - Math.log2(d0)) / (Math.log2(d1) - Math.log2(d0));
|
|
3725
|
+
return k0 + (k1 - k0) * t;
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
return last[1];
|
|
3668
3729
|
}
|
|
3730
|
+
function unisonCoherence(decay, pitch) {
|
|
3731
|
+
const a = unisonFloor(decay);
|
|
3732
|
+
return Math.min(1, a + (1 - a) * (pitch / UNISON_PITCH_SPAN) ** 2);
|
|
3733
|
+
}
|
|
3734
|
+
function shimmerRegenNorm(decay, pitch) {
|
|
3735
|
+
return unisonCoherence(decay, pitch) / (Math.sqrt(tankEnergyGain500(decay)) * HP_AT_500 * Math.sqrt(SHIFTER_ENERGY));
|
|
3736
|
+
}
|
|
3737
|
+
|
|
3738
|
+
// src/lib-runtime/generated/modules/shimmer.tsx
|
|
3669
3739
|
var params36 = {
|
|
3670
3740
|
decay: { unit: "s", default: 3, min: 0.5, max: 10, scale: "log" },
|
|
3671
3741
|
pitch: { unit: "semitone", default: 12, min: -12, max: 24 },
|
|
@@ -3699,14 +3769,14 @@ var shimmerDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3699
3769
|
const shifter = createPitchShifterNode(ctx, module.pitch, seed);
|
|
3700
3770
|
return { hp, shifter };
|
|
3701
3771
|
};
|
|
3702
|
-
const tapL = mkRegenTap(
|
|
3703
|
-
const tapR = mkRegenTap(
|
|
3772
|
+
const tapL = mkRegenTap(SHIFTER_SEEDS[0]);
|
|
3773
|
+
const tapR = mkRegenTap(SHIFTER_SEEDS[1]);
|
|
3704
3774
|
const regenNorm = ctx.createGain();
|
|
3705
|
-
regenNorm.gain.value = shimmerRegenNorm(module.decay);
|
|
3775
|
+
regenNorm.gain.value = shimmerRegenNorm(module.decay, module.pitch);
|
|
3706
3776
|
const regenGain = ctx.createGain();
|
|
3707
3777
|
regenGain.gain.value = module.shimmer;
|
|
3708
3778
|
const regenDelay = ctx.createDelay(0.1);
|
|
3709
|
-
regenDelay.delayTime.value =
|
|
3779
|
+
regenDelay.delayTime.value = REGEN_DELAY_S;
|
|
3710
3780
|
tank.output.connect(splitter);
|
|
3711
3781
|
splitter.connect(tapL.hp, 0);
|
|
3712
3782
|
splitter.connect(tapR.hp, 1);
|
|
@@ -3753,9 +3823,10 @@ var shimmerDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3753
3823
|
for (const key of ["pitchShifterL", "pitchShifterR"]) {
|
|
3754
3824
|
nodes[key].parameters.get("semitones").setTargetAtTime(value, now2, 0.02);
|
|
3755
3825
|
}
|
|
3826
|
+
nodes.regenNorm.gain.setTargetAtTime(shimmerRegenNorm(_m.decay, value), now2, 0.02);
|
|
3756
3827
|
} else if (param === "decay") {
|
|
3757
3828
|
setTankDecay({ node: nodes.tankNode }, value, now2);
|
|
3758
|
-
nodes.regenNorm.gain.setTargetAtTime(shimmerRegenNorm(value), now2, 0.02);
|
|
3829
|
+
nodes.regenNorm.gain.setTargetAtTime(shimmerRegenNorm(value, _m.pitch), now2, 0.02);
|
|
3759
3830
|
}
|
|
3760
3831
|
}
|
|
3761
3832
|
});
|