@jpdutoit/squelchy 0.0.4 → 0.0.6
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 +5 -1
- package/{chunk-N7J25N5J.js → chunk-PJDNZ52Q.js} +21 -5
- package/chunk-PJDNZ52Q.js.map +7 -0
- package/docs/GUIDE.md +87 -9
- package/docs/MODULES.md +47 -37
- package/docs/modules.json +114 -32
- package/index.d.ts +99 -30
- package/index.js +557 -362
- package/index.js.map +3 -3
- package/kits/compu-78/bd.flac +0 -0
- package/kits/compu-78/ch.flac +0 -0
- package/kits/compu-78/clap.flac +0 -0
- package/kits/compu-78/cym.flac +0 -0
- package/kits/compu-78/ht.flac +0 -0
- package/kits/compu-78/lt.flac +0 -0
- package/kits/compu-78/mt.flac +0 -0
- package/kits/compu-78/oh.flac +0 -0
- package/kits/compu-78/perc.flac +0 -0
- package/kits/compu-78/rim.flac +0 -0
- package/kits/compu-78/sd.flac +0 -0
- package/kits/deep-analogue/bd.flac +0 -0
- package/kits/deep-analogue/ch.flac +0 -0
- package/kits/deep-analogue/clap.flac +0 -0
- package/kits/deep-analogue/cym.flac +0 -0
- package/kits/deep-analogue/ht.flac +0 -0
- package/kits/deep-analogue/lt.flac +0 -0
- package/kits/deep-analogue/mt.flac +0 -0
- package/kits/deep-analogue/oh.flac +0 -0
- package/kits/deep-analogue/perc.flac +0 -0
- package/kits/deep-analogue/rim.flac +0 -0
- package/kits/deep-analogue/sd.flac +0 -0
- package/kits/hard-cell/bd.flac +0 -0
- package/kits/hard-cell/ch.flac +0 -0
- package/kits/hard-cell/clap.flac +0 -0
- package/kits/hard-cell/cym.flac +0 -0
- package/kits/hard-cell/ht.flac +0 -0
- package/kits/hard-cell/lt.flac +0 -0
- package/kits/hard-cell/mt.flac +0 -0
- package/kits/hard-cell/oh.flac +0 -0
- package/kits/hard-cell/perc.flac +0 -0
- package/kits/hard-cell/rim.flac +0 -0
- package/kits/hard-cell/sd.flac +0 -0
- package/kits/micro-click/bd.flac +0 -0
- package/kits/micro-click/ch.flac +0 -0
- package/kits/micro-click/clap.flac +0 -0
- package/kits/micro-click/cym.flac +0 -0
- package/kits/micro-click/ht.flac +0 -0
- package/kits/micro-click/lt.flac +0 -0
- package/kits/micro-click/mt.flac +0 -0
- package/kits/micro-click/oh.flac +0 -0
- package/kits/micro-click/perc.flac +0 -0
- package/kits/micro-click/rim.flac +0 -0
- package/kits/micro-click/sd.flac +0 -0
- package/kits/tape-dust/bd.flac +0 -0
- package/kits/tape-dust/ch.flac +0 -0
- package/kits/tape-dust/clap.flac +0 -0
- package/kits/tape-dust/cym.flac +0 -0
- package/kits/tape-dust/ht.flac +0 -0
- package/kits/tape-dust/lt.flac +0 -0
- package/kits/tape-dust/mt.flac +0 -0
- package/kits/tape-dust/oh.flac +0 -0
- package/kits/tape-dust/perc.flac +0 -0
- package/kits/tape-dust/rim.flac +0 -0
- package/kits/tape-dust/sd.flac +0 -0
- package/package.json +1 -1
- package/{worklets-inline-EF3OTQ4D.js → worklets-inline-NWG5PWND.js} +10 -2
- package/{worklets-inline-EF3OTQ4D.js.map → worklets-inline-NWG5PWND.js.map} +2 -2
- package/chunk-N7J25N5J.js.map +0 -7
package/index.js
CHANGED
|
@@ -2,12 +2,14 @@ import {
|
|
|
2
2
|
adsr_envelope_default,
|
|
3
3
|
bitcrusher_default,
|
|
4
4
|
comb_filter_default,
|
|
5
|
+
compressor_default,
|
|
5
6
|
env_follower_default,
|
|
6
7
|
fdn_reverb_default,
|
|
7
8
|
flanger_default,
|
|
8
9
|
formant_table_default,
|
|
9
10
|
freq_divider_default,
|
|
10
11
|
freq_shifter_default,
|
|
12
|
+
gate_default,
|
|
11
13
|
glide_default,
|
|
12
14
|
ladder_filter_default,
|
|
13
15
|
map_res_default,
|
|
@@ -15,12 +17,14 @@ import {
|
|
|
15
17
|
map_voct_to_period_default,
|
|
16
18
|
ping_pong_default,
|
|
17
19
|
pitch_shifter_default,
|
|
20
|
+
shaper_default,
|
|
18
21
|
spring_reverb_default,
|
|
19
22
|
tape_delay_default,
|
|
20
23
|
tape_stop_default,
|
|
21
24
|
vca_default,
|
|
25
|
+
vinyl_noise_default,
|
|
22
26
|
waveshaper_default
|
|
23
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-PJDNZ52Q.js";
|
|
24
28
|
|
|
25
29
|
// src/lib-runtime/core.ts
|
|
26
30
|
var pendingSources = {};
|
|
@@ -28,7 +32,7 @@ var registrations = /* @__PURE__ */ new WeakMap();
|
|
|
28
32
|
function preload(ctx, opts) {
|
|
29
33
|
const existing = registrations.get(ctx);
|
|
30
34
|
if (existing) return existing;
|
|
31
|
-
const sources = opts?.allWorklets ? import("./worklets-inline-
|
|
35
|
+
const sources = opts?.allWorklets ? import("./worklets-inline-NWG5PWND.js").then((m) => m.WORKLET_SOURCES) : Promise.resolve(pendingSources);
|
|
32
36
|
const promise = sources.then(
|
|
33
37
|
(map) => Promise.all(Object.entries(map).map(async ([name, src]) => {
|
|
34
38
|
const url = URL.createObjectURL(new Blob([src], { type: "text/javascript" }));
|
|
@@ -180,26 +184,29 @@ function createTransport(ctx, opts = {}) {
|
|
|
180
184
|
if (at === "now") return now2;
|
|
181
185
|
if (at === "beat") return Math.ceil(now2 - EPS);
|
|
182
186
|
if (at === "bar") return Math.ceil(now2 / beatsPerBar - EPS) * beatsPerBar;
|
|
183
|
-
if ("bar" in at) return at.bar * beatsPerBar;
|
|
187
|
+
if ("bar" in at) return at.bar * beatsPerBar + (at.beat ?? 0);
|
|
184
188
|
return at.beat;
|
|
185
189
|
}
|
|
186
190
|
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
|
-
};
|
|
191
|
+
function whenAudible(time, fire) {
|
|
193
192
|
if (offline) {
|
|
194
193
|
fire();
|
|
195
|
-
return;
|
|
194
|
+
return void 0;
|
|
196
195
|
}
|
|
197
|
-
const delay = Math.max(0, (
|
|
196
|
+
const delay = Math.max(0, (time - ctx.currentTime + latency()) * 1e3);
|
|
198
197
|
const id = setTimeout(() => {
|
|
199
198
|
tapTimers.delete(id);
|
|
200
199
|
fire();
|
|
201
200
|
}, delay);
|
|
202
201
|
tapTimers.add(id);
|
|
202
|
+
return id;
|
|
203
|
+
}
|
|
204
|
+
function emitTap(hit, local) {
|
|
205
|
+
if (!local && taps.size === 0) return;
|
|
206
|
+
whenAudible(hit.time, () => {
|
|
207
|
+
local?.(hit);
|
|
208
|
+
for (const cb of taps) cb(hit);
|
|
209
|
+
});
|
|
203
210
|
}
|
|
204
211
|
function horizonBeat() {
|
|
205
212
|
if (offline) return beatAt(ctx.length / ctx.sampleRate);
|
|
@@ -320,16 +327,20 @@ function createTransport(ctx, opts = {}) {
|
|
|
320
327
|
}
|
|
321
328
|
};
|
|
322
329
|
},
|
|
323
|
-
at(when, fn) {
|
|
330
|
+
at(when, fn, o = {}) {
|
|
324
331
|
const b = typeof when === "number" ? when : resolve(when);
|
|
325
332
|
let fired = false;
|
|
333
|
+
let audibleTimer;
|
|
326
334
|
const job = {
|
|
327
335
|
nextBeat: () => b,
|
|
328
336
|
run(until) {
|
|
329
337
|
if (fired) return false;
|
|
330
338
|
if (b < until) {
|
|
331
339
|
fired = true;
|
|
332
|
-
|
|
340
|
+
const time = timeAt(b);
|
|
341
|
+
fn(time);
|
|
342
|
+
const onAudible = o.onAudible;
|
|
343
|
+
if (onAudible) audibleTimer = whenAudible(time, () => onAudible(time));
|
|
333
344
|
return false;
|
|
334
345
|
}
|
|
335
346
|
return true;
|
|
@@ -340,6 +351,10 @@ function createTransport(ctx, opts = {}) {
|
|
|
340
351
|
return () => {
|
|
341
352
|
fired = true;
|
|
342
353
|
jobs.delete(job);
|
|
354
|
+
if (audibleTimer !== void 0) {
|
|
355
|
+
clearTimeout(audibleTimer);
|
|
356
|
+
tapTimers.delete(audibleTimer);
|
|
357
|
+
}
|
|
343
358
|
};
|
|
344
359
|
},
|
|
345
360
|
onHit(cb) {
|
|
@@ -491,20 +506,27 @@ var NoteCv = {
|
|
|
491
506
|
const pitch = ctx.createConstantSource();
|
|
492
507
|
pitch.offset.value = 60;
|
|
493
508
|
pitch.start();
|
|
509
|
+
const velocity = ctx.createConstantSource();
|
|
510
|
+
velocity.offset.value = 0;
|
|
511
|
+
velocity.start();
|
|
494
512
|
return {
|
|
495
513
|
gate,
|
|
496
514
|
pitch,
|
|
515
|
+
velocity,
|
|
497
516
|
trigger(time, h) {
|
|
498
517
|
if (typeof h?.value === "number") pitch.offset.setValueAtTime(h.value, time);
|
|
499
|
-
|
|
500
|
-
|
|
518
|
+
velocity.offset.setValueAtTime(vel(h), time);
|
|
519
|
+
const edge = Math.max(0, time - 1 / ctx.sampleRate);
|
|
520
|
+
gate.offset.cancelScheduledValues(edge);
|
|
521
|
+
gate.offset.setValueAtTime(0, edge);
|
|
522
|
+
gate.offset.setValueAtTime(1, time);
|
|
501
523
|
gate.offset.setValueAtTime(0, time + (h?.duration ?? 0.1));
|
|
502
524
|
},
|
|
503
525
|
dispose() {
|
|
504
|
-
gate
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
526
|
+
for (const n of [gate, pitch, velocity]) {
|
|
527
|
+
n.stop();
|
|
528
|
+
n.disconnect();
|
|
529
|
+
}
|
|
508
530
|
}
|
|
509
531
|
};
|
|
510
532
|
}
|
|
@@ -604,8 +626,9 @@ async function loadSampleSet(ctx, set, opts = {}) {
|
|
|
604
626
|
var SampleVoice = {
|
|
605
627
|
create(ctx, kit, key, opts = {}) {
|
|
606
628
|
const out = ctx.createGain();
|
|
607
|
-
const buf = kit.buffer(key);
|
|
608
629
|
const root = opts.root ?? 60;
|
|
630
|
+
let current = kit;
|
|
631
|
+
let buf = kit.buffer(key);
|
|
609
632
|
const trigger = (when, h) => {
|
|
610
633
|
if (!buf) return;
|
|
611
634
|
const src = ctx.createBufferSource();
|
|
@@ -619,6 +642,13 @@ var SampleVoice = {
|
|
|
619
642
|
return {
|
|
620
643
|
output: out,
|
|
621
644
|
trigger,
|
|
645
|
+
get kit() {
|
|
646
|
+
return current;
|
|
647
|
+
},
|
|
648
|
+
setKit(next) {
|
|
649
|
+
current = next;
|
|
650
|
+
buf = next.buffer(key);
|
|
651
|
+
},
|
|
622
652
|
connect: (d) => {
|
|
623
653
|
out.connect(d);
|
|
624
654
|
return d;
|
|
@@ -679,14 +709,33 @@ function createFormantNode(ctx) {
|
|
|
679
709
|
return new AudioWorkletNode(ctx, "formant-table", {
|
|
680
710
|
numberOfInputs: 1,
|
|
681
711
|
numberOfOutputs: 1,
|
|
682
|
-
outputChannelCount: [
|
|
712
|
+
outputChannelCount: [11]
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
function createShaperNode(ctx, curve, opts = {}) {
|
|
716
|
+
return new AudioWorkletNode(ctx, "shaper", {
|
|
717
|
+
numberOfInputs: 2,
|
|
718
|
+
numberOfOutputs: 2,
|
|
719
|
+
channelCount: 2,
|
|
720
|
+
channelCountMode: "clamped-max",
|
|
721
|
+
outputChannelCount: [2, 2],
|
|
722
|
+
processorOptions: { curve, dry: opts.dry !== false }
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
function createVinylNoiseNode(ctx, seed) {
|
|
726
|
+
return new AudioWorkletNode(ctx, "vinyl-noise", {
|
|
727
|
+
numberOfInputs: 0,
|
|
728
|
+
numberOfOutputs: 1,
|
|
729
|
+
outputChannelCount: [1],
|
|
730
|
+
processorOptions: { seed }
|
|
683
731
|
});
|
|
684
732
|
}
|
|
685
733
|
function createBitcrusherNode(ctx) {
|
|
686
734
|
return new AudioWorkletNode(ctx, "bitcrusher", {
|
|
687
735
|
numberOfInputs: 1,
|
|
688
736
|
numberOfOutputs: 1,
|
|
689
|
-
|
|
737
|
+
channelCount: 2,
|
|
738
|
+
channelCountMode: "clamped-max"
|
|
690
739
|
});
|
|
691
740
|
}
|
|
692
741
|
function createSubOctaveNode(ctx) {
|
|
@@ -703,6 +752,27 @@ function createEnvFollowerNode(ctx) {
|
|
|
703
752
|
outputChannelCount: [1]
|
|
704
753
|
});
|
|
705
754
|
}
|
|
755
|
+
function createGateNode(ctx) {
|
|
756
|
+
return new AudioWorkletNode(ctx, "gate", {
|
|
757
|
+
numberOfInputs: 2,
|
|
758
|
+
numberOfOutputs: 1,
|
|
759
|
+
outputChannelCount: [2],
|
|
760
|
+
channelCount: 2,
|
|
761
|
+
channelCountMode: "clamped-max",
|
|
762
|
+
channelInterpretation: "speakers"
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
function createCompressorNode(ctx, init) {
|
|
766
|
+
return new AudioWorkletNode(ctx, "compressor", {
|
|
767
|
+
numberOfInputs: 2,
|
|
768
|
+
numberOfOutputs: 1,
|
|
769
|
+
outputChannelCount: [2],
|
|
770
|
+
channelCount: 2,
|
|
771
|
+
channelCountMode: "clamped-max",
|
|
772
|
+
channelInterpretation: "speakers",
|
|
773
|
+
parameterData: init
|
|
774
|
+
});
|
|
775
|
+
}
|
|
706
776
|
function createWaveshaperNode(ctx) {
|
|
707
777
|
return new AudioWorkletNode(ctx, "waveshaper", {
|
|
708
778
|
numberOfInputs: 1,
|
|
@@ -908,7 +978,7 @@ var filter303Descriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
908
978
|
const envDepth = ctx.createGain();
|
|
909
979
|
envDepth.gain.value = module.envMod * (1 + module.accent) * 36;
|
|
910
980
|
const accentEnvGain = ctx.createGain();
|
|
911
|
-
accentEnvGain.gain.value = module.accent *
|
|
981
|
+
accentEnvGain.gain.value = module.accent * 1;
|
|
912
982
|
input.connect(filter1);
|
|
913
983
|
filter1.connect(filter2);
|
|
914
984
|
filter2.connect(accentVCA);
|
|
@@ -938,7 +1008,7 @@ var filter303Descriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
938
1008
|
case "accent": {
|
|
939
1009
|
const acc = value;
|
|
940
1010
|
nodes.envDepth.gain.value = module.envMod * (1 + acc) * 36;
|
|
941
|
-
nodes.accentEnvGain.gain.value = acc *
|
|
1011
|
+
nodes.accentEnvGain.gain.value = acc * 1;
|
|
942
1012
|
break;
|
|
943
1013
|
}
|
|
944
1014
|
case "decay": {
|
|
@@ -964,8 +1034,9 @@ var AcidFilter = /* @__PURE__ */ defineModule(filter303Descriptor, {
|
|
|
964
1034
|
|
|
965
1035
|
// src/lib-runtime/generated/modules/auto-pan.tsx
|
|
966
1036
|
var shapes = ["sine", "triangle", "square"];
|
|
1037
|
+
var SHAPE_VALUE = { square: -1, triangle: 0, sine: 1 };
|
|
967
1038
|
var params2 = {
|
|
968
|
-
rate: { node: "
|
|
1039
|
+
rate: { node: "_freqSrc", field: "offset", unit: "Hz", default: 2, min: 0.1, max: 10 },
|
|
969
1040
|
depth: { node: "lfoGain", field: "gain", unit: "factor", default: 0.8, min: 0, max: 1 },
|
|
970
1041
|
shape: { kind: "enum", options: shapes, default: "sine" }
|
|
971
1042
|
};
|
|
@@ -975,7 +1046,7 @@ var autoPanDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
975
1046
|
ports: {
|
|
976
1047
|
"in": { type: "input", signal: "audio", node: "input" },
|
|
977
1048
|
"out": { type: "output", signal: "audio", node: "output" },
|
|
978
|
-
"modRate": { type: "modulation", signal: "modulation", node: "
|
|
1049
|
+
"modRate": { type: "modulation", signal: "modulation", node: "_freqSrc", field: "offset" },
|
|
979
1050
|
"modDepth": { type: "modulation", signal: "modulation", node: "lfoGain", field: "gain" }
|
|
980
1051
|
},
|
|
981
1052
|
createModule(id, position) {
|
|
@@ -985,34 +1056,41 @@ var autoPanDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
985
1056
|
const input = ctx.createGain();
|
|
986
1057
|
const panner = ctx.createStereoPanner();
|
|
987
1058
|
const output = ctx.createGain();
|
|
988
|
-
const
|
|
1059
|
+
const _ws = createWaveshaperNode(ctx);
|
|
1060
|
+
const _freqSrc = ctx.createConstantSource();
|
|
1061
|
+
_freqSrc.offset.value = module.rate;
|
|
1062
|
+
_freqSrc.start();
|
|
1063
|
+
_freqSrc.connect(_ws);
|
|
1064
|
+
_ws.parameters.get("skew").value = 0;
|
|
1065
|
+
_ws.parameters.get("shape").value = SHAPE_VALUE[module.shape];
|
|
989
1066
|
const lfoGain = ctx.createGain();
|
|
990
|
-
lfo.type = module.shape;
|
|
991
|
-
lfo.frequency.value = module.rate;
|
|
992
1067
|
lfoGain.gain.value = module.depth;
|
|
993
|
-
|
|
1068
|
+
_ws.connect(lfoGain);
|
|
994
1069
|
lfoGain.connect(panner.pan);
|
|
995
|
-
lfo.start();
|
|
996
1070
|
input.connect(panner);
|
|
997
1071
|
panner.connect(output);
|
|
998
|
-
return { input, output,
|
|
1072
|
+
return { input, output, _ws, _freqSrc, lfoGain };
|
|
999
1073
|
},
|
|
1000
1074
|
updateParam(nodes, _m, param, value) {
|
|
1001
1075
|
if (param === "rate") {
|
|
1002
|
-
nodes.
|
|
1076
|
+
nodes._freqSrc.offset.value = value;
|
|
1003
1077
|
} else if (param === "depth") {
|
|
1004
1078
|
nodes.lfoGain.gain.value = value;
|
|
1005
1079
|
} else if (param === "shape") {
|
|
1006
|
-
nodes.
|
|
1080
|
+
nodes._ws.parameters.get("shape").value = SHAPE_VALUE[value];
|
|
1007
1081
|
}
|
|
1008
1082
|
},
|
|
1009
1083
|
dispose(nodes) {
|
|
1010
|
-
nodes.
|
|
1084
|
+
nodes._freqSrc.stop();
|
|
1011
1085
|
}
|
|
1012
1086
|
});
|
|
1013
1087
|
|
|
1014
1088
|
// src/lib-runtime/generated/modules/auto-pan.wrapper.ts
|
|
1015
|
-
var AutoPan = /* @__PURE__ */ defineModule(autoPanDescriptor
|
|
1089
|
+
var AutoPan = /* @__PURE__ */ defineModule(autoPanDescriptor, {
|
|
1090
|
+
worklets: {
|
|
1091
|
+
"waveshaper": waveshaper_default
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1016
1094
|
|
|
1017
1095
|
// src/lib/dsp/mix.ts
|
|
1018
1096
|
var CURVE_POINTS = 2049;
|
|
@@ -1064,7 +1142,10 @@ var bitcrusherDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1064
1142
|
params: params3,
|
|
1065
1143
|
ports: {
|
|
1066
1144
|
"in": { type: "input", signal: "audio", node: "input" },
|
|
1067
|
-
"out": { type: "output", signal: "audio", node: "output" }
|
|
1145
|
+
"out": { type: "output", signal: "audio", node: "output" },
|
|
1146
|
+
"modBits": { type: "modulation", signal: "modulation", node: "crusher", field: "bits" },
|
|
1147
|
+
"modRate": { type: "modulation", signal: "modulation", node: "crusher", field: "rate" },
|
|
1148
|
+
"modMix": { type: "modulation", signal: "modulation", node: "_mix", field: "offset" }
|
|
1068
1149
|
},
|
|
1069
1150
|
createModule(id, position) {
|
|
1070
1151
|
return { id, type: "bitcrusher", position, ...paramDefaults(params3) };
|
|
@@ -1105,6 +1186,8 @@ var Bitcrusher = /* @__PURE__ */ defineModule(bitcrusherDescriptor, {
|
|
|
1105
1186
|
});
|
|
1106
1187
|
|
|
1107
1188
|
// src/lib-runtime/generated/modules/chorus.tsx
|
|
1189
|
+
var CENTRE_S = 566e-5;
|
|
1190
|
+
var SWING_S = 4e-3;
|
|
1108
1191
|
var params4 = {
|
|
1109
1192
|
rate: { node: "lfo", field: "frequency", unit: "Hz", default: 1.5, min: 0.1, max: 5 },
|
|
1110
1193
|
depth: { unit: "factor", default: 0.5, min: 0, max: 1 },
|
|
@@ -1137,8 +1220,8 @@ var chorusDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1137
1220
|
const lfoGain = ctx.createGain();
|
|
1138
1221
|
const lfoInv = ctx.createGain();
|
|
1139
1222
|
const merger = ctx.createChannelMerger(2);
|
|
1140
|
-
delayL.delayTime.value =
|
|
1141
|
-
delayR.delayTime.value =
|
|
1223
|
+
delayL.delayTime.value = CENTRE_S;
|
|
1224
|
+
delayR.delayTime.value = CENTRE_S;
|
|
1142
1225
|
const _mix = ctx.createConstantSource();
|
|
1143
1226
|
_mix.offset.value = module.mix;
|
|
1144
1227
|
dryGain.gain.value = 1;
|
|
@@ -1150,7 +1233,7 @@ var chorusDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1150
1233
|
_mix.start();
|
|
1151
1234
|
lfo.type = "sine";
|
|
1152
1235
|
lfo.frequency.value = module.rate;
|
|
1153
|
-
lfoGain.gain.value = module.depth *
|
|
1236
|
+
lfoGain.gain.value = module.depth * SWING_S;
|
|
1154
1237
|
lfoInv.gain.value = -1;
|
|
1155
1238
|
lfo.connect(lfoGain);
|
|
1156
1239
|
lfoGain.connect(delayL.delayTime);
|
|
@@ -1174,7 +1257,7 @@ var chorusDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1174
1257
|
nodes.lfo.frequency.value = value;
|
|
1175
1258
|
break;
|
|
1176
1259
|
case "depth":
|
|
1177
|
-
nodes.lfoGain.gain.value = value *
|
|
1260
|
+
nodes.lfoGain.gain.value = value * SWING_S;
|
|
1178
1261
|
break;
|
|
1179
1262
|
case "mix":
|
|
1180
1263
|
nodes._mix.offset.value = value;
|
|
@@ -1287,62 +1370,59 @@ var CombFilter = /* @__PURE__ */ defineModule(combFilterDescriptor, {
|
|
|
1287
1370
|
var params6 = {
|
|
1288
1371
|
threshold: { node: "comp", field: "threshold", unit: "dB", default: -24, min: -60, max: 0 },
|
|
1289
1372
|
ratio: { node: "comp", field: "ratio", unit: "factor", default: 4, min: 1, max: 20, scale: "log" },
|
|
1290
|
-
attack: { node: "comp", field: "attack", unit: "s", default: 3e-3, min: 1e-
|
|
1373
|
+
attack: { node: "comp", field: "attack", unit: "s", default: 3e-3, min: 1e-4, max: 1, scale: "log" },
|
|
1291
1374
|
release: { node: "comp", field: "release", unit: "s", default: 0.25, min: 0.01, max: 1, scale: "log" },
|
|
1292
1375
|
knee: { node: "comp", field: "knee", unit: "dB", default: 10, min: 0, max: 40 },
|
|
1293
|
-
|
|
1294
|
-
// not
|
|
1295
|
-
|
|
1376
|
+
makeup: { node: "comp", field: "makeup", unit: "dB", default: 0, min: 0, max: 30 },
|
|
1377
|
+
// A switch, not jack sensing: the browser reports an input as empty
|
|
1378
|
+
// whenever its source stops (e.g. between drum samples). See compressor.ts.
|
|
1379
|
+
keySource: { kind: "enum", options: ["internal", "external"], default: "internal" }
|
|
1296
1380
|
};
|
|
1297
1381
|
var compressorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
1298
1382
|
type: "compressor",
|
|
1299
1383
|
params: params6,
|
|
1300
1384
|
ports: {
|
|
1301
1385
|
"in": { type: "input", signal: "audio", node: "comp" },
|
|
1302
|
-
"
|
|
1386
|
+
"key": { type: "input", signal: "audio", node: "_keyIn" },
|
|
1387
|
+
"out": { type: "output", signal: "audio", node: "comp" }
|
|
1303
1388
|
},
|
|
1304
1389
|
createModule(id, position) {
|
|
1305
|
-
return { id, type: "compressor", position, ...paramDefaults(params6) };
|
|
1390
|
+
return { id, type: "compressor", position, timeUnit: "tau", ...paramDefaults(params6) };
|
|
1306
1391
|
},
|
|
1392
|
+
// One worklet does detection, gain computing, smoothing and makeup — every
|
|
1393
|
+
// knob is one of its AudioParams, 1:1. See src/worklets/compressor.ts.
|
|
1307
1394
|
createNodes(ctx, module) {
|
|
1308
|
-
const comp = ctx
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1395
|
+
const comp = createCompressorNode(ctx, {
|
|
1396
|
+
threshold: module.threshold,
|
|
1397
|
+
ratio: module.ratio,
|
|
1398
|
+
attack: module.attack,
|
|
1399
|
+
release: module.release,
|
|
1400
|
+
knee: module.knee,
|
|
1401
|
+
makeup: module.makeup ?? 0,
|
|
1402
|
+
keyExt: module.keySource === "external" ? 1 : 0
|
|
1403
|
+
});
|
|
1404
|
+
const _keyIn = ctx.createGain();
|
|
1405
|
+
_keyIn.channelCount = 2;
|
|
1406
|
+
_keyIn.channelCountMode = "clamped-max";
|
|
1407
|
+
_keyIn.connect(comp, 0, 1);
|
|
1408
|
+
return { comp, _keyIn };
|
|
1318
1409
|
},
|
|
1319
1410
|
updateParam(nodes, _m, param, value) {
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
nodes.comp.threshold.value = v;
|
|
1324
|
-
break;
|
|
1325
|
-
case "ratio":
|
|
1326
|
-
nodes.comp.ratio.value = v;
|
|
1327
|
-
break;
|
|
1328
|
-
case "attack":
|
|
1329
|
-
nodes.comp.attack.value = v;
|
|
1330
|
-
break;
|
|
1331
|
-
case "release":
|
|
1332
|
-
nodes.comp.release.value = v;
|
|
1333
|
-
break;
|
|
1334
|
-
case "knee":
|
|
1335
|
-
nodes.comp.knee.value = v;
|
|
1336
|
-
break;
|
|
1337
|
-
case "makeup":
|
|
1338
|
-
nodes.makeup.gain.value = Math.pow(10, v / 20);
|
|
1339
|
-
break;
|
|
1411
|
+
if (param === "keySource") {
|
|
1412
|
+
nodes.comp.parameters.get("keyExt").value = value === "external" ? 1 : 0;
|
|
1413
|
+
return;
|
|
1340
1414
|
}
|
|
1415
|
+
const p = nodes.comp.parameters.get(param);
|
|
1416
|
+
if (p) p.value = value;
|
|
1341
1417
|
}
|
|
1342
1418
|
});
|
|
1343
1419
|
|
|
1344
1420
|
// src/lib-runtime/generated/modules/comp.wrapper.ts
|
|
1345
|
-
var Compressor = /* @__PURE__ */ defineModule(compressorDescriptor
|
|
1421
|
+
var Compressor = /* @__PURE__ */ defineModule(compressorDescriptor, {
|
|
1422
|
+
worklets: {
|
|
1423
|
+
"compressor": compressor_default
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1346
1426
|
|
|
1347
1427
|
// src/lib-runtime/generated/modules/crossfade.tsx
|
|
1348
1428
|
var params7 = {
|
|
@@ -1469,7 +1549,19 @@ var Delay = /* @__PURE__ */ defineModule(delayDescriptor, {
|
|
|
1469
1549
|
});
|
|
1470
1550
|
|
|
1471
1551
|
// src/lib-runtime/generated/modules/dimension.tsx
|
|
1552
|
+
var CENTER_S = 35e-4;
|
|
1553
|
+
var SWING_S2 = 185e-5;
|
|
1554
|
+
var WET = 0.5;
|
|
1555
|
+
var CROSS_HPF_HZ = 200;
|
|
1556
|
+
var BUTTERWORTH_Q_DB = -3.0102999566;
|
|
1557
|
+
function setWidth(n, w) {
|
|
1558
|
+
n.llGain.gain.value = (1 + w) / 2;
|
|
1559
|
+
n.rrGain.gain.value = (1 + w) / 2;
|
|
1560
|
+
n.rlGain.gain.value = (1 - w) / 2;
|
|
1561
|
+
n.lrGain.gain.value = (1 - w) / 2;
|
|
1562
|
+
}
|
|
1472
1563
|
var params9 = {
|
|
1564
|
+
width: { unit: "factor", default: 1.5, min: 0, max: 2 },
|
|
1473
1565
|
rate: { node: "lfo", field: "frequency", unit: "Hz", default: 0.5, min: 0.1, max: 5 },
|
|
1474
1566
|
depth: { unit: "factor", default: 0.3, min: 0, max: 1 }
|
|
1475
1567
|
};
|
|
@@ -1484,6 +1576,24 @@ var dimensionDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1484
1576
|
createModule(id, position) {
|
|
1485
1577
|
return { id, type: "dimension", position, ...paramDefaults(params9) };
|
|
1486
1578
|
},
|
|
1579
|
+
// Roland SDD-320 topology (Haible's service-schematic description, HSR 1984
|
|
1580
|
+
// review, pendragon-andyh's Juno-60 BBD analysis — see
|
|
1581
|
+
// reports/expectations/discussion/dimension.md): the dry signal anchors
|
|
1582
|
+
// both outputs; each BBD line is mixed in phase into its own channel and
|
|
1583
|
+
// inverted into the other, with the low end kept out of the cancellation.
|
|
1584
|
+
// Two short BBD-range lines (1.65–5.35 ms at full DEPTH) swept by ONE
|
|
1585
|
+
// triangle LFO in antiphase. Written out, that matrix is
|
|
1586
|
+
// A = dry_L + WET·HP(bbdA − bbdB), B = dry_R − WET·HP(bbdA − bbdB)
|
|
1587
|
+
// i.e. the moving DIFFERENCE of the two lines becomes side signal. Nothing
|
|
1588
|
+
// reaches the mid, so there is no vibrato and the mono sum is exactly the
|
|
1589
|
+
// dry input (the hardware's famed mono compatibility); the bass stays dry
|
|
1590
|
+
// and centred. HP is a Linkwitz-Riley 4th-order low-cut at 200 Hz; since
|
|
1591
|
+
// the side enters A and B in opposite polarity, the mono sum cancels it
|
|
1592
|
+
// whatever its phase, so a steep filter costs no mono compatibility.
|
|
1593
|
+
// Previously the module was 100% wet — two 10/12 ms modulated delays, i.e.
|
|
1594
|
+
// a stereo vibrato with 10 ms of latency and nothing anchoring pitch.
|
|
1595
|
+
// WIDTH then scales the side of (A, B): L = M + w·S, R = M − w·S, so
|
|
1596
|
+
// 0 = mono, 1 = the hardware matrix, 2 = exaggerated.
|
|
1487
1597
|
createNodes(ctx, module) {
|
|
1488
1598
|
const input = ctx.createGain();
|
|
1489
1599
|
input.channelCount = 2;
|
|
@@ -1497,51 +1607,62 @@ var dimensionDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1497
1607
|
const lfo = ctx.createOscillator();
|
|
1498
1608
|
const lfoGainL = ctx.createGain();
|
|
1499
1609
|
const lfoGainR = ctx.createGain();
|
|
1610
|
+
const invB = ctx.createGain();
|
|
1611
|
+
invB.gain.value = -1;
|
|
1612
|
+
const diff = ctx.createGain();
|
|
1613
|
+
const hp1 = ctx.createBiquadFilter();
|
|
1614
|
+
hp1.type = "highpass";
|
|
1615
|
+
hp1.frequency.value = CROSS_HPF_HZ;
|
|
1616
|
+
hp1.Q.value = BUTTERWORTH_Q_DB;
|
|
1617
|
+
const hp2 = ctx.createBiquadFilter();
|
|
1618
|
+
hp2.type = "highpass";
|
|
1619
|
+
hp2.frequency.value = CROSS_HPF_HZ;
|
|
1620
|
+
hp2.Q.value = BUTTERWORTH_Q_DB;
|
|
1621
|
+
const side = ctx.createGain();
|
|
1622
|
+
side.gain.value = WET;
|
|
1623
|
+
const sideInv = ctx.createGain();
|
|
1624
|
+
sideInv.gain.value = -1;
|
|
1625
|
+
const aSum = ctx.createGain();
|
|
1626
|
+
const bSum = ctx.createGain();
|
|
1500
1627
|
const llGain = ctx.createGain();
|
|
1501
1628
|
const lrGain = ctx.createGain();
|
|
1502
1629
|
const rlGain = ctx.createGain();
|
|
1503
1630
|
const rrGain = ctx.createGain();
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
lrGain.gain.value = (1 - w) / 2;
|
|
1509
|
-
leftDelay.delayTime.value = 0.01;
|
|
1510
|
-
rightDelay.delayTime.value = 0.012;
|
|
1511
|
-
lfo.type = "sine";
|
|
1631
|
+
setWidth({ llGain, lrGain, rlGain, rrGain }, module.width);
|
|
1632
|
+
leftDelay.delayTime.value = CENTER_S;
|
|
1633
|
+
rightDelay.delayTime.value = CENTER_S;
|
|
1634
|
+
lfo.type = "triangle";
|
|
1512
1635
|
lfo.frequency.value = module.rate;
|
|
1513
|
-
lfoGainL.gain.value = module.depth *
|
|
1514
|
-
lfoGainR.gain.value = -module.depth *
|
|
1636
|
+
lfoGainL.gain.value = module.depth * SWING_S2;
|
|
1637
|
+
lfoGainR.gain.value = -module.depth * SWING_S2;
|
|
1515
1638
|
lfo.connect(lfoGainL);
|
|
1516
1639
|
lfo.connect(lfoGainR);
|
|
1517
1640
|
lfoGainL.connect(leftDelay.delayTime);
|
|
1518
1641
|
lfoGainR.connect(rightDelay.delayTime);
|
|
1519
1642
|
lfo.start();
|
|
1520
1643
|
input.connect(splitter);
|
|
1644
|
+
splitter.connect(aSum, 0);
|
|
1645
|
+
splitter.connect(bSum, 1);
|
|
1521
1646
|
splitter.connect(leftDelay, 0);
|
|
1522
1647
|
splitter.connect(rightDelay, 1);
|
|
1523
|
-
leftDelay.connect(
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
lrGain.connect(merger, 0, 1);
|
|
1530
|
-
|
|
1648
|
+
leftDelay.connect(diff);
|
|
1649
|
+
rightDelay.connect(invB).connect(diff);
|
|
1650
|
+
diff.connect(hp1).connect(hp2).connect(side);
|
|
1651
|
+
side.connect(aSum);
|
|
1652
|
+
side.connect(sideInv).connect(bSum);
|
|
1653
|
+
aSum.connect(llGain).connect(merger, 0, 0);
|
|
1654
|
+
aSum.connect(lrGain).connect(merger, 0, 1);
|
|
1655
|
+
bSum.connect(rlGain).connect(merger, 0, 0);
|
|
1656
|
+
bSum.connect(rrGain).connect(merger, 0, 1);
|
|
1531
1657
|
merger.connect(output);
|
|
1532
|
-
return { input, output, splitter, merger, leftDelay, rightDelay, lfo, lfoGainL, lfoGainR, llGain, rrGain, lrGain, rlGain };
|
|
1658
|
+
return { input, output, splitter, merger, leftDelay, rightDelay, lfo, lfoGainL, lfoGainR, invB, diff, hp1, hp2, side, sideInv, aSum, bSum, llGain, rrGain, lrGain, rlGain };
|
|
1533
1659
|
},
|
|
1534
1660
|
updateParam(nodes, _m, param, value) {
|
|
1535
|
-
if (param === "width")
|
|
1536
|
-
|
|
1537
|
-
nodes.llGain.gain.value = (1 + w) / 2;
|
|
1538
|
-
nodes.rrGain.gain.value = (1 + w) / 2;
|
|
1539
|
-
nodes.rlGain.gain.value = (1 - w) / 2;
|
|
1540
|
-
nodes.lrGain.gain.value = (1 - w) / 2;
|
|
1541
|
-
} else if (param === "rate") nodes.lfo.frequency.value = value;
|
|
1661
|
+
if (param === "width") setWidth(nodes, value);
|
|
1662
|
+
else if (param === "rate") nodes.lfo.frequency.value = value;
|
|
1542
1663
|
else if (param === "depth") {
|
|
1543
|
-
nodes.lfoGainL.gain.value = value *
|
|
1544
|
-
nodes.lfoGainR.gain.value = -value *
|
|
1664
|
+
nodes.lfoGainL.gain.value = value * SWING_S2;
|
|
1665
|
+
nodes.lfoGainR.gain.value = -value * SWING_S2;
|
|
1545
1666
|
}
|
|
1546
1667
|
},
|
|
1547
1668
|
dispose(nodes) {
|
|
@@ -1613,12 +1734,10 @@ var distortionDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1613
1734
|
const output = ctx.createGain();
|
|
1614
1735
|
const dryGain = ctx.createGain();
|
|
1615
1736
|
const wetGain = ctx.createGain();
|
|
1616
|
-
const waveshaper = ctx.
|
|
1737
|
+
const waveshaper = createShaperNode(ctx, makeDistortionCurve(module.distortionType, module.drive));
|
|
1617
1738
|
const makeup = ctx.createGain();
|
|
1618
1739
|
const dcBlock = ctx.createBiquadFilter();
|
|
1619
1740
|
const toneFilter = ctx.createBiquadFilter();
|
|
1620
|
-
waveshaper.curve = makeDistortionCurve(module.distortionType, module.drive);
|
|
1621
|
-
waveshaper.oversample = "4x";
|
|
1622
1741
|
makeup.gain.value = computeMakeup(module.distortionType, module.drive);
|
|
1623
1742
|
dcBlock.type = "highpass";
|
|
1624
1743
|
dcBlock.frequency.value = 10;
|
|
@@ -1627,9 +1746,9 @@ var distortionDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1627
1746
|
toneFilter.frequency.value = module.frequency;
|
|
1628
1747
|
toneFilter.Q.value = 0.707;
|
|
1629
1748
|
const _mix = createMix(ctx, dryGain, wetGain, module.mix, "linear");
|
|
1630
|
-
input.connect(dryGain);
|
|
1631
1749
|
input.connect(waveshaper);
|
|
1632
|
-
waveshaper.connect(
|
|
1750
|
+
waveshaper.connect(dryGain, 1);
|
|
1751
|
+
waveshaper.connect(makeup, 0);
|
|
1633
1752
|
makeup.connect(dcBlock);
|
|
1634
1753
|
dcBlock.connect(toneFilter);
|
|
1635
1754
|
toneFilter.connect(wetGain);
|
|
@@ -1639,7 +1758,7 @@ var distortionDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1639
1758
|
},
|
|
1640
1759
|
updateParam(nodes, module, param, value) {
|
|
1641
1760
|
if (param === "drive" || param === "distortionType") {
|
|
1642
|
-
nodes.waveshaper.curve
|
|
1761
|
+
nodes.waveshaper.port.postMessage({ curve: makeDistortionCurve(module.distortionType, module.drive) });
|
|
1643
1762
|
nodes.makeup.gain.value = computeMakeup(module.distortionType, module.drive);
|
|
1644
1763
|
}
|
|
1645
1764
|
if (param === "frequency") {
|
|
@@ -1652,7 +1771,11 @@ var distortionDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1652
1771
|
});
|
|
1653
1772
|
|
|
1654
1773
|
// src/lib-runtime/generated/modules/distortion.wrapper.ts
|
|
1655
|
-
var Distortion = /* @__PURE__ */ defineModule(distortionDescriptor
|
|
1774
|
+
var Distortion = /* @__PURE__ */ defineModule(distortionDescriptor, {
|
|
1775
|
+
worklets: {
|
|
1776
|
+
"shaper": shaper_default
|
|
1777
|
+
}
|
|
1778
|
+
});
|
|
1656
1779
|
|
|
1657
1780
|
// src/lib-runtime/generated/modules/ducker.tsx
|
|
1658
1781
|
var params11 = {
|
|
@@ -1954,22 +2077,21 @@ var exciterDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1954
2077
|
const dryGain = ctx.createGain();
|
|
1955
2078
|
const wetGain = ctx.createGain();
|
|
1956
2079
|
const highpass = ctx.createBiquadFilter();
|
|
1957
|
-
const saturation = ctx.
|
|
2080
|
+
const saturation = createShaperNode(ctx, makeExciterCurve(module.drive));
|
|
1958
2081
|
const highshelf = ctx.createBiquadFilter();
|
|
1959
2082
|
highpass.type = "highpass";
|
|
1960
2083
|
highpass.frequency.value = module.frequency;
|
|
1961
2084
|
highpass.Q.value = 0.7;
|
|
1962
|
-
saturation.curve = makeExciterCurve(module.drive);
|
|
1963
|
-
saturation.oversample = "2x";
|
|
1964
2085
|
highshelf.type = "highshelf";
|
|
1965
2086
|
highshelf.frequency.value = module.frequency;
|
|
1966
2087
|
highshelf.gain.value = 6 + module.drive * 6;
|
|
1967
2088
|
dryGain.gain.value = 1;
|
|
1968
2089
|
wetGain.gain.value = module.mix;
|
|
1969
|
-
input.connect(
|
|
2090
|
+
input.connect(saturation, 0, 1);
|
|
2091
|
+
saturation.connect(dryGain, 1);
|
|
1970
2092
|
input.connect(highpass);
|
|
1971
|
-
highpass.connect(saturation);
|
|
1972
|
-
saturation.connect(highshelf);
|
|
2093
|
+
highpass.connect(saturation, 0, 0);
|
|
2094
|
+
saturation.connect(highshelf, 0);
|
|
1973
2095
|
highshelf.connect(wetGain);
|
|
1974
2096
|
dryGain.connect(output);
|
|
1975
2097
|
wetGain.connect(output);
|
|
@@ -1977,7 +2099,7 @@ var exciterDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1977
2099
|
},
|
|
1978
2100
|
updateParam(nodes, _m, param, value) {
|
|
1979
2101
|
if (param === "drive") {
|
|
1980
|
-
nodes.saturation.curve
|
|
2102
|
+
nodes.saturation.port.postMessage({ curve: makeExciterCurve(value) });
|
|
1981
2103
|
nodes.highshelf.gain.value = 6 + value * 6;
|
|
1982
2104
|
} else if (param === "frequency") {
|
|
1983
2105
|
nodes.highpass.frequency.value = value;
|
|
@@ -1989,7 +2111,11 @@ var exciterDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
1989
2111
|
});
|
|
1990
2112
|
|
|
1991
2113
|
// src/lib-runtime/generated/modules/exciter.wrapper.ts
|
|
1992
|
-
var Exciter = /* @__PURE__ */ defineModule(exciterDescriptor
|
|
2114
|
+
var Exciter = /* @__PURE__ */ defineModule(exciterDescriptor, {
|
|
2115
|
+
worklets: {
|
|
2116
|
+
"shaper": shaper_default
|
|
2117
|
+
}
|
|
2118
|
+
});
|
|
1993
2119
|
|
|
1994
2120
|
// src/lib-runtime/generated/modules/flanger.tsx
|
|
1995
2121
|
var params16 = {
|
|
@@ -2057,7 +2183,7 @@ var Flanger = /* @__PURE__ */ defineModule(flangerDescriptor, {
|
|
|
2057
2183
|
// src/lib-runtime/generated/modules/formant.tsx
|
|
2058
2184
|
var params17 = {
|
|
2059
2185
|
morph: { unit: "factor", default: 0, min: 0, max: 5 },
|
|
2060
|
-
resonance: { unit: "factor", default: 6, min: 1, max: 20, scale: "sqrt" },
|
|
2186
|
+
resonance: { node: "formantWorklet", field: "resonance", unit: "factor", default: 6, min: 1, max: 20, scale: "sqrt" },
|
|
2061
2187
|
mix: { unit: "factor", default: 1, min: 0, max: 1 }
|
|
2062
2188
|
};
|
|
2063
2189
|
var formantDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
@@ -2076,75 +2202,54 @@ var formantDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
2076
2202
|
const output = ctx.createGain();
|
|
2077
2203
|
const dryGain = ctx.createGain();
|
|
2078
2204
|
const wetGain = ctx.createGain();
|
|
2079
|
-
const
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2205
|
+
const bands = [0, 1, 2, 3, 4].map(() => {
|
|
2206
|
+
const f = ctx.createBiquadFilter();
|
|
2207
|
+
f.type = "bandpass";
|
|
2208
|
+
f.frequency.value = 0;
|
|
2209
|
+
f.Q.value = 0;
|
|
2210
|
+
return f;
|
|
2211
|
+
});
|
|
2085
2212
|
const formantWorklet = createFormantNode(ctx);
|
|
2086
|
-
|
|
2213
|
+
const wp = formantWorklet.parameters;
|
|
2214
|
+
wp.get("baseMorph").value = module.morph;
|
|
2215
|
+
wp.get("resonance").value = module.resonance;
|
|
2087
2216
|
const vowelCV = ctx.createGain();
|
|
2088
2217
|
vowelCV.gain.value = 1;
|
|
2089
2218
|
vowelCV.connect(formantWorklet);
|
|
2090
|
-
const splitter = ctx.createChannelSplitter(
|
|
2219
|
+
const splitter = ctx.createChannelSplitter(11);
|
|
2091
2220
|
formantWorklet.connect(splitter);
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
f2.Q.value = module.resonance * 0.4;
|
|
2109
|
-
f3.Q.value = module.resonance * 0.3;
|
|
2110
|
-
f4.Q.value = module.resonance * 0.25;
|
|
2111
|
-
f5.Q.value = module.resonance * 0.2;
|
|
2221
|
+
bands.forEach((f, k) => {
|
|
2222
|
+
splitter.connect(f.frequency, k);
|
|
2223
|
+
splitter.connect(f.Q, 5 + k);
|
|
2224
|
+
});
|
|
2225
|
+
const BAND_GAIN = [1, -1, 1, -0.5, 0.35];
|
|
2226
|
+
const bandGains = bands.map((f, k) => {
|
|
2227
|
+
const g = ctx.createGain();
|
|
2228
|
+
g.gain.value = BAND_GAIN[k];
|
|
2229
|
+
input.connect(f);
|
|
2230
|
+
f.connect(g);
|
|
2231
|
+
return g;
|
|
2232
|
+
});
|
|
2233
|
+
const formantMix = ctx.createGain();
|
|
2234
|
+
formantMix.gain.value = 0;
|
|
2235
|
+
splitter.connect(formantMix.gain, 10);
|
|
2236
|
+
bandGains.forEach((g) => g.connect(formantMix));
|
|
2112
2237
|
dryGain.gain.value = 1 - module.mix;
|
|
2113
2238
|
wetGain.gain.value = module.mix;
|
|
2114
|
-
formantMix.gain.value = 2;
|
|
2115
|
-
const f4Gain = ctx.createGain();
|
|
2116
|
-
const f5Gain = ctx.createGain();
|
|
2117
|
-
f4Gain.gain.value = 0.5;
|
|
2118
|
-
f5Gain.gain.value = 0.35;
|
|
2119
2239
|
input.connect(dryGain);
|
|
2120
|
-
input.connect(f1);
|
|
2121
|
-
input.connect(f2);
|
|
2122
|
-
input.connect(f3);
|
|
2123
|
-
input.connect(f4);
|
|
2124
|
-
input.connect(f5);
|
|
2125
|
-
f1.connect(formantMix);
|
|
2126
|
-
f2.connect(formantMix);
|
|
2127
|
-
f3.connect(formantMix);
|
|
2128
|
-
f4.connect(f4Gain);
|
|
2129
|
-
f5.connect(f5Gain);
|
|
2130
|
-
f4Gain.connect(formantMix);
|
|
2131
|
-
f5Gain.connect(formantMix);
|
|
2132
2240
|
formantMix.connect(wetGain);
|
|
2133
2241
|
dryGain.connect(output);
|
|
2134
2242
|
wetGain.connect(output);
|
|
2243
|
+
const [f1, f2, f3, f4, f5] = bands;
|
|
2135
2244
|
const _alive = createKeepAlive(ctx, f1, f2, f3, f4, f5);
|
|
2136
|
-
return { input, output, vowelCV, f1, f2, f3, f4, f5,
|
|
2245
|
+
return { input, output, vowelCV, f1, f2, f3, f4, f5, formantMix, dryGain, wetGain, formantWorklet, _alive };
|
|
2137
2246
|
},
|
|
2138
2247
|
updateParam(nodes, _module, param, value) {
|
|
2248
|
+
const wp = nodes.formantWorklet.parameters;
|
|
2139
2249
|
if (param === "morph") {
|
|
2140
|
-
|
|
2250
|
+
wp.get("baseMorph").value = value;
|
|
2141
2251
|
} else if (param === "resonance") {
|
|
2142
|
-
|
|
2143
|
-
nodes.f1.Q.value = r * 0.5;
|
|
2144
|
-
nodes.f2.Q.value = r * 0.4;
|
|
2145
|
-
nodes.f3.Q.value = r * 0.3;
|
|
2146
|
-
nodes.f4.Q.value = r * 0.25;
|
|
2147
|
-
nodes.f5.Q.value = r * 0.2;
|
|
2252
|
+
wp.get("resonance").value = value;
|
|
2148
2253
|
} else if (param === "mix") {
|
|
2149
2254
|
nodes.dryGain.gain.value = 1 - value;
|
|
2150
2255
|
nodes.wetGain.gain.value = value;
|
|
@@ -2211,35 +2316,22 @@ var FrequencyShifter = /* @__PURE__ */ defineModule(freqShifterDescriptor, {
|
|
|
2211
2316
|
|
|
2212
2317
|
// src/lib-runtime/generated/modules/gate.tsx
|
|
2213
2318
|
var params19 = {
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2319
|
+
threshold: { node: "gate", field: "threshold", unit: "dB", default: -40, min: -60, max: 0 },
|
|
2320
|
+
range: { node: "gate", field: "range", unit: "factor", default: 0.8, min: 0, max: 1 },
|
|
2321
|
+
// ATK/REL shape the VCA gain's own attack/release ramp once the (fixed,
|
|
2322
|
+
// fast) detector has decided open/closed — same separation as a real
|
|
2323
|
+
// hardware gate (e.g. Drawmer DS201). See src/worklets/gate.ts.
|
|
2324
|
+
attack: { node: "gate", field: "attack", unit: "s", default: 5e-3, min: 1e-3, max: 0.05, scale: "log" },
|
|
2325
|
+
release: { node: "gate", field: "release", unit: "s", default: 0.1, min: 0.01, max: 0.5, scale: "log" },
|
|
2326
|
+
// A switch, not jack sensing (see src/worklets/gate.ts).
|
|
2327
|
+
keySource: { kind: "enum", options: ["internal", "external"], default: "internal" }
|
|
2220
2328
|
};
|
|
2221
|
-
function makeGateCurve(threshold, range) {
|
|
2222
|
-
const threshLinear = Math.pow(10, threshold / 20);
|
|
2223
|
-
const kneeLow = Math.pow(10, (threshold - 2) / 20);
|
|
2224
|
-
const closed = 1 - range;
|
|
2225
|
-
const gsLen = 32768;
|
|
2226
|
-
const gsCurve = new Float32Array(gsLen);
|
|
2227
|
-
for (let i = 0; i < gsLen; i++) {
|
|
2228
|
-
const x = i / (gsLen - 1) * 2 - 1;
|
|
2229
|
-
const env = Math.max(0, x);
|
|
2230
|
-
let g;
|
|
2231
|
-
if (env >= threshLinear) g = 1;
|
|
2232
|
-
else if (env <= kneeLow) g = closed;
|
|
2233
|
-
else g = closed + (1 - closed) * ((env - kneeLow) / (threshLinear - kneeLow));
|
|
2234
|
-
gsCurve[i] = g;
|
|
2235
|
-
}
|
|
2236
|
-
return gsCurve;
|
|
2237
|
-
}
|
|
2238
2329
|
var gateDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
2239
2330
|
type: "gate",
|
|
2240
2331
|
params: params19,
|
|
2241
2332
|
ports: {
|
|
2242
2333
|
"in": { type: "input", signal: "audio", node: "input" },
|
|
2334
|
+
"key": { type: "input", signal: "audio", node: "_keyIn" },
|
|
2243
2335
|
"out": { type: "output", signal: "audio", node: "output" }
|
|
2244
2336
|
},
|
|
2245
2337
|
createModule(id, position) {
|
|
@@ -2248,37 +2340,33 @@ var gateDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
2248
2340
|
createNodes(ctx, module) {
|
|
2249
2341
|
const input = ctx.createGain();
|
|
2250
2342
|
const output = ctx.createGain();
|
|
2251
|
-
const
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
return { input, output,
|
|
2343
|
+
const gate = createGateNode(ctx);
|
|
2344
|
+
gate.parameters.get("threshold").value = module.threshold;
|
|
2345
|
+
gate.parameters.get("range").value = module.range;
|
|
2346
|
+
gate.parameters.get("attack").value = module.attack;
|
|
2347
|
+
gate.parameters.get("release").value = module.release;
|
|
2348
|
+
gate.parameters.get("keyExt").value = module.keySource === "external" ? 1 : 0;
|
|
2349
|
+
const _keyIn = ctx.createGain();
|
|
2350
|
+
_keyIn.channelCount = 2;
|
|
2351
|
+
_keyIn.channelCountMode = "clamped-max";
|
|
2352
|
+
input.connect(gate);
|
|
2353
|
+
_keyIn.connect(gate, 0, 1);
|
|
2354
|
+
gate.connect(output);
|
|
2355
|
+
return { input, output, gate, _keyIn };
|
|
2264
2356
|
},
|
|
2265
2357
|
updateParam(nodes, module, param, value) {
|
|
2266
|
-
if (param === "
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
nodes.gateShaper.curve = makeGateCurve(thresh, range);
|
|
2270
|
-
} else if (param === "attack") {
|
|
2271
|
-
nodes.envFollower.parameters.get("attack").value = value;
|
|
2272
|
-
} else if (param === "release") {
|
|
2273
|
-
nodes.envFollower.parameters.get("release").value = value;
|
|
2358
|
+
if (param === "keySource") {
|
|
2359
|
+
nodes.gate.parameters.get("keyExt").value = value === "external" ? 1 : 0;
|
|
2360
|
+
return;
|
|
2274
2361
|
}
|
|
2362
|
+
nodes.gate.parameters.get(param).value = value;
|
|
2275
2363
|
}
|
|
2276
2364
|
});
|
|
2277
2365
|
|
|
2278
2366
|
// src/lib-runtime/generated/modules/gate.wrapper.ts
|
|
2279
2367
|
var Gate = /* @__PURE__ */ defineModule(gateDescriptor, {
|
|
2280
2368
|
worklets: {
|
|
2281
|
-
"
|
|
2369
|
+
"gate": gate_default
|
|
2282
2370
|
}
|
|
2283
2371
|
});
|
|
2284
2372
|
|
|
@@ -2403,7 +2491,7 @@ var HaasWidener = /* @__PURE__ */ defineModule(haasDescriptor);
|
|
|
2403
2491
|
var params22 = {
|
|
2404
2492
|
rate: { node: "lfo", field: "frequency", unit: "Hz", default: 4, min: 1, max: 10 },
|
|
2405
2493
|
depth: { unit: "factor", default: 0.7, min: 0, max: 1 },
|
|
2406
|
-
crossover: { node: "
|
|
2494
|
+
crossover: { node: "_xover", field: "offset", unit: "Hz", default: 800, min: 200, max: 2e3 }
|
|
2407
2495
|
};
|
|
2408
2496
|
var harmonicTremDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
2409
2497
|
type: "harmonic-trem",
|
|
@@ -2412,7 +2500,7 @@ var harmonicTremDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
2412
2500
|
"in": { type: "input", signal: "audio", node: "input" },
|
|
2413
2501
|
"out": { type: "output", signal: "audio", node: "output" },
|
|
2414
2502
|
"modRate": { type: "modulation", signal: "modulation", node: "lfo", field: "frequency" },
|
|
2415
|
-
"modCrossover": { type: "modulation", signal: "modulation", node: "
|
|
2503
|
+
"modCrossover": { type: "modulation", signal: "modulation", node: "_xover", field: "offset" }
|
|
2416
2504
|
},
|
|
2417
2505
|
createModule(id, position) {
|
|
2418
2506
|
return { id, type: "harmonic-trem", position, ...paramDefaults(params22) };
|
|
@@ -2421,8 +2509,9 @@ var harmonicTremDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
2421
2509
|
const input = ctx.createGain();
|
|
2422
2510
|
const output = ctx.createGain();
|
|
2423
2511
|
const lowpass = ctx.createBiquadFilter();
|
|
2424
|
-
const
|
|
2425
|
-
const
|
|
2512
|
+
const highpass = ctx.createBiquadFilter();
|
|
2513
|
+
const hpInvert = ctx.createGain();
|
|
2514
|
+
const _xover = ctx.createConstantSource();
|
|
2426
2515
|
const lowGain = ctx.createGain();
|
|
2427
2516
|
const highGain = ctx.createGain();
|
|
2428
2517
|
const lfo = ctx.createOscillator();
|
|
@@ -2430,10 +2519,14 @@ var harmonicTremDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
2430
2519
|
const lfoGainHigh = ctx.createGain();
|
|
2431
2520
|
const lfoInvert = ctx.createGain();
|
|
2432
2521
|
lowpass.type = "lowpass";
|
|
2433
|
-
|
|
2434
|
-
lowpass
|
|
2435
|
-
|
|
2436
|
-
|
|
2522
|
+
highpass.type = "highpass";
|
|
2523
|
+
for (const f of [lowpass, highpass]) {
|
|
2524
|
+
f.Q.value = -6.0206;
|
|
2525
|
+
f.frequency.value = 0;
|
|
2526
|
+
_xover.connect(f.frequency);
|
|
2527
|
+
}
|
|
2528
|
+
_xover.offset.value = module.crossover;
|
|
2529
|
+
hpInvert.gain.value = -1;
|
|
2437
2530
|
lfo.type = "sine";
|
|
2438
2531
|
lfo.frequency.value = module.rate;
|
|
2439
2532
|
lfoGainLow.gain.value = module.depth * 0.5;
|
|
@@ -2442,20 +2535,20 @@ var harmonicTremDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
2442
2535
|
lowGain.gain.value = 1;
|
|
2443
2536
|
highGain.gain.value = 1;
|
|
2444
2537
|
input.connect(lowpass);
|
|
2445
|
-
input.connect(
|
|
2446
|
-
|
|
2447
|
-
lpInvert.connect(highBand);
|
|
2538
|
+
input.connect(highpass);
|
|
2539
|
+
highpass.connect(hpInvert);
|
|
2448
2540
|
lfo.connect(lfoGainLow);
|
|
2449
2541
|
lfo.connect(lfoInvert);
|
|
2450
2542
|
lfoInvert.connect(lfoGainHigh);
|
|
2451
2543
|
lfoGainLow.connect(lowGain.gain);
|
|
2452
2544
|
lfoGainHigh.connect(highGain.gain);
|
|
2453
2545
|
lowpass.connect(lowGain);
|
|
2454
|
-
|
|
2546
|
+
hpInvert.connect(highGain);
|
|
2455
2547
|
lowGain.connect(output);
|
|
2456
2548
|
highGain.connect(output);
|
|
2457
2549
|
lfo.start();
|
|
2458
|
-
|
|
2550
|
+
_xover.start();
|
|
2551
|
+
return { input, output, lfo, lfoGainLow, lfoGainHigh, lowpass, highpass, hpInvert, _xover };
|
|
2459
2552
|
},
|
|
2460
2553
|
updateParam(nodes, _m, param, value) {
|
|
2461
2554
|
if (param === "rate") nodes.lfo.frequency.value = value;
|
|
@@ -2463,10 +2556,11 @@ var harmonicTremDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
2463
2556
|
nodes.lfoGainLow.gain.value = value * 0.5;
|
|
2464
2557
|
nodes.lfoGainHigh.gain.value = value * 0.5;
|
|
2465
2558
|
} else if (param === "crossover") {
|
|
2466
|
-
nodes.
|
|
2559
|
+
nodes._xover.offset.value = value;
|
|
2467
2560
|
}
|
|
2468
2561
|
},
|
|
2469
2562
|
dispose(nodes) {
|
|
2563
|
+
nodes._xover.stop();
|
|
2470
2564
|
nodes.lfo.stop();
|
|
2471
2565
|
}
|
|
2472
2566
|
});
|
|
@@ -2604,21 +2698,27 @@ var Lfo = /* @__PURE__ */ defineModule(lfoDescriptor, {
|
|
|
2604
2698
|
});
|
|
2605
2699
|
|
|
2606
2700
|
// src/lib-runtime/generated/modules/lo-fi.tsx
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2701
|
+
var DRIVE_BIAS = 0.3;
|
|
2702
|
+
var INPUT_SPAN = 16;
|
|
2703
|
+
var CURVE_LEN2 = 32769;
|
|
2704
|
+
var WOBBLE_MAX_S = 2e-3;
|
|
2705
|
+
var driveK = (drive) => 0.125 * Math.pow(128, Math.max(0, Math.min(1, drive)));
|
|
2706
|
+
function loFiCurve(drive) {
|
|
2707
|
+
const k = driveK(drive);
|
|
2708
|
+
const t0 = Math.tanh(DRIVE_BIAS);
|
|
2709
|
+
const slope0 = 1 - t0 * t0;
|
|
2710
|
+
const c = new Float32Array(CURVE_LEN2);
|
|
2711
|
+
for (let i = 0; i < CURVE_LEN2; i++) {
|
|
2712
|
+
const v = i * 2 / (CURVE_LEN2 - 1) - 1;
|
|
2713
|
+
c[i] = (Math.tanh(k * INPUT_SPAN * v + DRIVE_BIAS) - t0) / (k * slope0);
|
|
2614
2714
|
}
|
|
2615
|
-
return
|
|
2715
|
+
return c;
|
|
2616
2716
|
}
|
|
2617
2717
|
var params25 = {
|
|
2618
2718
|
drive: { unit: "factor", default: 0.3, min: 0, max: 1 },
|
|
2619
2719
|
cutoff: { node: "lowpass", field: "frequency", unit: "Hz", default: 4e3, min: 500, max: 8e3 },
|
|
2620
|
-
noise: { unit: "factor", default: 0.2, min: 0, max: 1 },
|
|
2621
|
-
wobble: { unit: "factor", default: 0.1, min: 0, max: 1 }
|
|
2720
|
+
noise: { node: "noiseGain", field: "gain", unit: "factor", default: 0.2, min: 0, max: 1 },
|
|
2721
|
+
wobble: { node: "wobbleAmt", field: "offset", unit: "factor", default: 0.1, min: 0, max: 1 }
|
|
2622
2722
|
};
|
|
2623
2723
|
var loFiDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
2624
2724
|
type: "lo-fi",
|
|
@@ -2634,73 +2734,78 @@ var loFiDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
2634
2734
|
createNodes(ctx, module) {
|
|
2635
2735
|
const input = ctx.createGain();
|
|
2636
2736
|
const output = ctx.createGain();
|
|
2637
|
-
const
|
|
2737
|
+
const preGain = ctx.createGain();
|
|
2738
|
+
preGain.gain.value = 1 / INPUT_SPAN;
|
|
2739
|
+
const saturation = createShaperNode(ctx, loFiCurve(module.drive), { dry: false });
|
|
2740
|
+
const dcBlock = ctx.createBiquadFilter();
|
|
2741
|
+
dcBlock.type = "highpass";
|
|
2742
|
+
dcBlock.frequency.value = 10;
|
|
2743
|
+
dcBlock.Q.value = Math.SQRT1_2;
|
|
2638
2744
|
const lowpass = ctx.createBiquadFilter();
|
|
2639
|
-
const noiseGain = ctx.createGain();
|
|
2640
|
-
const wobbleLfo = ctx.createOscillator();
|
|
2641
|
-
const wobbleGain = ctx.createGain();
|
|
2642
|
-
saturation.curve = makeLoFiSaturationCurve(module.drive);
|
|
2643
|
-
saturation.oversample = "2x";
|
|
2644
2745
|
lowpass.type = "lowpass";
|
|
2645
2746
|
lowpass.frequency.value = module.cutoff;
|
|
2646
2747
|
lowpass.Q.value = 0.7;
|
|
2647
|
-
const
|
|
2648
|
-
|
|
2649
|
-
const
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
for (let i = 0; i < bufferSize; i++) {
|
|
2653
|
-
const white = rand();
|
|
2654
|
-
b0 = 0.99765 * b0 + white * 0.099046;
|
|
2655
|
-
b1 = 0.963 * b1 + white * 0.2965164;
|
|
2656
|
-
b2 = 0.57 * b2 + white * 1.0526913;
|
|
2657
|
-
data[i] = (b0 + b1 + b2) * 0.1;
|
|
2658
|
-
}
|
|
2659
|
-
const noiseSrc = ctx.createBufferSource();
|
|
2660
|
-
noiseSrc.buffer = noiseBuffer2;
|
|
2661
|
-
noiseSrc.loop = true;
|
|
2662
|
-
noiseGain.gain.value = module.noise * 0.05;
|
|
2663
|
-
noiseSrc.connect(noiseGain);
|
|
2664
|
-
noiseSrc.start();
|
|
2665
|
-
const wobbleDelay = ctx.createDelay(0.05);
|
|
2666
|
-
wobbleDelay.delayTime.value = 0.01;
|
|
2748
|
+
const wobbleAmt = ctx.createConstantSource();
|
|
2749
|
+
wobbleAmt.offset.value = module.wobble;
|
|
2750
|
+
const wobbleScale = ctx.createGain();
|
|
2751
|
+
wobbleScale.gain.value = WOBBLE_MAX_S;
|
|
2752
|
+
const wobbleLfo = ctx.createOscillator();
|
|
2667
2753
|
wobbleLfo.type = "sine";
|
|
2668
2754
|
wobbleLfo.frequency.value = 0.73;
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2755
|
+
const wobbleDepth = ctx.createGain();
|
|
2756
|
+
wobbleDepth.gain.value = 0;
|
|
2757
|
+
const wobbleDelay = ctx.createDelay(0.05);
|
|
2758
|
+
wobbleDelay.delayTime.value = 0;
|
|
2759
|
+
wobbleAmt.connect(wobbleScale);
|
|
2760
|
+
wobbleScale.connect(wobbleDelay.delayTime);
|
|
2761
|
+
wobbleScale.connect(wobbleDepth.gain);
|
|
2762
|
+
wobbleLfo.connect(wobbleDepth);
|
|
2763
|
+
wobbleDepth.connect(wobbleDelay.delayTime);
|
|
2764
|
+
wobbleAmt.start();
|
|
2672
2765
|
wobbleLfo.start();
|
|
2673
|
-
|
|
2674
|
-
|
|
2766
|
+
const noiseSrc = createVinylNoiseNode(ctx, NOISE_SEEDS.loFiCrackle);
|
|
2767
|
+
const noiseGain = ctx.createGain();
|
|
2768
|
+
noiseGain.gain.value = module.noise;
|
|
2769
|
+
noiseSrc.connect(noiseGain);
|
|
2770
|
+
input.connect(preGain);
|
|
2771
|
+
preGain.connect(saturation);
|
|
2772
|
+
saturation.connect(dcBlock, 0);
|
|
2773
|
+
dcBlock.connect(lowpass);
|
|
2675
2774
|
lowpass.connect(wobbleDelay);
|
|
2676
2775
|
wobbleDelay.connect(output);
|
|
2677
2776
|
noiseGain.connect(output);
|
|
2678
|
-
return { input, output, saturation,
|
|
2777
|
+
return { input, output, preGain, saturation, dcBlock, lowpass, wobbleAmt, wobbleScale, wobbleLfo, wobbleDepth, wobbleDelay, noiseSrc, noiseGain };
|
|
2679
2778
|
},
|
|
2680
2779
|
updateParam(nodes, _m, param, value) {
|
|
2681
2780
|
if (param === "drive") {
|
|
2682
|
-
nodes.saturation.curve
|
|
2781
|
+
nodes.saturation.port.postMessage({ curve: loFiCurve(value) });
|
|
2683
2782
|
} else if (param === "cutoff") {
|
|
2684
2783
|
nodes.lowpass.frequency.value = value;
|
|
2685
2784
|
} else if (param === "noise") {
|
|
2686
|
-
nodes.noiseGain.gain.value = value
|
|
2785
|
+
nodes.noiseGain.gain.value = value;
|
|
2687
2786
|
} else if (param === "wobble") {
|
|
2688
|
-
nodes.
|
|
2787
|
+
nodes.wobbleAmt.offset.value = value;
|
|
2689
2788
|
}
|
|
2690
2789
|
},
|
|
2691
2790
|
dispose(nodes) {
|
|
2692
2791
|
nodes.wobbleLfo.stop();
|
|
2693
|
-
nodes.
|
|
2792
|
+
nodes.wobbleAmt.stop();
|
|
2694
2793
|
}
|
|
2695
2794
|
});
|
|
2696
2795
|
|
|
2697
2796
|
// src/lib-runtime/generated/modules/lo-fi.wrapper.ts
|
|
2698
|
-
var LoFi = /* @__PURE__ */ defineModule(loFiDescriptor
|
|
2797
|
+
var LoFi = /* @__PURE__ */ defineModule(loFiDescriptor, {
|
|
2798
|
+
worklets: {
|
|
2799
|
+
"shaper": shaper_default,
|
|
2800
|
+
"vinyl-noise": vinyl_noise_default
|
|
2801
|
+
}
|
|
2802
|
+
});
|
|
2699
2803
|
|
|
2700
2804
|
// src/lib-runtime/generated/modules/mid-side.tsx
|
|
2701
2805
|
var params26 = {
|
|
2702
2806
|
midGain: { node: "midGainNode", field: "gain", unit: "factor", default: 1, min: 0, max: 2 },
|
|
2703
|
-
sideGain: { node: "sideGainNode", field: "gain", unit: "factor", default: 1, min: 0, max: 2 }
|
|
2807
|
+
sideGain: { node: "sideGainNode", field: "gain", unit: "factor", default: 1, min: 0, max: 2 },
|
|
2808
|
+
width: { node: "widthNode", field: "gain", unit: "factor", default: 1, min: 0, max: 2 }
|
|
2704
2809
|
};
|
|
2705
2810
|
var midSideDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
2706
2811
|
type: "mid-side",
|
|
@@ -3143,9 +3248,58 @@ function dampingToQ(damping) {
|
|
|
3143
3248
|
const d = Math.min(1, Math.max(0, Number.isFinite(damping) ? damping : 0.5));
|
|
3144
3249
|
return MODAL_Q_MAX * Math.pow(MODAL_Q_MIN / MODAL_Q_MAX, d);
|
|
3145
3250
|
}
|
|
3251
|
+
function modeT60(q, hz2) {
|
|
3252
|
+
return T60_PER_Q_HZ * q / hz2;
|
|
3253
|
+
}
|
|
3146
3254
|
function modalMakeup(q) {
|
|
3147
3255
|
return Math.sqrt(Math.max(1, q));
|
|
3148
3256
|
}
|
|
3257
|
+
var MODAL_PARTIALS = 5;
|
|
3258
|
+
var MODAL_REF_NOTE = 57;
|
|
3259
|
+
function partialEnergySum(structure) {
|
|
3260
|
+
let s = 0;
|
|
3261
|
+
for (let n = 1; n <= MODAL_PARTIALS; n++) s += Math.pow(n, -(1 + structure));
|
|
3262
|
+
return s;
|
|
3263
|
+
}
|
|
3264
|
+
function modalPartialGain(n, q, structure) {
|
|
3265
|
+
return modalMakeup(q) * Math.pow(n, -(1 + structure)) * Math.sqrt(MODAL_PARTIALS / partialEnergySum(structure)) * modalOverlapGain(q, structure);
|
|
3266
|
+
}
|
|
3267
|
+
var OVERLAP_REF_HZ = 220;
|
|
3268
|
+
var OVERLAP_SR = 48e3;
|
|
3269
|
+
var overlapCache = /* @__PURE__ */ new Map();
|
|
3270
|
+
function modalOverlapGain(q, structure) {
|
|
3271
|
+
if (!(q < 40)) return 1;
|
|
3272
|
+
const key = `${q.toFixed(4)}:${structure.toFixed(4)}`;
|
|
3273
|
+
const hit = overlapCache.get(key);
|
|
3274
|
+
if (hit !== void 0) return hit;
|
|
3275
|
+
const n = Math.ceil(2 * modeT60(q, OVERLAP_REF_HZ) * OVERLAP_SR) + 64;
|
|
3276
|
+
const sum = new Float64Array(n);
|
|
3277
|
+
let incoherent = 0;
|
|
3278
|
+
for (let p = 1; p <= MODAL_PARTIALS; p++) {
|
|
3279
|
+
const f0 = Math.min(OVERLAP_SR * 0.45, OVERLAP_REF_HZ * Math.pow(p, 1 + structure));
|
|
3280
|
+
const g = Math.pow(p, -(1 + structure));
|
|
3281
|
+
const w0 = 2 * Math.PI * f0 / OVERLAP_SR;
|
|
3282
|
+
const alpha = Math.sin(w0) / (2 * q);
|
|
3283
|
+
const a0 = 1 + alpha;
|
|
3284
|
+
const b0 = alpha / a0, a1 = -2 * Math.cos(w0) / a0, a2 = (1 - alpha) / a0;
|
|
3285
|
+
let y2 = 0, y1 = 0;
|
|
3286
|
+
for (let i = 0; i < n; i++) {
|
|
3287
|
+
const x = i === 0 ? b0 : i === 2 ? -b0 : 0;
|
|
3288
|
+
const y = x - a1 * y1 - a2 * y2;
|
|
3289
|
+
y2 = y1;
|
|
3290
|
+
y1 = y;
|
|
3291
|
+
sum[i] += g * y;
|
|
3292
|
+
incoherent += g * g * y * y;
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3295
|
+
let coherent = 0;
|
|
3296
|
+
for (let i = 0; i < n; i++) coherent += sum[i] * sum[i];
|
|
3297
|
+
const gain = coherent > 0 ? Math.sqrt(incoherent / coherent) : 1;
|
|
3298
|
+
if (overlapCache.size > 4096) overlapCache.clear();
|
|
3299
|
+
overlapCache.set(key, gain);
|
|
3300
|
+
return gain;
|
|
3301
|
+
}
|
|
3302
|
+
var MODAL_PITCH_GAIN_TRANSPOSE = 69 + 12 * (MODAL_REF_NOTE / 24 - Math.log2(440));
|
|
3149
3303
|
|
|
3150
3304
|
// src/lib-runtime/generated/modules/resonator.tsx
|
|
3151
3305
|
var params31 = {
|
|
@@ -3153,12 +3307,13 @@ var params31 = {
|
|
|
3153
3307
|
offset: { node: "_root", field: "offset", default: 57, min: -48, max: 108, unit: "semitone" },
|
|
3154
3308
|
structure: { unit: "factor", default: 0, min: 0, max: 1 },
|
|
3155
3309
|
damping: { unit: "factor", default: 0.5, min: 0, max: 1 },
|
|
3156
|
-
mix: { node: "_mix", field: "offset", unit: "factor", default:
|
|
3310
|
+
mix: { node: "_mix", field: "offset", unit: "factor", default: 1, min: 0, max: 1 }
|
|
3157
3311
|
};
|
|
3158
3312
|
function partialOffset(partial, structure) {
|
|
3159
3313
|
return 12 * (1 + structure) * Math.log2(partial);
|
|
3160
3314
|
}
|
|
3161
3315
|
var patchCount2 = /* @__PURE__ */ new WeakMap();
|
|
3316
|
+
var shape = /* @__PURE__ */ new WeakMap();
|
|
3162
3317
|
var resonatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
3163
3318
|
type: "resonator",
|
|
3164
3319
|
params: params31,
|
|
@@ -3186,7 +3341,17 @@ var resonatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3186
3341
|
const partialGains = [];
|
|
3187
3342
|
const voct = [];
|
|
3188
3343
|
const q = dampingToQ(module.damping);
|
|
3189
|
-
|
|
3344
|
+
shape.set(_pitch, { q, structure: module.structure });
|
|
3345
|
+
const _halfPitch = ctx.createGain();
|
|
3346
|
+
_halfPitch.gain.value = -0.5;
|
|
3347
|
+
_pitch.connect(_halfPitch);
|
|
3348
|
+
const _trackGain = createVoctFreqNode(ctx);
|
|
3349
|
+
_trackGain.parameters.get("transpose").value = MODAL_PITCH_GAIN_TRANSPOSE;
|
|
3350
|
+
_halfPitch.connect(_trackGain);
|
|
3351
|
+
const _track = ctx.createGain();
|
|
3352
|
+
_track.gain.value = 0;
|
|
3353
|
+
_trackGain.connect(_track.gain);
|
|
3354
|
+
_track.connect(wetGain);
|
|
3190
3355
|
for (let i = 1; i <= 5; i++) {
|
|
3191
3356
|
const v = createVoctFreqNode(ctx);
|
|
3192
3357
|
v.parameters.get("transpose").value = partialOffset(i, module.structure);
|
|
@@ -3200,9 +3365,9 @@ var resonatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3200
3365
|
voct.push(v);
|
|
3201
3366
|
input.connect(filter);
|
|
3202
3367
|
const partialGain = ctx.createGain();
|
|
3203
|
-
partialGain.gain.value =
|
|
3368
|
+
partialGain.gain.value = modalPartialGain(i, q, module.structure);
|
|
3204
3369
|
filter.connect(partialGain);
|
|
3205
|
-
partialGain.connect(
|
|
3370
|
+
partialGain.connect(_track);
|
|
3206
3371
|
partialGains.push(partialGain);
|
|
3207
3372
|
}
|
|
3208
3373
|
const _alive = createKeepAlive(ctx, ...filters);
|
|
@@ -3219,6 +3384,9 @@ var resonatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3219
3384
|
_root,
|
|
3220
3385
|
_pitch,
|
|
3221
3386
|
_alive,
|
|
3387
|
+
_halfPitch,
|
|
3388
|
+
_trackGain,
|
|
3389
|
+
_track,
|
|
3222
3390
|
v1: voct[0],
|
|
3223
3391
|
v2: voct[1],
|
|
3224
3392
|
v3: voct[2],
|
|
@@ -3244,19 +3412,20 @@ var resonatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3244
3412
|
if (!patchCount2.get(nodes)) nodes._root.offset.value = value;
|
|
3245
3413
|
} else if (param === "transpose") {
|
|
3246
3414
|
if (patchCount2.get(nodes)) nodes._root.offset.value = value;
|
|
3247
|
-
} else if (param === "structure") {
|
|
3248
|
-
const
|
|
3249
|
-
|
|
3250
|
-
|
|
3415
|
+
} else if (param === "structure" || param === "damping") {
|
|
3416
|
+
const st = shape.get(nodes._pitch);
|
|
3417
|
+
if (param === "structure") {
|
|
3418
|
+
st.structure = value;
|
|
3419
|
+
const voct = [nodes.v1, nodes.v2, nodes.v3, nodes.v4, nodes.v5];
|
|
3420
|
+
for (let i = 1; i < 5; i++) {
|
|
3421
|
+
voct[i].parameters.get("transpose").value = partialOffset(i + 1, st.structure);
|
|
3422
|
+
}
|
|
3423
|
+
} else {
|
|
3424
|
+
st.q = dampingToQ(value);
|
|
3425
|
+
for (const f of filters) f.Q.value = st.q;
|
|
3251
3426
|
}
|
|
3252
|
-
} else if (param === "damping") {
|
|
3253
|
-
const q = dampingToQ(value);
|
|
3254
|
-
const makeup = modalMakeup(q);
|
|
3255
3427
|
const gains = [nodes.g1, nodes.g2, nodes.g3, nodes.g4, nodes.g5];
|
|
3256
|
-
for (let i = 0; i < 5; i++)
|
|
3257
|
-
filters[i].Q.value = q;
|
|
3258
|
-
gains[i].gain.value = makeup / Math.sqrt(i + 1);
|
|
3259
|
-
}
|
|
3428
|
+
for (let i = 0; i < 5; i++) gains[i].gain.value = modalPartialGain(i + 1, st.q, st.structure);
|
|
3260
3429
|
} else if (param === "mix") {
|
|
3261
3430
|
nodes._mix.offset.value = value;
|
|
3262
3431
|
}
|
|
@@ -3295,13 +3464,30 @@ var Resonator = /* @__PURE__ */ defineModule(resonatorDescriptor, {
|
|
|
3295
3464
|
});
|
|
3296
3465
|
|
|
3297
3466
|
// src/lib/dsp/fdnTank.ts
|
|
3298
|
-
var
|
|
3467
|
+
var LINE_MS = [
|
|
3468
|
+
32.479167,
|
|
3469
|
+
32.645833,
|
|
3470
|
+
39.354167,
|
|
3471
|
+
37.979167,
|
|
3472
|
+
44.854167,
|
|
3473
|
+
46.729167,
|
|
3474
|
+
54.854167,
|
|
3475
|
+
54.020833,
|
|
3476
|
+
64.354167,
|
|
3477
|
+
65.020833,
|
|
3478
|
+
77.770833,
|
|
3479
|
+
76.229167,
|
|
3480
|
+
90.770833,
|
|
3481
|
+
91.854167,
|
|
3482
|
+
108.520833,
|
|
3483
|
+
108.270833
|
|
3484
|
+
];
|
|
3299
3485
|
function tankEnergyGain500(rt60, size = 1) {
|
|
3300
3486
|
let g2 = 0;
|
|
3301
|
-
for (const ms2 of
|
|
3302
|
-
g2 /=
|
|
3487
|
+
for (const ms2 of LINE_MS) g2 += Math.pow(10, -6 * (ms2 / 1e3) * size / Math.max(rt60, 0.05));
|
|
3488
|
+
g2 /= LINE_MS.length;
|
|
3303
3489
|
const loss = 1 - g2;
|
|
3304
|
-
return Math.max(0.
|
|
3490
|
+
return Math.max(0.01, 1.32117 / loss - 1.32832 - 0.01158 * loss);
|
|
3305
3491
|
}
|
|
3306
3492
|
function createFdnTank(ctx, opts) {
|
|
3307
3493
|
const input = ctx.createGain();
|
|
@@ -3481,10 +3667,10 @@ var RingModulator = /* @__PURE__ */ defineModule(ringModDescriptor, {
|
|
|
3481
3667
|
|
|
3482
3668
|
// src/lib-runtime/generated/modules/rotary.tsx
|
|
3483
3669
|
var CROSSOVER_HZ = 800;
|
|
3484
|
-
var
|
|
3670
|
+
var BUTTERWORTH_Q_DB2 = -3.0103;
|
|
3485
3671
|
var DRUM_RATIO = 0.85;
|
|
3486
|
-
var HORN = { baseDelay: 3e-3, dopplerSec: 44e-5, ampBase: 0.
|
|
3487
|
-
var DRUM = { baseDelay: 3e-3, dopplerSec: 2e-4, ampBase: 0.
|
|
3672
|
+
var HORN = { baseDelay: 3e-3, dopplerSec: 44e-5, ampBase: 0.54, ampDepth: 0.46, phaseDeg: 0, tauUp: 0.35, tauDown: 0.55 };
|
|
3673
|
+
var DRUM = { baseDelay: 3e-3, dopplerSec: 2e-4, ampBase: 0.6, ampDepth: 0.4, phaseDeg: 90, tauUp: 1.5, tauDown: 1.7 };
|
|
3488
3674
|
var params34 = {
|
|
3489
3675
|
speed: { kind: "enum", options: ["slow", "fast"], default: "slow" },
|
|
3490
3676
|
slowRate: { unit: "Hz", default: 0.8, min: 0.5, max: 2 },
|
|
@@ -3517,7 +3703,7 @@ var rotaryDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3517
3703
|
const f = ctx.createBiquadFilter();
|
|
3518
3704
|
f.type = type;
|
|
3519
3705
|
f.frequency.value = CROSSOVER_HZ;
|
|
3520
|
-
f.Q.value =
|
|
3706
|
+
f.Q.value = BUTTERWORTH_Q_DB2;
|
|
3521
3707
|
return f;
|
|
3522
3708
|
};
|
|
3523
3709
|
const lp1 = biquad("lowpass"), lp2 = biquad("lowpass");
|
|
@@ -3610,22 +3796,24 @@ var Rotary = /* @__PURE__ */ defineModule(rotaryDescriptor);
|
|
|
3610
3796
|
|
|
3611
3797
|
// src/lib-runtime/generated/modules/saturator.tsx
|
|
3612
3798
|
var params35 = {
|
|
3613
|
-
//
|
|
3614
|
-
//
|
|
3799
|
+
// DRIVE reshapes the curve (hotter knee, output trimmed to match) — no
|
|
3800
|
+
// single AudioParam carries it: set-only.
|
|
3615
3801
|
drive: { unit: "factor", default: 0.5, min: 0, max: 1 },
|
|
3616
3802
|
// warmthFilter.gain = warmth * 6 — a scaled conversion, so no node/field.
|
|
3617
3803
|
warmth: { unit: "factor", default: 0.5, min: 0, max: 1 },
|
|
3618
3804
|
mix: { node: "_mix", field: "offset", unit: "factor", default: 1, min: 0, max: 1 }
|
|
3619
3805
|
};
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3806
|
+
var INPUT_SPAN2 = 16;
|
|
3807
|
+
var CURVE_LEN3 = 32769;
|
|
3808
|
+
var driveGain = (drive) => 0.25 * Math.pow(64, Math.max(0, Math.min(1, drive)));
|
|
3809
|
+
function saturationCurve(drive) {
|
|
3810
|
+
const g = driveGain(drive);
|
|
3811
|
+
const c = new Float32Array(CURVE_LEN3);
|
|
3812
|
+
for (let i = 0; i < CURVE_LEN3; i++) {
|
|
3813
|
+
const v = i * 2 / (CURVE_LEN3 - 1) - 1;
|
|
3814
|
+
c[i] = Math.tanh(g * INPUT_SPAN2 * v) / g;
|
|
3627
3815
|
}
|
|
3628
|
-
return
|
|
3816
|
+
return c;
|
|
3629
3817
|
}
|
|
3630
3818
|
var saturatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
3631
3819
|
type: "saturator",
|
|
@@ -3642,29 +3830,29 @@ var saturatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3642
3830
|
const output = ctx.createGain();
|
|
3643
3831
|
const dryGain = ctx.createGain();
|
|
3644
3832
|
const wetGain = ctx.createGain();
|
|
3645
|
-
const
|
|
3646
|
-
|
|
3833
|
+
const preGain = ctx.createGain();
|
|
3834
|
+
preGain.gain.value = 1 / INPUT_SPAN2;
|
|
3835
|
+
const shaper = createShaperNode(ctx, saturationCurve(module.drive));
|
|
3836
|
+
const dryTrim = ctx.createGain();
|
|
3837
|
+
dryTrim.gain.value = INPUT_SPAN2;
|
|
3647
3838
|
const warmthFilter = ctx.createBiquadFilter();
|
|
3648
|
-
driveGain.gain.value = 1 + module.drive * 4;
|
|
3649
|
-
waveshaper.curve = makeSaturationCurve(module.drive);
|
|
3650
|
-
waveshaper.oversample = "2x";
|
|
3651
3839
|
warmthFilter.type = "lowshelf";
|
|
3652
3840
|
warmthFilter.frequency.value = 300;
|
|
3653
3841
|
warmthFilter.gain.value = module.warmth * 6;
|
|
3654
3842
|
const _mix = createMix(ctx, dryGain, wetGain, module.mix, "linear");
|
|
3655
|
-
input.connect(
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
waveshaper.connect(warmthFilter);
|
|
3843
|
+
input.connect(preGain);
|
|
3844
|
+
preGain.connect(shaper);
|
|
3845
|
+
shaper.connect(warmthFilter, 0);
|
|
3659
3846
|
warmthFilter.connect(wetGain);
|
|
3847
|
+
shaper.connect(dryTrim, 1);
|
|
3848
|
+
dryTrim.connect(dryGain);
|
|
3660
3849
|
dryGain.connect(output);
|
|
3661
3850
|
wetGain.connect(output);
|
|
3662
|
-
return { input, output,
|
|
3851
|
+
return { input, output, preGain, shaper, dryTrim, warmthFilter, dryGain, wetGain, _mix };
|
|
3663
3852
|
},
|
|
3664
3853
|
updateParam(nodes, _m, param, value) {
|
|
3665
3854
|
if (param === "drive") {
|
|
3666
|
-
nodes.
|
|
3667
|
-
nodes.waveshaper.curve = makeSaturationCurve(value);
|
|
3855
|
+
nodes.shaper.port.postMessage({ curve: saturationCurve(value) });
|
|
3668
3856
|
} else if (param === "warmth") {
|
|
3669
3857
|
nodes.warmthFilter.gain.value = value * 6;
|
|
3670
3858
|
} else if (param === "mix") {
|
|
@@ -3674,7 +3862,11 @@ var saturatorDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3674
3862
|
});
|
|
3675
3863
|
|
|
3676
3864
|
// src/lib-runtime/generated/modules/saturator.wrapper.ts
|
|
3677
|
-
var Saturator = /* @__PURE__ */ defineModule(saturatorDescriptor
|
|
3865
|
+
var Saturator = /* @__PURE__ */ defineModule(saturatorDescriptor, {
|
|
3866
|
+
worklets: {
|
|
3867
|
+
"shaper": shaper_default
|
|
3868
|
+
}
|
|
3869
|
+
});
|
|
3678
3870
|
|
|
3679
3871
|
// src/lib/dsp/shimmerRegen.ts
|
|
3680
3872
|
var REGEN_HP_HZ = 300;
|
|
@@ -3684,13 +3876,13 @@ var SHIFTER_ENERGY = 0.75;
|
|
|
3684
3876
|
var REGEN_DELAY_S = 0.02;
|
|
3685
3877
|
var SHIFTER_SEEDS = [5370206, 739982445];
|
|
3686
3878
|
var UNISON_FLOOR = [
|
|
3687
|
-
[0.5, 0.
|
|
3688
|
-
[1, 0.
|
|
3689
|
-
[2, 0.
|
|
3690
|
-
[3, 0.
|
|
3691
|
-
[5, 0.
|
|
3692
|
-
[7, 0.
|
|
3693
|
-
[10, 0.
|
|
3879
|
+
[0.5, 0.58],
|
|
3880
|
+
[1, 0.67],
|
|
3881
|
+
[2, 0.73],
|
|
3882
|
+
[3, 0.77],
|
|
3883
|
+
[5, 0.79],
|
|
3884
|
+
[7, 0.77],
|
|
3885
|
+
[10, 0.72]
|
|
3694
3886
|
];
|
|
3695
3887
|
var UNISON_PITCH_SPAN = 0.75;
|
|
3696
3888
|
function unisonFloor(decay) {
|
|
@@ -3832,9 +4024,9 @@ function makeSoftLimitCurve(knee, drive) {
|
|
|
3832
4024
|
const k = 0.1 + knee * 0.9;
|
|
3833
4025
|
const driveMul = 1 + drive * 3;
|
|
3834
4026
|
for (let i = 0; i < samples; i++) {
|
|
3835
|
-
const x = (i * 2 / samples - 1) * driveMul;
|
|
3836
|
-
if (Math.abs(x) < k) {
|
|
3837
|
-
curve[i] = x;
|
|
4027
|
+
const x = (i * 2 / (samples - 1) - 1) * driveMul;
|
|
4028
|
+
if (Math.abs(x) < k || 1 - k < 1e-9) {
|
|
4029
|
+
curve[i] = Math.max(-1, Math.min(1, x));
|
|
3838
4030
|
} else {
|
|
3839
4031
|
const sign = x > 0 ? 1 : -1;
|
|
3840
4032
|
curve[i] = sign * (k + (1 - k) * Math.tanh((Math.abs(x) - k) / (1 - k)));
|
|
@@ -3855,25 +4047,28 @@ var softLimitDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3855
4047
|
createNodes(ctx, module) {
|
|
3856
4048
|
const input = ctx.createGain();
|
|
3857
4049
|
const output = ctx.createGain();
|
|
3858
|
-
const waveshaper = ctx.
|
|
4050
|
+
const waveshaper = createShaperNode(ctx, makeSoftLimitCurve(module.knee, module.drive), { dry: false });
|
|
3859
4051
|
const ceiling = ctx.createGain();
|
|
3860
|
-
waveshaper.curve = makeSoftLimitCurve(module.knee, module.drive);
|
|
3861
|
-
waveshaper.oversample = "2x";
|
|
3862
4052
|
ceiling.gain.value = Math.pow(10, module.ceiling / 20);
|
|
3863
4053
|
input.connect(waveshaper);
|
|
3864
|
-
waveshaper.connect(ceiling);
|
|
4054
|
+
waveshaper.connect(ceiling, 0);
|
|
3865
4055
|
ceiling.connect(output);
|
|
3866
4056
|
return { input, output, waveshaper, ceiling };
|
|
3867
4057
|
},
|
|
3868
4058
|
updateParam(nodes, m, param, value) {
|
|
3869
|
-
|
|
3870
|
-
|
|
4059
|
+
const port = nodes.waveshaper.port;
|
|
4060
|
+
if (param === "drive") port.postMessage({ curve: makeSoftLimitCurve(m.knee, value) });
|
|
4061
|
+
else if (param === "knee") port.postMessage({ curve: makeSoftLimitCurve(value, m.drive) });
|
|
3871
4062
|
else if (param === "ceiling") nodes.ceiling.gain.value = Math.pow(10, value / 20);
|
|
3872
4063
|
}
|
|
3873
4064
|
});
|
|
3874
4065
|
|
|
3875
4066
|
// src/lib-runtime/generated/modules/soft-limit.wrapper.ts
|
|
3876
|
-
var SoftLimiter = /* @__PURE__ */ defineModule(softLimitDescriptor
|
|
4067
|
+
var SoftLimiter = /* @__PURE__ */ defineModule(softLimitDescriptor, {
|
|
4068
|
+
worklets: {
|
|
4069
|
+
"shaper": shaper_default
|
|
4070
|
+
}
|
|
4071
|
+
});
|
|
3877
4072
|
|
|
3878
4073
|
// src/lib-runtime/generated/modules/spring-reverb.tsx
|
|
3879
4074
|
var params38 = {
|
|
@@ -3938,6 +4133,7 @@ var SpringReverb = /* @__PURE__ */ defineModule(springReverbDescriptor, {
|
|
|
3938
4133
|
// src/lib-runtime/generated/modules/stereo-spread.tsx
|
|
3939
4134
|
var params39 = {
|
|
3940
4135
|
spread: { unit: "factor", default: 0.7, min: 0, max: 1 },
|
|
4136
|
+
width: { node: "wetGain", field: "gain", unit: "factor", default: 1, min: 0, max: 2 },
|
|
3941
4137
|
center: { unit: "Hz", default: 800, min: 200, max: 2e3, scale: "log" }
|
|
3942
4138
|
};
|
|
3943
4139
|
var stereoSpreadDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
@@ -3953,12 +4149,11 @@ var stereoSpreadDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3953
4149
|
createNodes(ctx, module) {
|
|
3954
4150
|
const input = ctx.createGain();
|
|
3955
4151
|
const output = ctx.createGain();
|
|
3956
|
-
|
|
4152
|
+
input.connect(output);
|
|
3957
4153
|
const highpass = ctx.createBiquadFilter();
|
|
3958
|
-
lowpass.type = "lowpass";
|
|
3959
|
-
lowpass.frequency.value = module.center;
|
|
3960
4154
|
highpass.type = "highpass";
|
|
3961
4155
|
highpass.frequency.value = module.center;
|
|
4156
|
+
highpass.Q.value = -3.0102999566;
|
|
3962
4157
|
const panLeft = ctx.createStereoPanner();
|
|
3963
4158
|
const panRight = ctx.createStereoPanner();
|
|
3964
4159
|
const haasDelay = ctx.createDelay(0.02);
|
|
@@ -3967,8 +4162,6 @@ var stereoSpreadDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3967
4162
|
haasDelay.delayTime.value = module.spread * 5e-3;
|
|
3968
4163
|
const wetGain = ctx.createGain();
|
|
3969
4164
|
wetGain.gain.value = module.width;
|
|
3970
|
-
input.connect(lowpass);
|
|
3971
|
-
lowpass.connect(output);
|
|
3972
4165
|
input.connect(highpass);
|
|
3973
4166
|
highpass.connect(panLeft);
|
|
3974
4167
|
highpass.connect(haasDelay);
|
|
@@ -3976,7 +4169,7 @@ var stereoSpreadDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3976
4169
|
panLeft.connect(wetGain);
|
|
3977
4170
|
panRight.connect(wetGain);
|
|
3978
4171
|
wetGain.connect(output);
|
|
3979
|
-
return { input, output,
|
|
4172
|
+
return { input, output, highpass, panLeft, panRight, haasDelay, wetGain };
|
|
3980
4173
|
},
|
|
3981
4174
|
updateParam(nodes, _m, param, value) {
|
|
3982
4175
|
if (param === "spread") {
|
|
@@ -3986,7 +4179,6 @@ var stereoSpreadDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
3986
4179
|
} else if (param === "width") {
|
|
3987
4180
|
nodes.wetGain.gain.value = value;
|
|
3988
4181
|
} else if (param === "center") {
|
|
3989
|
-
nodes.lowpass.frequency.value = value;
|
|
3990
4182
|
nodes.highpass.frequency.value = value;
|
|
3991
4183
|
}
|
|
3992
4184
|
}
|
|
@@ -4483,12 +4675,13 @@ var Vco = /* @__PURE__ */ defineModule(oscillatorDescriptor, {
|
|
|
4483
4675
|
});
|
|
4484
4676
|
|
|
4485
4677
|
// src/lib-runtime/generated/modules/wah.tsx
|
|
4678
|
+
var DEPTH_ST = 18;
|
|
4486
4679
|
var params48 = {
|
|
4487
4680
|
note: { node: "_cutoffVoct", field: "transpose", unit: "note", default: 79, min: 55, max: 95 },
|
|
4488
4681
|
// Resonance drives both the filter Q and a separate makeup gain — a split, so it stays set-only.
|
|
4489
4682
|
resonance: { unit: "factor", default: 8, min: 1, max: 20, scale: "log" },
|
|
4490
4683
|
rate: { node: "lfo", field: "frequency", unit: "Hz", default: 1, min: 0.1, max: 10, scale: "log" },
|
|
4491
|
-
// Depth is stored 0-1 but scaled by
|
|
4684
|
+
// Depth is stored 0-1 but scaled by DEPTH_ST semitones onto lfoGain.gain — a conversion, so set-only.
|
|
4492
4685
|
depth: { unit: "factor", default: 0.6, min: 0, max: 1 }
|
|
4493
4686
|
};
|
|
4494
4687
|
var wahDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
@@ -4522,7 +4715,7 @@ var wahDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
4522
4715
|
_cutoffVoct.connect(filter.frequency);
|
|
4523
4716
|
lfo.type = "sine";
|
|
4524
4717
|
lfo.frequency.value = module.rate;
|
|
4525
|
-
lfoGain.gain.value = module.depth *
|
|
4718
|
+
lfoGain.gain.value = module.depth * DEPTH_ST;
|
|
4526
4719
|
lfo.connect(lfoGain);
|
|
4527
4720
|
lfoGain.connect(_cutoffVoct);
|
|
4528
4721
|
lfo.start();
|
|
@@ -4541,7 +4734,7 @@ var wahDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
4541
4734
|
} else if (param === "rate") {
|
|
4542
4735
|
nodes.lfo.frequency.value = value;
|
|
4543
4736
|
} else if (param === "depth") {
|
|
4544
|
-
nodes.lfoGain.gain.value = value *
|
|
4737
|
+
nodes.lfoGain.gain.value = value * DEPTH_ST;
|
|
4545
4738
|
}
|
|
4546
4739
|
},
|
|
4547
4740
|
dispose(nodes) {
|
|
@@ -4599,20 +4792,18 @@ var wavefolderDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
4599
4792
|
const output = ctx.createGain();
|
|
4600
4793
|
const dryGain = ctx.createGain();
|
|
4601
4794
|
const wetGain = ctx.createGain();
|
|
4602
|
-
const waveshaper = ctx.
|
|
4603
|
-
waveshaper.curve = makeWavefoldCurve(module.folds, module.symmetry);
|
|
4604
|
-
waveshaper.oversample = "4x";
|
|
4795
|
+
const waveshaper = createShaperNode(ctx, makeWavefoldCurve(module.folds, module.symmetry));
|
|
4605
4796
|
const _mix = createMix(ctx, dryGain, wetGain, module.mix, "linear");
|
|
4606
|
-
input.connect(dryGain);
|
|
4607
4797
|
input.connect(waveshaper);
|
|
4608
|
-
waveshaper.connect(
|
|
4798
|
+
waveshaper.connect(dryGain, 1);
|
|
4799
|
+
waveshaper.connect(wetGain, 0);
|
|
4609
4800
|
dryGain.connect(output);
|
|
4610
4801
|
wetGain.connect(output);
|
|
4611
4802
|
return { input, output, waveshaper, dryGain, wetGain, _mix };
|
|
4612
4803
|
},
|
|
4613
4804
|
updateParam(nodes, module, param, value) {
|
|
4614
4805
|
if (param === "folds" || param === "symmetry") {
|
|
4615
|
-
nodes.waveshaper.curve
|
|
4806
|
+
nodes.waveshaper.port.postMessage({ curve: makeWavefoldCurve(module.folds, module.symmetry) });
|
|
4616
4807
|
} else if (param === "mix") {
|
|
4617
4808
|
nodes._mix.offset.value = value;
|
|
4618
4809
|
}
|
|
@@ -4620,7 +4811,11 @@ var wavefolderDescriptor = /* @__PURE__ */ defineDescriptor({
|
|
|
4620
4811
|
});
|
|
4621
4812
|
|
|
4622
4813
|
// src/lib-runtime/generated/modules/wavefolder.wrapper.ts
|
|
4623
|
-
var Wavefolder = /* @__PURE__ */ defineModule(wavefolderDescriptor
|
|
4814
|
+
var Wavefolder = /* @__PURE__ */ defineModule(wavefolderDescriptor, {
|
|
4815
|
+
worklets: {
|
|
4816
|
+
"shaper": shaper_default
|
|
4817
|
+
}
|
|
4818
|
+
});
|
|
4624
4819
|
export {
|
|
4625
4820
|
AcidFilter,
|
|
4626
4821
|
AutoPan,
|