@audiofab-io/fv1-core 0.6.0 → 0.6.1
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/blocks/ATL_DEVELOPER_REFERENCE.md +156 -156
- package/blocks/control/constant.atl +36 -36
- package/blocks/control/entropy_lfo.atl +74 -74
- package/blocks/control/envelope.atl +120 -120
- package/blocks/control/invert.atl +33 -33
- package/blocks/control/pot.atl +149 -149
- package/blocks/control/power.atl +76 -76
- package/blocks/control/ramp_lfo.atl +122 -122
- package/blocks/control/scale_offset.atl +84 -84
- package/blocks/control/sincos_lfo.atl +126 -126
- package/blocks/control/smoother.atl +48 -48
- package/blocks/control/tremolizer.atl +54 -54
- package/blocks/effects/delay/micro_stutter.atl +77 -77
- package/blocks/effects/delay/mn3011.atl +280 -280
- package/blocks/effects/delay/simple_delay.atl +96 -96
- package/blocks/effects/delay/triple_tap_delay.atl +176 -176
- package/blocks/effects/lo-fi/bit_mangler.atl +74 -74
- package/blocks/effects/lo-fi/chiptune.atl +311 -311
- package/blocks/effects/lo-fi/tape_degrade.atl +181 -181
- package/blocks/effects/modulation/chorus.atl +141 -141
- package/blocks/effects/modulation/chorus_4voice.atl +188 -188
- package/blocks/effects/modulation/flanger.atl +184 -184
- package/blocks/effects/modulation/harmonic_trem.atl +129 -129
- package/blocks/effects/modulation/phaser.atl +299 -299
- package/blocks/effects/pitch/octave_up_down.atl +80 -80
- package/blocks/effects/pitch/pitch_offset.atl +149 -149
- package/blocks/effects/pitch/pitch_offset_dual.atl +197 -197
- package/blocks/effects/pitch/pitch_shift.atl +115 -115
- package/blocks/effects/pitch/sub_octave.atl +100 -100
- package/blocks/effects/reverb/ducking_reverb.atl +145 -145
- package/blocks/effects/reverb/min_reverb.atl +132 -132
- package/blocks/effects/reverb/plate_reverb.atl +344 -344
- package/blocks/effects/reverb/room_reverb.atl +293 -293
- package/blocks/effects/reverb/smear.atl +90 -90
- package/blocks/effects/reverb/spring_reverb.atl +353 -353
- package/blocks/filter/1p_high_pass.atl +62 -62
- package/blocks/filter/1p_low_pass.atl +58 -58
- package/blocks/filter/auto_wah.atl +207 -207
- package/blocks/filter/bbd_loss.atl +79 -79
- package/blocks/filter/shelving_high_pass.atl +76 -76
- package/blocks/filter/shelving_low_pass.atl +76 -76
- package/blocks/filter/svf_2p.atl +116 -116
- package/blocks/gain_mix/crossfade.atl +93 -93
- package/blocks/gain_mix/crossfade2.atl +86 -86
- package/blocks/gain_mix/crossfade3.atl +71 -71
- package/blocks/gain_mix/gainboost.atl +54 -54
- package/blocks/gain_mix/mixer2.atl +76 -76
- package/blocks/gain_mix/mixer3.atl +109 -109
- package/blocks/gain_mix/mixer4.atl +151 -151
- package/blocks/gain_mix/volume.atl +50 -50
- package/blocks/io/adc.atl +53 -53
- package/blocks/io/dac.atl +61 -61
- package/blocks/other/stickynote.atl +24 -24
- package/blocks/other/tone_gen_adjustable.atl +137 -137
- package/blocks/other/tone_gen_fixed.atl +109 -109
- package/dist/blockDiagram/builtinBlocks.js +107 -107
- package/dist/blockDiagram/builtinBlocks.js.map +1 -1
- package/dist/blockDiagram/compiler/BlockTemplate.d.ts.map +1 -1
- package/dist/blockDiagram/compiler/BlockTemplate.js +18 -0
- package/dist/blockDiagram/compiler/BlockTemplate.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,311 +1,311 @@
|
|
|
1
|
-
---
|
|
2
|
-
{
|
|
3
|
-
"type": "effects.novelty.chiptune",
|
|
4
|
-
"name": "Chip Tune",
|
|
5
|
-
"category": "Effects",
|
|
6
|
-
"subcategory": "Lo-Fi",
|
|
7
|
-
"description": "Commodore 64 SID chip emulator: Transforms your guitar into 8-bit chiptune glory with bit crushing, square-wave shaping, ring modulation, white noise, and the legendary SID resonant filter.",
|
|
8
|
-
"color": "#4466BB",
|
|
9
|
-
"width": 180,
|
|
10
|
-
"inputs": [
|
|
11
|
-
{
|
|
12
|
-
"id": "in",
|
|
13
|
-
"name": "Input",
|
|
14
|
-
"type": "audio",
|
|
15
|
-
"required": true
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"id": "crushCV",
|
|
19
|
-
"name": "Crush",
|
|
20
|
-
"type": "control",
|
|
21
|
-
"required": false,
|
|
22
|
-
"parameter": "crush"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"id": "squareCV",
|
|
26
|
-
"name": "Square",
|
|
27
|
-
"type": "control",
|
|
28
|
-
"required": false,
|
|
29
|
-
"parameter": "square"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"id": "cutoffCV",
|
|
33
|
-
"name": "Cutoff",
|
|
34
|
-
"type": "control",
|
|
35
|
-
"required": false,
|
|
36
|
-
"parameter": "cutoff"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"id": "resoCV",
|
|
40
|
-
"name": "Resonance",
|
|
41
|
-
"type": "control",
|
|
42
|
-
"required": false,
|
|
43
|
-
"parameter": "resonance"
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
"outputs": [
|
|
47
|
-
{
|
|
48
|
-
"id": "out",
|
|
49
|
-
"name": "Output",
|
|
50
|
-
"type": "audio"
|
|
51
|
-
}
|
|
52
|
-
],
|
|
53
|
-
"parameters": [
|
|
54
|
-
{
|
|
55
|
-
"id": "crush",
|
|
56
|
-
"name": "Crush Depth",
|
|
57
|
-
"type": "number",
|
|
58
|
-
"default": 0.2,
|
|
59
|
-
"min": 0.005,
|
|
60
|
-
"max": 0.25,
|
|
61
|
-
"step": 0.005,
|
|
62
|
-
"description": "Sample-rate reduction intensity. Higher = more lo-fi 8-bit crunch."
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
"id": "square",
|
|
66
|
-
"name": "Square Drive",
|
|
67
|
-
"type": "number",
|
|
68
|
-
"default": 0.5,
|
|
69
|
-
"min": 0.0,
|
|
70
|
-
"max": 1.99,
|
|
71
|
-
"step": 0.01,
|
|
72
|
-
"description": "Blend from clean (0) to hard-clipped square pulse waveform (max)."
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
"id": "ring_freq",
|
|
76
|
-
"name": "Ring Mod",
|
|
77
|
-
"type": "number",
|
|
78
|
-
"default": 0.0,
|
|
79
|
-
"min": 0.0,
|
|
80
|
-
"max": 1.0,
|
|
81
|
-
"step": 0.01,
|
|
82
|
-
"description": "Ring modulator frequency. 0 = off. Adds metallic SID harmonics."
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"id": "noise",
|
|
86
|
-
"name": "Noise Level",
|
|
87
|
-
"type": "number",
|
|
88
|
-
"default": 0.5,
|
|
89
|
-
"min": 0.0,
|
|
90
|
-
"max": 1.0,
|
|
91
|
-
"step": 0.01,
|
|
92
|
-
"description": "White noise generator level. Classic SID noise channel for hi-hats, snares, and static textures."
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
"id": "cutoff",
|
|
96
|
-
"name": "Filter Cutoff",
|
|
97
|
-
"type": "number",
|
|
98
|
-
"default": 3000,
|
|
99
|
-
"min": 60,
|
|
100
|
-
"max": 6000,
|
|
101
|
-
"step": 10,
|
|
102
|
-
"conversion": "SVFFREQ",
|
|
103
|
-
"description": "SID-style resonant low-pass filter cutoff frequency."
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
"id": "resonance",
|
|
107
|
-
"name": "Filter Resonance",
|
|
108
|
-
"type": "number",
|
|
109
|
-
"default": 4.0,
|
|
110
|
-
"min": 0.5,
|
|
111
|
-
"max": 20.0,
|
|
112
|
-
"step": 0.1,
|
|
113
|
-
"conversion": "SVF_DAMP",
|
|
114
|
-
"description": "Filter Q. Crank it for that classic SID filter sweep character."
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
"id": "mix",
|
|
118
|
-
"name": "Dry/Wet Mix",
|
|
119
|
-
"type": "number",
|
|
120
|
-
"default": 1.0,
|
|
121
|
-
"min": 0.0,
|
|
122
|
-
"max": 1.0,
|
|
123
|
-
"step": 0.01,
|
|
124
|
-
"description": "Blend between dry and SID-processed signal."
|
|
125
|
-
}
|
|
126
|
-
],
|
|
127
|
-
"registers": [
|
|
128
|
-
"counter",
|
|
129
|
-
"held",
|
|
130
|
-
"squared",
|
|
131
|
-
"ring_sin",
|
|
132
|
-
"ring_cos",
|
|
133
|
-
"f_ring",
|
|
134
|
-
"ringmod",
|
|
135
|
-
"noise_reg",
|
|
136
|
-
"noise_dc",
|
|
137
|
-
"lp_state",
|
|
138
|
-
"bp_state",
|
|
139
|
-
"damp_reg",
|
|
140
|
-
"dry",
|
|
141
|
-
"wet",
|
|
142
|
-
"mix_val"
|
|
143
|
-
]
|
|
144
|
-
}
|
|
145
|
-
---
|
|
146
|
-
@section header
|
|
147
|
-
equ damp_target (${param.resonance})
|
|
148
|
-
|
|
149
|
-
@section init
|
|
150
|
-
; Seed the ring mod oscillator (cos=0.5, sin=0)
|
|
151
|
-
; Without this, the magic circle stays at zero forever!
|
|
152
|
-
sof 0.0, 0.5
|
|
153
|
-
wrax ${reg.ring_cos}, 0.0
|
|
154
|
-
|
|
155
|
-
; Seed the noise LFSR with a non-zero, non-one starting value
|
|
156
|
-
sof 0.0, 0.3
|
|
157
|
-
wrax ${reg.noise_reg}, 0.0
|
|
158
|
-
|
|
159
|
-
@section main
|
|
160
|
-
@if pinConnected(in)
|
|
161
|
-
|
|
162
|
-
; ======================================================
|
|
163
|
-
; Stage 0: Save dry signal for mix
|
|
164
|
-
; ======================================================
|
|
165
|
-
rdax ${input.in}, 1.0
|
|
166
|
-
wrax ${reg.dry}, 0.0
|
|
167
|
-
|
|
168
|
-
; ======================================================
|
|
169
|
-
; Stage 1: Sample-Rate Reduction (SID S&H Bit Crush)
|
|
170
|
-
; ======================================================
|
|
171
|
-
skp run, ${local.SKIP_INIT}
|
|
172
|
-
rdax ${input.in}, 1.0
|
|
173
|
-
wrax ${reg.held}, 0.0
|
|
174
|
-
${local.SKIP_INIT}:
|
|
175
|
-
|
|
176
|
-
; Counter increment: inverted crush so higher = more crushed
|
|
177
|
-
; step = 0.255 - crush_value (smaller step = slower S&H = more lo-fi)
|
|
178
|
-
rdax ${reg.counter}, 1.0
|
|
179
|
-
wrax ${reg.counter}, 0.0
|
|
180
|
-
@cv crushCV ; ACC = crush depth (0.005..0.25)
|
|
181
|
-
sof -1.0, 0.255 ; ACC = 0.255 - crush = step size
|
|
182
|
-
rdax ${reg.counter}, 1.0 ; ACC = counter + step
|
|
183
|
-
wrax ${reg.counter}, 1.0
|
|
184
|
-
|
|
185
|
-
sof 1.0, -0.99
|
|
186
|
-
skp neg, ${local.SKIP_SAMPLE}
|
|
187
|
-
|
|
188
|
-
clr
|
|
189
|
-
rdax ${input.in}, 1.0
|
|
190
|
-
wrax ${reg.held}, 0.0
|
|
191
|
-
sof 0.0, 0.0
|
|
192
|
-
wrax ${reg.counter}, 0.0
|
|
193
|
-
|
|
194
|
-
${local.SKIP_SAMPLE}:
|
|
195
|
-
|
|
196
|
-
; ======================================================
|
|
197
|
-
; Stage 2: Square Wave Shaping (SID Pulse Oscillator)
|
|
198
|
-
; ======================================================
|
|
199
|
-
clr
|
|
200
|
-
rdax ${reg.held}, 1.0
|
|
201
|
-
sof 1.99, 0.0
|
|
202
|
-
sof -1.99, 0.0
|
|
203
|
-
sof -1.99, 0.0
|
|
204
|
-
sof 0.5, 0.0
|
|
205
|
-
wrax ${reg.squared}, 0.0
|
|
206
|
-
|
|
207
|
-
; Crossfade: out = held + (squared - held) * squareDrive
|
|
208
|
-
rdax ${reg.squared}, 1.0
|
|
209
|
-
rdax ${reg.held}, -1.0
|
|
210
|
-
wrax ${reg.mix_val}, 0.0 ; Save (squared - held), clear ACC
|
|
211
|
-
@cv squareCV ; ACC = square drive value
|
|
212
|
-
mulx ${reg.mix_val} ; ACC = (squared - held) * drive
|
|
213
|
-
rdax ${reg.held}, 1.0 ; ACC = held + (squared - held) * drive
|
|
214
|
-
wrax ${reg.squared}, 0.0
|
|
215
|
-
|
|
216
|
-
; ======================================================
|
|
217
|
-
; Stage 3: Ring Modulation (SID Ring Mod)
|
|
218
|
-
; ======================================================
|
|
219
|
-
sof 0.0, ${param.ring_freq}
|
|
220
|
-
sof 0.15, 0.0
|
|
221
|
-
wrax ${reg.f_ring}, 0.0
|
|
222
|
-
|
|
223
|
-
; Magic circle sine oscillator (seeded in init!)
|
|
224
|
-
rdax ${reg.ring_sin}, -1.0
|
|
225
|
-
mulx ${reg.f_ring}
|
|
226
|
-
rdax ${reg.ring_cos}, 1.0
|
|
227
|
-
wrax ${reg.ring_cos}, 1.0
|
|
228
|
-
mulx ${reg.f_ring}
|
|
229
|
-
rdax ${reg.ring_sin}, 1.0
|
|
230
|
-
wrax ${reg.ring_sin}, 0.0
|
|
231
|
-
|
|
232
|
-
; Ring mod = squared * carrier
|
|
233
|
-
rdax ${reg.squared}, 1.0
|
|
234
|
-
mulx ${reg.ring_sin}
|
|
235
|
-
sof 1.99, 0.0
|
|
236
|
-
wrax ${reg.ringmod}, 0.0
|
|
237
|
-
|
|
238
|
-
; Crossfade by ring_freq: 0 = all squared, 1 = all ring
|
|
239
|
-
sof 0.0, ${param.ring_freq}
|
|
240
|
-
wrax ${reg.mix_val}, 0.0
|
|
241
|
-
rdax ${reg.ringmod}, 1.0
|
|
242
|
-
rdax ${reg.squared}, -1.0
|
|
243
|
-
mulx ${reg.mix_val}
|
|
244
|
-
rdax ${reg.squared}, 1.0
|
|
245
|
-
wrax ${reg.wet}, 0.0
|
|
246
|
-
|
|
247
|
-
; ======================================================
|
|
248
|
-
; Stage 3.5: SID Noise Channel (Tent Map + DC Blocker)
|
|
249
|
-
; ======================================================
|
|
250
|
-
; Tent map: x_next ≈ 1 - 2|x| (chaotic noise source)
|
|
251
|
-
; FV-1 can't represent exact coefficients 2/1, so the raw
|
|
252
|
-
; output has a slight positive mean. A DC-blocking LP filter
|
|
253
|
-
; tracks and removes it for guaranteed zero-mean noise.
|
|
254
|
-
rdax ${reg.noise_reg}, 1.0 ; ACC = x
|
|
255
|
-
absa ; ACC = |x|
|
|
256
|
-
sof -1.99, 0.999 ; ACC ≈ 1 - 2|x| — tent map
|
|
257
|
-
wrax ${reg.noise_reg}, 0.0 ; Save x_next, ACC = 0
|
|
258
|
-
|
|
259
|
-
; DC blocker: track running average with ultra-slow LP
|
|
260
|
-
rdax ${reg.noise_dc}, 1.0 ; ACC = old DC estimate
|
|
261
|
-
rdfx ${reg.noise_reg}, 0.001 ; ACC = DC_old*0.999 + noise*0.001
|
|
262
|
-
wrax ${reg.noise_dc}, -1.0 ; Save new DC estimate, ACC = -DC
|
|
263
|
-
rdax ${reg.noise_reg}, 1.0 ; ACC = noise - DC = zero-mean noise
|
|
264
|
-
|
|
265
|
-
; Scale by noise level and add to wet signal
|
|
266
|
-
; Noise needs ~12dB pre-boost because the SID filter downstream
|
|
267
|
-
; heavily attenuates high-frequency content where most noise energy lives
|
|
268
|
-
sof 1.99, 0.0
|
|
269
|
-
sof 1.99, 0.0
|
|
270
|
-
sof ${param.noise}, 0.0
|
|
271
|
-
rdax ${reg.wet}, 1.0
|
|
272
|
-
wrax ${reg.wet}, 0.0
|
|
273
|
-
|
|
274
|
-
; ======================================================
|
|
275
|
-
; Stage 4: SID Filter (Resonant SVF Low-Pass)
|
|
276
|
-
; ======================================================
|
|
277
|
-
; Load damping coefficient (resonance CV or fixed parameter)
|
|
278
|
-
@cv resoCV
|
|
279
|
-
wrax ${reg.damp_reg}, 0.0
|
|
280
|
-
|
|
281
|
-
; Load cutoff coefficient
|
|
282
|
-
@cv cutoffCV
|
|
283
|
-
wrax ${reg.mix_val}, 0.0
|
|
284
|
-
|
|
285
|
-
; Chamberlin SVF: HP → BP → LP
|
|
286
|
-
rdax ${reg.wet}, 1.0
|
|
287
|
-
rdax ${reg.lp_state}, -1.0
|
|
288
|
-
wrax ${reg.wet}, 0.0 ; Reuse wet as temp = (input - lp_old)
|
|
289
|
-
rdax ${reg.bp_state}, 1.0
|
|
290
|
-
mulx ${reg.damp_reg} ; ACC = bp_old * damp
|
|
291
|
-
rdax ${reg.wet}, -1.0 ; ACC = -(input - lp_old) + bp_old * damp = -(HP)
|
|
292
|
-
sof -1.0, 0.0 ; ACC = HP
|
|
293
|
-
mulx ${reg.mix_val} ; ACC = F * HP
|
|
294
|
-
rdax ${reg.bp_state}, 1.0 ; ACC = bp_old + F * HP = bp_new
|
|
295
|
-
wrax ${reg.bp_state}, 1.0 ; Save bp, keep in ACC
|
|
296
|
-
mulx ${reg.mix_val} ; ACC = F * bp_new
|
|
297
|
-
rdax ${reg.lp_state}, 1.0 ; ACC = lp_old + F * bp_new = lp_new
|
|
298
|
-
wrax ${reg.lp_state}, 0.0
|
|
299
|
-
|
|
300
|
-
; ======================================================
|
|
301
|
-
; Stage 5: Dry/Wet Mix
|
|
302
|
-
; ======================================================
|
|
303
|
-
rdax ${reg.lp_state}, 1.0
|
|
304
|
-
rdax ${reg.dry}, -1.0
|
|
305
|
-
sof ${param.mix}, 0.0
|
|
306
|
-
rdax ${reg.dry}, 1.0
|
|
307
|
-
wrax ${output.out}, 0.0
|
|
308
|
-
|
|
309
|
-
@else
|
|
310
|
-
; Bypassed
|
|
311
|
-
@endif
|
|
1
|
+
---
|
|
2
|
+
{
|
|
3
|
+
"type": "effects.novelty.chiptune",
|
|
4
|
+
"name": "Chip Tune",
|
|
5
|
+
"category": "Effects",
|
|
6
|
+
"subcategory": "Lo-Fi",
|
|
7
|
+
"description": "Commodore 64 SID chip emulator: Transforms your guitar into 8-bit chiptune glory with bit crushing, square-wave shaping, ring modulation, white noise, and the legendary SID resonant filter.",
|
|
8
|
+
"color": "#4466BB",
|
|
9
|
+
"width": 180,
|
|
10
|
+
"inputs": [
|
|
11
|
+
{
|
|
12
|
+
"id": "in",
|
|
13
|
+
"name": "Input",
|
|
14
|
+
"type": "audio",
|
|
15
|
+
"required": true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "crushCV",
|
|
19
|
+
"name": "Crush",
|
|
20
|
+
"type": "control",
|
|
21
|
+
"required": false,
|
|
22
|
+
"parameter": "crush"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "squareCV",
|
|
26
|
+
"name": "Square",
|
|
27
|
+
"type": "control",
|
|
28
|
+
"required": false,
|
|
29
|
+
"parameter": "square"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "cutoffCV",
|
|
33
|
+
"name": "Cutoff",
|
|
34
|
+
"type": "control",
|
|
35
|
+
"required": false,
|
|
36
|
+
"parameter": "cutoff"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "resoCV",
|
|
40
|
+
"name": "Resonance",
|
|
41
|
+
"type": "control",
|
|
42
|
+
"required": false,
|
|
43
|
+
"parameter": "resonance"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"outputs": [
|
|
47
|
+
{
|
|
48
|
+
"id": "out",
|
|
49
|
+
"name": "Output",
|
|
50
|
+
"type": "audio"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"parameters": [
|
|
54
|
+
{
|
|
55
|
+
"id": "crush",
|
|
56
|
+
"name": "Crush Depth",
|
|
57
|
+
"type": "number",
|
|
58
|
+
"default": 0.2,
|
|
59
|
+
"min": 0.005,
|
|
60
|
+
"max": 0.25,
|
|
61
|
+
"step": 0.005,
|
|
62
|
+
"description": "Sample-rate reduction intensity. Higher = more lo-fi 8-bit crunch."
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "square",
|
|
66
|
+
"name": "Square Drive",
|
|
67
|
+
"type": "number",
|
|
68
|
+
"default": 0.5,
|
|
69
|
+
"min": 0.0,
|
|
70
|
+
"max": 1.99,
|
|
71
|
+
"step": 0.01,
|
|
72
|
+
"description": "Blend from clean (0) to hard-clipped square pulse waveform (max)."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "ring_freq",
|
|
76
|
+
"name": "Ring Mod",
|
|
77
|
+
"type": "number",
|
|
78
|
+
"default": 0.0,
|
|
79
|
+
"min": 0.0,
|
|
80
|
+
"max": 1.0,
|
|
81
|
+
"step": 0.01,
|
|
82
|
+
"description": "Ring modulator frequency. 0 = off. Adds metallic SID harmonics."
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "noise",
|
|
86
|
+
"name": "Noise Level",
|
|
87
|
+
"type": "number",
|
|
88
|
+
"default": 0.5,
|
|
89
|
+
"min": 0.0,
|
|
90
|
+
"max": 1.0,
|
|
91
|
+
"step": 0.01,
|
|
92
|
+
"description": "White noise generator level. Classic SID noise channel for hi-hats, snares, and static textures."
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "cutoff",
|
|
96
|
+
"name": "Filter Cutoff",
|
|
97
|
+
"type": "number",
|
|
98
|
+
"default": 3000,
|
|
99
|
+
"min": 60,
|
|
100
|
+
"max": 6000,
|
|
101
|
+
"step": 10,
|
|
102
|
+
"conversion": "SVFFREQ",
|
|
103
|
+
"description": "SID-style resonant low-pass filter cutoff frequency."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "resonance",
|
|
107
|
+
"name": "Filter Resonance",
|
|
108
|
+
"type": "number",
|
|
109
|
+
"default": 4.0,
|
|
110
|
+
"min": 0.5,
|
|
111
|
+
"max": 20.0,
|
|
112
|
+
"step": 0.1,
|
|
113
|
+
"conversion": "SVF_DAMP",
|
|
114
|
+
"description": "Filter Q. Crank it for that classic SID filter sweep character."
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "mix",
|
|
118
|
+
"name": "Dry/Wet Mix",
|
|
119
|
+
"type": "number",
|
|
120
|
+
"default": 1.0,
|
|
121
|
+
"min": 0.0,
|
|
122
|
+
"max": 1.0,
|
|
123
|
+
"step": 0.01,
|
|
124
|
+
"description": "Blend between dry and SID-processed signal."
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"registers": [
|
|
128
|
+
"counter",
|
|
129
|
+
"held",
|
|
130
|
+
"squared",
|
|
131
|
+
"ring_sin",
|
|
132
|
+
"ring_cos",
|
|
133
|
+
"f_ring",
|
|
134
|
+
"ringmod",
|
|
135
|
+
"noise_reg",
|
|
136
|
+
"noise_dc",
|
|
137
|
+
"lp_state",
|
|
138
|
+
"bp_state",
|
|
139
|
+
"damp_reg",
|
|
140
|
+
"dry",
|
|
141
|
+
"wet",
|
|
142
|
+
"mix_val"
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
---
|
|
146
|
+
@section header
|
|
147
|
+
equ damp_target (${param.resonance})
|
|
148
|
+
|
|
149
|
+
@section init
|
|
150
|
+
; Seed the ring mod oscillator (cos=0.5, sin=0)
|
|
151
|
+
; Without this, the magic circle stays at zero forever!
|
|
152
|
+
sof 0.0, 0.5
|
|
153
|
+
wrax ${reg.ring_cos}, 0.0
|
|
154
|
+
|
|
155
|
+
; Seed the noise LFSR with a non-zero, non-one starting value
|
|
156
|
+
sof 0.0, 0.3
|
|
157
|
+
wrax ${reg.noise_reg}, 0.0
|
|
158
|
+
|
|
159
|
+
@section main
|
|
160
|
+
@if pinConnected(in)
|
|
161
|
+
|
|
162
|
+
; ======================================================
|
|
163
|
+
; Stage 0: Save dry signal for mix
|
|
164
|
+
; ======================================================
|
|
165
|
+
rdax ${input.in}, 1.0
|
|
166
|
+
wrax ${reg.dry}, 0.0
|
|
167
|
+
|
|
168
|
+
; ======================================================
|
|
169
|
+
; Stage 1: Sample-Rate Reduction (SID S&H Bit Crush)
|
|
170
|
+
; ======================================================
|
|
171
|
+
skp run, ${local.SKIP_INIT}
|
|
172
|
+
rdax ${input.in}, 1.0
|
|
173
|
+
wrax ${reg.held}, 0.0
|
|
174
|
+
${local.SKIP_INIT}:
|
|
175
|
+
|
|
176
|
+
; Counter increment: inverted crush so higher = more crushed
|
|
177
|
+
; step = 0.255 - crush_value (smaller step = slower S&H = more lo-fi)
|
|
178
|
+
rdax ${reg.counter}, 1.0
|
|
179
|
+
wrax ${reg.counter}, 0.0
|
|
180
|
+
@cv crushCV ; ACC = crush depth (0.005..0.25)
|
|
181
|
+
sof -1.0, 0.255 ; ACC = 0.255 - crush = step size
|
|
182
|
+
rdax ${reg.counter}, 1.0 ; ACC = counter + step
|
|
183
|
+
wrax ${reg.counter}, 1.0
|
|
184
|
+
|
|
185
|
+
sof 1.0, -0.99
|
|
186
|
+
skp neg, ${local.SKIP_SAMPLE}
|
|
187
|
+
|
|
188
|
+
clr
|
|
189
|
+
rdax ${input.in}, 1.0
|
|
190
|
+
wrax ${reg.held}, 0.0
|
|
191
|
+
sof 0.0, 0.0
|
|
192
|
+
wrax ${reg.counter}, 0.0
|
|
193
|
+
|
|
194
|
+
${local.SKIP_SAMPLE}:
|
|
195
|
+
|
|
196
|
+
; ======================================================
|
|
197
|
+
; Stage 2: Square Wave Shaping (SID Pulse Oscillator)
|
|
198
|
+
; ======================================================
|
|
199
|
+
clr
|
|
200
|
+
rdax ${reg.held}, 1.0
|
|
201
|
+
sof 1.99, 0.0
|
|
202
|
+
sof -1.99, 0.0
|
|
203
|
+
sof -1.99, 0.0
|
|
204
|
+
sof 0.5, 0.0
|
|
205
|
+
wrax ${reg.squared}, 0.0
|
|
206
|
+
|
|
207
|
+
; Crossfade: out = held + (squared - held) * squareDrive
|
|
208
|
+
rdax ${reg.squared}, 1.0
|
|
209
|
+
rdax ${reg.held}, -1.0
|
|
210
|
+
wrax ${reg.mix_val}, 0.0 ; Save (squared - held), clear ACC
|
|
211
|
+
@cv squareCV ; ACC = square drive value
|
|
212
|
+
mulx ${reg.mix_val} ; ACC = (squared - held) * drive
|
|
213
|
+
rdax ${reg.held}, 1.0 ; ACC = held + (squared - held) * drive
|
|
214
|
+
wrax ${reg.squared}, 0.0
|
|
215
|
+
|
|
216
|
+
; ======================================================
|
|
217
|
+
; Stage 3: Ring Modulation (SID Ring Mod)
|
|
218
|
+
; ======================================================
|
|
219
|
+
sof 0.0, ${param.ring_freq}
|
|
220
|
+
sof 0.15, 0.0
|
|
221
|
+
wrax ${reg.f_ring}, 0.0
|
|
222
|
+
|
|
223
|
+
; Magic circle sine oscillator (seeded in init!)
|
|
224
|
+
rdax ${reg.ring_sin}, -1.0
|
|
225
|
+
mulx ${reg.f_ring}
|
|
226
|
+
rdax ${reg.ring_cos}, 1.0
|
|
227
|
+
wrax ${reg.ring_cos}, 1.0
|
|
228
|
+
mulx ${reg.f_ring}
|
|
229
|
+
rdax ${reg.ring_sin}, 1.0
|
|
230
|
+
wrax ${reg.ring_sin}, 0.0
|
|
231
|
+
|
|
232
|
+
; Ring mod = squared * carrier
|
|
233
|
+
rdax ${reg.squared}, 1.0
|
|
234
|
+
mulx ${reg.ring_sin}
|
|
235
|
+
sof 1.99, 0.0
|
|
236
|
+
wrax ${reg.ringmod}, 0.0
|
|
237
|
+
|
|
238
|
+
; Crossfade by ring_freq: 0 = all squared, 1 = all ring
|
|
239
|
+
sof 0.0, ${param.ring_freq}
|
|
240
|
+
wrax ${reg.mix_val}, 0.0
|
|
241
|
+
rdax ${reg.ringmod}, 1.0
|
|
242
|
+
rdax ${reg.squared}, -1.0
|
|
243
|
+
mulx ${reg.mix_val}
|
|
244
|
+
rdax ${reg.squared}, 1.0
|
|
245
|
+
wrax ${reg.wet}, 0.0
|
|
246
|
+
|
|
247
|
+
; ======================================================
|
|
248
|
+
; Stage 3.5: SID Noise Channel (Tent Map + DC Blocker)
|
|
249
|
+
; ======================================================
|
|
250
|
+
; Tent map: x_next ≈ 1 - 2|x| (chaotic noise source)
|
|
251
|
+
; FV-1 can't represent exact coefficients 2/1, so the raw
|
|
252
|
+
; output has a slight positive mean. A DC-blocking LP filter
|
|
253
|
+
; tracks and removes it for guaranteed zero-mean noise.
|
|
254
|
+
rdax ${reg.noise_reg}, 1.0 ; ACC = x
|
|
255
|
+
absa ; ACC = |x|
|
|
256
|
+
sof -1.99, 0.999 ; ACC ≈ 1 - 2|x| — tent map
|
|
257
|
+
wrax ${reg.noise_reg}, 0.0 ; Save x_next, ACC = 0
|
|
258
|
+
|
|
259
|
+
; DC blocker: track running average with ultra-slow LP
|
|
260
|
+
rdax ${reg.noise_dc}, 1.0 ; ACC = old DC estimate
|
|
261
|
+
rdfx ${reg.noise_reg}, 0.001 ; ACC = DC_old*0.999 + noise*0.001
|
|
262
|
+
wrax ${reg.noise_dc}, -1.0 ; Save new DC estimate, ACC = -DC
|
|
263
|
+
rdax ${reg.noise_reg}, 1.0 ; ACC = noise - DC = zero-mean noise
|
|
264
|
+
|
|
265
|
+
; Scale by noise level and add to wet signal
|
|
266
|
+
; Noise needs ~12dB pre-boost because the SID filter downstream
|
|
267
|
+
; heavily attenuates high-frequency content where most noise energy lives
|
|
268
|
+
sof 1.99, 0.0
|
|
269
|
+
sof 1.99, 0.0
|
|
270
|
+
sof ${param.noise}, 0.0
|
|
271
|
+
rdax ${reg.wet}, 1.0
|
|
272
|
+
wrax ${reg.wet}, 0.0
|
|
273
|
+
|
|
274
|
+
; ======================================================
|
|
275
|
+
; Stage 4: SID Filter (Resonant SVF Low-Pass)
|
|
276
|
+
; ======================================================
|
|
277
|
+
; Load damping coefficient (resonance CV or fixed parameter)
|
|
278
|
+
@cv resoCV
|
|
279
|
+
wrax ${reg.damp_reg}, 0.0
|
|
280
|
+
|
|
281
|
+
; Load cutoff coefficient
|
|
282
|
+
@cv cutoffCV
|
|
283
|
+
wrax ${reg.mix_val}, 0.0
|
|
284
|
+
|
|
285
|
+
; Chamberlin SVF: HP → BP → LP
|
|
286
|
+
rdax ${reg.wet}, 1.0
|
|
287
|
+
rdax ${reg.lp_state}, -1.0
|
|
288
|
+
wrax ${reg.wet}, 0.0 ; Reuse wet as temp = (input - lp_old)
|
|
289
|
+
rdax ${reg.bp_state}, 1.0
|
|
290
|
+
mulx ${reg.damp_reg} ; ACC = bp_old * damp
|
|
291
|
+
rdax ${reg.wet}, -1.0 ; ACC = -(input - lp_old) + bp_old * damp = -(HP)
|
|
292
|
+
sof -1.0, 0.0 ; ACC = HP
|
|
293
|
+
mulx ${reg.mix_val} ; ACC = F * HP
|
|
294
|
+
rdax ${reg.bp_state}, 1.0 ; ACC = bp_old + F * HP = bp_new
|
|
295
|
+
wrax ${reg.bp_state}, 1.0 ; Save bp, keep in ACC
|
|
296
|
+
mulx ${reg.mix_val} ; ACC = F * bp_new
|
|
297
|
+
rdax ${reg.lp_state}, 1.0 ; ACC = lp_old + F * bp_new = lp_new
|
|
298
|
+
wrax ${reg.lp_state}, 0.0
|
|
299
|
+
|
|
300
|
+
; ======================================================
|
|
301
|
+
; Stage 5: Dry/Wet Mix
|
|
302
|
+
; ======================================================
|
|
303
|
+
rdax ${reg.lp_state}, 1.0
|
|
304
|
+
rdax ${reg.dry}, -1.0
|
|
305
|
+
sof ${param.mix}, 0.0
|
|
306
|
+
rdax ${reg.dry}, 1.0
|
|
307
|
+
wrax ${output.out}, 0.0
|
|
308
|
+
|
|
309
|
+
@else
|
|
310
|
+
; Bypassed
|
|
311
|
+
@endif
|