@audiofab-io/fv1-core 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/blocks/ATL_DEVELOPER_REFERENCE.md +156 -156
  2. package/blocks/control/constant.atl +36 -36
  3. package/blocks/control/entropy_lfo.atl +74 -74
  4. package/blocks/control/envelope.atl +120 -120
  5. package/blocks/control/invert.atl +33 -33
  6. package/blocks/control/pot.atl +149 -149
  7. package/blocks/control/power.atl +76 -76
  8. package/blocks/control/ramp_lfo.atl +122 -122
  9. package/blocks/control/scale_offset.atl +84 -84
  10. package/blocks/control/sincos_lfo.atl +126 -126
  11. package/blocks/control/smoother.atl +48 -48
  12. package/blocks/control/tremolizer.atl +54 -54
  13. package/blocks/effects/delay/micro_stutter.atl +77 -77
  14. package/blocks/effects/delay/mn3011.atl +280 -280
  15. package/blocks/effects/delay/simple_delay.atl +96 -96
  16. package/blocks/effects/delay/triple_tap_delay.atl +176 -176
  17. package/blocks/effects/lo-fi/bit_mangler.atl +74 -74
  18. package/blocks/effects/lo-fi/chiptune.atl +311 -311
  19. package/blocks/effects/lo-fi/tape_degrade.atl +181 -181
  20. package/blocks/effects/modulation/chorus.atl +141 -141
  21. package/blocks/effects/modulation/chorus_4voice.atl +188 -188
  22. package/blocks/effects/modulation/flanger.atl +184 -184
  23. package/blocks/effects/modulation/harmonic_trem.atl +129 -129
  24. package/blocks/effects/modulation/phaser.atl +299 -299
  25. package/blocks/effects/pitch/octave_up_down.atl +80 -80
  26. package/blocks/effects/pitch/pitch_offset.atl +149 -149
  27. package/blocks/effects/pitch/pitch_offset_dual.atl +197 -197
  28. package/blocks/effects/pitch/pitch_shift.atl +115 -115
  29. package/blocks/effects/pitch/sub_octave.atl +100 -100
  30. package/blocks/effects/reverb/ducking_reverb.atl +145 -145
  31. package/blocks/effects/reverb/min_reverb.atl +132 -132
  32. package/blocks/effects/reverb/plate_reverb.atl +344 -344
  33. package/blocks/effects/reverb/room_reverb.atl +293 -293
  34. package/blocks/effects/reverb/smear.atl +90 -90
  35. package/blocks/effects/reverb/spring_reverb.atl +353 -353
  36. package/blocks/filter/1p_high_pass.atl +62 -62
  37. package/blocks/filter/1p_low_pass.atl +58 -58
  38. package/blocks/filter/auto_wah.atl +207 -207
  39. package/blocks/filter/bbd_loss.atl +79 -79
  40. package/blocks/filter/shelving_high_pass.atl +76 -76
  41. package/blocks/filter/shelving_low_pass.atl +76 -76
  42. package/blocks/filter/svf_2p.atl +116 -116
  43. package/blocks/gain_mix/crossfade.atl +93 -93
  44. package/blocks/gain_mix/crossfade2.atl +86 -86
  45. package/blocks/gain_mix/crossfade3.atl +71 -71
  46. package/blocks/gain_mix/gainboost.atl +54 -54
  47. package/blocks/gain_mix/mixer2.atl +76 -76
  48. package/blocks/gain_mix/mixer3.atl +109 -109
  49. package/blocks/gain_mix/mixer4.atl +151 -151
  50. package/blocks/gain_mix/volume.atl +50 -50
  51. package/blocks/io/adc.atl +53 -53
  52. package/blocks/io/dac.atl +61 -61
  53. package/blocks/other/stickynote.atl +24 -24
  54. package/blocks/other/tone_gen_adjustable.atl +137 -137
  55. package/blocks/other/tone_gen_fixed.atl +109 -109
  56. package/dist/blockDiagram/builtinBlocks.js +107 -107
  57. package/dist/blockDiagram/builtinBlocks.js.map +1 -1
  58. package/dist/simulator/FV1Simulator.d.ts +12 -0
  59. package/dist/simulator/FV1Simulator.d.ts.map +1 -1
  60. package/dist/simulator/FV1Simulator.js +47 -1
  61. package/dist/simulator/FV1Simulator.js.map +1 -1
  62. package/package.json +1 -1
@@ -1,197 +1,197 @@
1
- ---
2
- {
3
- "type": "effects.pitch.pitch_offset_dual",
4
- "name": "Dual Pitch Offset (Hilbert)",
5
- "category": "Effects",
6
- "subcategory": "Pitch",
7
- "description": "Two independent bipolar frequency offsets mixed to a mono output.",
8
- "color": "#fcba03",
9
- "inputs": [
10
- {
11
- "id": "in",
12
- "name": "Audio Input",
13
- "type": "audio",
14
- "required": true
15
- },
16
- {
17
- "id": "shift1_ctrl",
18
- "name": "Shift 1 CV",
19
- "type": "control",
20
- "required": false,
21
- "parameter": "shiftValue1"
22
- },
23
- {
24
- "id": "shift2_ctrl",
25
- "name": "Shift 2 CV",
26
- "type": "control",
27
- "required": false,
28
- "parameter": "shiftValue2"
29
- }
30
- ],
31
- "outputs": [
32
- {
33
- "id": "out",
34
- "name": "Output",
35
- "type": "audio"
36
- }
37
- ],
38
- "parameters": [
39
- {
40
- "id": "shiftRange",
41
- "name": "Shift Range (Hz)",
42
- "type": "number",
43
- "default": 600,
44
- "min": 1,
45
- "max": 2000,
46
- "conversion": "HZ_TO_HILBERT_SHIFT",
47
- "description": "Total frequency range for both controls."
48
- },
49
- {
50
- "id": "shiftValue1",
51
- "name": "Shift 1",
52
- "type": "number",
53
- "default": 0.5,
54
- "min": 0.0,
55
- "max": 1.0,
56
- "step": 0.01,
57
- "description": "Bipolar control for shift 1."
58
- },
59
- {
60
- "id": "shiftValue2",
61
- "name": "Shift 2",
62
- "type": "number",
63
- "default": 0.5,
64
- "min": 0.0,
65
- "max": 1.0,
66
- "step": 0.01,
67
- "description": "Bipolar control for shift 2."
68
- }
69
- ],
70
- "registers": [
71
- "sigs",
72
- "sigc",
73
- "lpf",
74
- "hpf",
75
- "sigfil",
76
- "sinosc1",
77
- "cososc1",
78
- "sinosc2",
79
- "cososc2",
80
- "temp1",
81
- "temp2",
82
- "shift1_amt",
83
- "shift2_amt",
84
- "potfil1",
85
- "potfil2"
86
- ],
87
- "memories": [
88
- { "id": "ap1", "size": 2 },
89
- { "id": "ap2", "size": 2 },
90
- { "id": "ap3", "size": 2 },
91
- { "id": "ap4", "size": 2 },
92
- { "id": "ap5", "size": 2 },
93
- { "id": "ap6", "size": 2 }
94
- ]
95
- }
96
- ---
97
- @section header
98
-
99
- @section init
100
- ; Initialize oscillators (cosine = 1.0)
101
- skp run, done_init
102
- or $7fffff
103
- wrax ${reg.cososc1}, 1.0
104
- wrax ${reg.cososc2}, 0.0
105
- done_init:
106
-
107
- @section main
108
- ; 1. Process CVs and smoothing
109
- @cv shift1_ctrl
110
- rdfx ${reg.potfil1}, 0.001
111
- wrlx ${reg.potfil1}, -1.0
112
- ; Bipolar mapping: ACC = (0.5 - shift1) * range
113
- sof -1.0, 0.5
114
- sof ${shiftRange}, 0.0
115
- wrax ${reg.shift1_amt}, 0.0
116
-
117
- @cv shift2_ctrl
118
- rdfx ${reg.potfil2}, 0.001
119
- wrlx ${reg.potfil2}, -1.0
120
- ; Bipolar mapping: ACC = (0.5 - shift2) * range
121
- sof -1.0, 0.5
122
- sof ${shiftRange}, 0.0
123
- wrax ${reg.shift2_amt}, 0.0
124
-
125
- ; 2. Audio input filtering
126
- rdax ${input.in}, 1.0
127
- rdfx ${reg.hpf}, 0.04
128
- wrhx ${reg.hpf}, -1.0
129
- rdfx ${reg.lpf}, 0.4
130
- wrlx ${reg.lpf}, -1.0
131
- wrax ${reg.sigfil}, 0.0039
132
-
133
- ; 3. Hilbert phase shifter (Shared)
134
- ; Sine path
135
- rda ${mem.ap1} + 1, 0.995 ; 44Hz
136
- wrap ${mem.ap1}, -0.995
137
- rda ${mem.ap2} + 1, 0.937 ; 488Hz
138
- wrap ${mem.ap2}, -0.937
139
- rda ${mem.ap3} + 1, 0.61 ; 3531Hz
140
- wrap ${mem.ap3}, -0.61
141
- wrax ${reg.sigs}, 0.0
142
-
143
- ; Cosine path
144
- rdax ${reg.sigfil}, 0.0039
145
- rda ${mem.ap4} + 1, 0.978 ; 178Hz
146
- wrap ${mem.ap4}, -0.978
147
- rda ${mem.ap5} + 1, 0.84 ; 1289Hz
148
- wrap ${mem.ap5}, -0.84
149
- rda ${mem.ap6} + 1, 0.0
150
- wrap ${mem.ap6}, 0.0
151
- wrax ${reg.sigc}, 0.0
152
-
153
- ; 4. Oscillator 1 update
154
- rdax ${reg.cososc1}, 1.0
155
- mulx ${reg.shift1_amt}
156
- rdax ${reg.sinosc1}, 1.0
157
- wrax ${reg.sinosc1}, -1.0
158
- mulx ${reg.shift1_amt}
159
- rdax ${reg.cososc1}, 1.0
160
- wrax ${reg.cososc1}, 0.0
161
-
162
- ; 5. Pitch shift 1 calculation
163
- rdax ${reg.sigc}, -2.0
164
- mulx ${reg.cososc1}
165
- wrax ${reg.temp1}, 0.0
166
- rdax ${reg.sigs}, -2.0
167
- mulx ${reg.sinosc1}
168
- rdax ${reg.temp1}, 1.0
169
- wrax ${reg.temp1}, 0.0
170
-
171
- ; 6. Oscillator 2 update
172
- rdax ${reg.cososc2}, 1.0
173
- mulx ${reg.shift2_amt}
174
- rdax ${reg.sinosc2}, 1.0
175
- wrax ${reg.sinosc2}, -1.0
176
- mulx ${reg.shift2_amt}
177
- rdax ${reg.cososc2}, 1.0
178
- wrax ${reg.cososc2}, 0.0
179
-
180
- ; 7. Pitch shift 2 calculation
181
- rdax ${reg.sigc}, -2.0
182
- mulx ${reg.cososc2}
183
- wrax ${reg.temp2}, 0.0
184
- rdax ${reg.sigs}, -2.0
185
- mulx ${reg.sinosc2}
186
- rdax ${reg.temp2}, 1.0
187
-
188
- ; 8. Sum results and scale up
189
- rdax ${reg.temp1}, 0.5 ; Mix
190
- sof -2.0, 0.0
191
- sof -2.0, 0.0
192
- sof -2.0, 0.0
193
- sof -2.0, 0.0
194
- sof -2.0, 0.0
195
- sof -2.0, 0.0
196
- sof -2.0, 0.0
197
- wrax ${output.out}, 0.0
1
+ ---
2
+ {
3
+ "type": "effects.pitch.pitch_offset_dual",
4
+ "name": "Dual Pitch Offset (Hilbert)",
5
+ "category": "Effects",
6
+ "subcategory": "Pitch",
7
+ "description": "Two independent bipolar frequency offsets mixed to a mono output.",
8
+ "color": "#fcba03",
9
+ "inputs": [
10
+ {
11
+ "id": "in",
12
+ "name": "Audio Input",
13
+ "type": "audio",
14
+ "required": true
15
+ },
16
+ {
17
+ "id": "shift1_ctrl",
18
+ "name": "Shift 1 CV",
19
+ "type": "control",
20
+ "required": false,
21
+ "parameter": "shiftValue1"
22
+ },
23
+ {
24
+ "id": "shift2_ctrl",
25
+ "name": "Shift 2 CV",
26
+ "type": "control",
27
+ "required": false,
28
+ "parameter": "shiftValue2"
29
+ }
30
+ ],
31
+ "outputs": [
32
+ {
33
+ "id": "out",
34
+ "name": "Output",
35
+ "type": "audio"
36
+ }
37
+ ],
38
+ "parameters": [
39
+ {
40
+ "id": "shiftRange",
41
+ "name": "Shift Range (Hz)",
42
+ "type": "number",
43
+ "default": 600,
44
+ "min": 1,
45
+ "max": 2000,
46
+ "conversion": "HZ_TO_HILBERT_SHIFT",
47
+ "description": "Total frequency range for both controls."
48
+ },
49
+ {
50
+ "id": "shiftValue1",
51
+ "name": "Shift 1",
52
+ "type": "number",
53
+ "default": 0.5,
54
+ "min": 0.0,
55
+ "max": 1.0,
56
+ "step": 0.01,
57
+ "description": "Bipolar control for shift 1."
58
+ },
59
+ {
60
+ "id": "shiftValue2",
61
+ "name": "Shift 2",
62
+ "type": "number",
63
+ "default": 0.5,
64
+ "min": 0.0,
65
+ "max": 1.0,
66
+ "step": 0.01,
67
+ "description": "Bipolar control for shift 2."
68
+ }
69
+ ],
70
+ "registers": [
71
+ "sigs",
72
+ "sigc",
73
+ "lpf",
74
+ "hpf",
75
+ "sigfil",
76
+ "sinosc1",
77
+ "cososc1",
78
+ "sinosc2",
79
+ "cososc2",
80
+ "temp1",
81
+ "temp2",
82
+ "shift1_amt",
83
+ "shift2_amt",
84
+ "potfil1",
85
+ "potfil2"
86
+ ],
87
+ "memories": [
88
+ { "id": "ap1", "size": 2 },
89
+ { "id": "ap2", "size": 2 },
90
+ { "id": "ap3", "size": 2 },
91
+ { "id": "ap4", "size": 2 },
92
+ { "id": "ap5", "size": 2 },
93
+ { "id": "ap6", "size": 2 }
94
+ ]
95
+ }
96
+ ---
97
+ @section header
98
+
99
+ @section init
100
+ ; Initialize oscillators (cosine = 1.0)
101
+ skp run, done_init
102
+ or $7fffff
103
+ wrax ${reg.cososc1}, 1.0
104
+ wrax ${reg.cososc2}, 0.0
105
+ done_init:
106
+
107
+ @section main
108
+ ; 1. Process CVs and smoothing
109
+ @cv shift1_ctrl
110
+ rdfx ${reg.potfil1}, 0.001
111
+ wrlx ${reg.potfil1}, -1.0
112
+ ; Bipolar mapping: ACC = (0.5 - shift1) * range
113
+ sof -1.0, 0.5
114
+ sof ${shiftRange}, 0.0
115
+ wrax ${reg.shift1_amt}, 0.0
116
+
117
+ @cv shift2_ctrl
118
+ rdfx ${reg.potfil2}, 0.001
119
+ wrlx ${reg.potfil2}, -1.0
120
+ ; Bipolar mapping: ACC = (0.5 - shift2) * range
121
+ sof -1.0, 0.5
122
+ sof ${shiftRange}, 0.0
123
+ wrax ${reg.shift2_amt}, 0.0
124
+
125
+ ; 2. Audio input filtering
126
+ rdax ${input.in}, 1.0
127
+ rdfx ${reg.hpf}, 0.04
128
+ wrhx ${reg.hpf}, -1.0
129
+ rdfx ${reg.lpf}, 0.4
130
+ wrlx ${reg.lpf}, -1.0
131
+ wrax ${reg.sigfil}, 0.0039
132
+
133
+ ; 3. Hilbert phase shifter (Shared)
134
+ ; Sine path
135
+ rda ${mem.ap1} + 1, 0.995 ; 44Hz
136
+ wrap ${mem.ap1}, -0.995
137
+ rda ${mem.ap2} + 1, 0.937 ; 488Hz
138
+ wrap ${mem.ap2}, -0.937
139
+ rda ${mem.ap3} + 1, 0.61 ; 3531Hz
140
+ wrap ${mem.ap3}, -0.61
141
+ wrax ${reg.sigs}, 0.0
142
+
143
+ ; Cosine path
144
+ rdax ${reg.sigfil}, 0.0039
145
+ rda ${mem.ap4} + 1, 0.978 ; 178Hz
146
+ wrap ${mem.ap4}, -0.978
147
+ rda ${mem.ap5} + 1, 0.84 ; 1289Hz
148
+ wrap ${mem.ap5}, -0.84
149
+ rda ${mem.ap6} + 1, 0.0
150
+ wrap ${mem.ap6}, 0.0
151
+ wrax ${reg.sigc}, 0.0
152
+
153
+ ; 4. Oscillator 1 update
154
+ rdax ${reg.cososc1}, 1.0
155
+ mulx ${reg.shift1_amt}
156
+ rdax ${reg.sinosc1}, 1.0
157
+ wrax ${reg.sinosc1}, -1.0
158
+ mulx ${reg.shift1_amt}
159
+ rdax ${reg.cososc1}, 1.0
160
+ wrax ${reg.cososc1}, 0.0
161
+
162
+ ; 5. Pitch shift 1 calculation
163
+ rdax ${reg.sigc}, -2.0
164
+ mulx ${reg.cososc1}
165
+ wrax ${reg.temp1}, 0.0
166
+ rdax ${reg.sigs}, -2.0
167
+ mulx ${reg.sinosc1}
168
+ rdax ${reg.temp1}, 1.0
169
+ wrax ${reg.temp1}, 0.0
170
+
171
+ ; 6. Oscillator 2 update
172
+ rdax ${reg.cososc2}, 1.0
173
+ mulx ${reg.shift2_amt}
174
+ rdax ${reg.sinosc2}, 1.0
175
+ wrax ${reg.sinosc2}, -1.0
176
+ mulx ${reg.shift2_amt}
177
+ rdax ${reg.cososc2}, 1.0
178
+ wrax ${reg.cososc2}, 0.0
179
+
180
+ ; 7. Pitch shift 2 calculation
181
+ rdax ${reg.sigc}, -2.0
182
+ mulx ${reg.cososc2}
183
+ wrax ${reg.temp2}, 0.0
184
+ rdax ${reg.sigs}, -2.0
185
+ mulx ${reg.sinosc2}
186
+ rdax ${reg.temp2}, 1.0
187
+
188
+ ; 8. Sum results and scale up
189
+ rdax ${reg.temp1}, 0.5 ; Mix
190
+ sof -2.0, 0.0
191
+ sof -2.0, 0.0
192
+ sof -2.0, 0.0
193
+ sof -2.0, 0.0
194
+ sof -2.0, 0.0
195
+ sof -2.0, 0.0
196
+ sof -2.0, 0.0
197
+ wrax ${output.out}, 0.0
@@ -1,115 +1,115 @@
1
- ---
2
- {
3
- "type": "effects.pitch.pitch_shift",
4
- "name": "Pitch Shift",
5
- "category": "Effects",
6
- "subcategory": "Pitch",
7
- "description": "Adjustable pitch shifter using Ramp LFOs.",
8
- "color": "#fcba03",
9
- "width": 180,
10
- "inputs": [
11
- {
12
- "id": "in",
13
- "name": "Input",
14
- "type": "audio",
15
- "required": true
16
- },
17
- {
18
- "id": "pitch_ctrl",
19
- "name": "Pitch CV",
20
- "type": "control",
21
- "required": false,
22
- "parameter": "semitones"
23
- }
24
- ],
25
- "outputs": [
26
- {
27
- "id": "out",
28
- "name": "Output",
29
- "type": "audio"
30
- }
31
- ],
32
- "parameters": [
33
- {
34
- "id": "semitones",
35
- "name": "Pitch (Semitones)",
36
- "type": "number",
37
- "default": 12,
38
- "min": -24,
39
- "max": 24,
40
- "step": 0.1,
41
- "conversion": "SEMITONES_TO_RATE",
42
- "description": "Base pitch shift in semitones. If Pitch CV is connected, this acts as the maximum shift range."
43
- },
44
- {
45
- "id": "lfoWidth",
46
- "name": "Buffer Size",
47
- "type": "select",
48
- "default": 4096,
49
- "options": [
50
- { "label": "4096 (Smooth)", "value": 4096 },
51
- { "label": "2048", "value": 2048 },
52
- { "label": "1024", "value": 1024 },
53
- { "label": "512 (Lo-fi)", "value": 512 }
54
- ],
55
- "description": "Size of the pitch shift buffer. Larger values are smoother but add more latency."
56
- },
57
- {
58
- "id": "lfoSel",
59
- "name": "LFO Slot",
60
- "type": "select",
61
- "default": 0,
62
- "options": [
63
- { "label": "Ramp 0", "value": 0 },
64
- { "label": "Ramp 1", "value": 1 }
65
- ]
66
- }
67
- ],
68
- "memories": [
69
- {
70
- "id": "buffer",
71
- "size": "lfoWidth"
72
- },
73
- {
74
- "id": "temp",
75
- "size": 1
76
- }
77
- ],
78
- "registers": []
79
- }
80
- ---
81
- @section header
82
- @if lfoSel == 0
83
- @equals lfo RMP0
84
- @equals lfo_rate RMP0_RATE
85
- @else
86
- @equals lfo RMP1
87
- @equals lfo_rate RMP1_RATE
88
- @endif
89
-
90
- @section init
91
- ; Initialize Ramp LFO
92
- skp run, done_init
93
- wldr ${lfoSel}, ${semitones}, ${lfoWidth}
94
- done_init:
95
-
96
- @section main
97
- ; Write input to delay buffer
98
- rdax ${input.in}, 1.0
99
- wra ${mem.buffer}, 0.0
100
-
101
- ; Update pitch shift rate via CV
102
- @cv pitch_ctrl
103
- wrax ${lfo_rate}, 0.0
104
-
105
- ; Perform pitch shift (dual-tap for crossfading)
106
- cho rda, ${lfo}, REG | COMPC, ${mem.buffer}
107
- cho rda, ${lfo}, 0, ${mem.buffer} + 1
108
- wra ${mem.temp}, 0.0
109
-
110
- cho rda, ${lfo}, RPTR2 | COMPC, ${mem.buffer}
111
- cho rda, ${lfo}, RPTR2, ${mem.buffer} + 1
112
- cho sof, ${lfo}, NA | COMPC, 0.0
113
- cho rda, ${lfo}, NA, ${mem.temp}
114
-
115
- wrax ${output.out}, 0.0
1
+ ---
2
+ {
3
+ "type": "effects.pitch.pitch_shift",
4
+ "name": "Pitch Shift",
5
+ "category": "Effects",
6
+ "subcategory": "Pitch",
7
+ "description": "Adjustable pitch shifter using Ramp LFOs.",
8
+ "color": "#fcba03",
9
+ "width": 180,
10
+ "inputs": [
11
+ {
12
+ "id": "in",
13
+ "name": "Input",
14
+ "type": "audio",
15
+ "required": true
16
+ },
17
+ {
18
+ "id": "pitch_ctrl",
19
+ "name": "Pitch CV",
20
+ "type": "control",
21
+ "required": false,
22
+ "parameter": "semitones"
23
+ }
24
+ ],
25
+ "outputs": [
26
+ {
27
+ "id": "out",
28
+ "name": "Output",
29
+ "type": "audio"
30
+ }
31
+ ],
32
+ "parameters": [
33
+ {
34
+ "id": "semitones",
35
+ "name": "Pitch (Semitones)",
36
+ "type": "number",
37
+ "default": 12,
38
+ "min": -24,
39
+ "max": 24,
40
+ "step": 0.1,
41
+ "conversion": "SEMITONES_TO_RATE",
42
+ "description": "Base pitch shift in semitones. If Pitch CV is connected, this acts as the maximum shift range."
43
+ },
44
+ {
45
+ "id": "lfoWidth",
46
+ "name": "Buffer Size",
47
+ "type": "select",
48
+ "default": 4096,
49
+ "options": [
50
+ { "label": "4096 (Smooth)", "value": 4096 },
51
+ { "label": "2048", "value": 2048 },
52
+ { "label": "1024", "value": 1024 },
53
+ { "label": "512 (Lo-fi)", "value": 512 }
54
+ ],
55
+ "description": "Size of the pitch shift buffer. Larger values are smoother but add more latency."
56
+ },
57
+ {
58
+ "id": "lfoSel",
59
+ "name": "LFO Slot",
60
+ "type": "select",
61
+ "default": 0,
62
+ "options": [
63
+ { "label": "Ramp 0", "value": 0 },
64
+ { "label": "Ramp 1", "value": 1 }
65
+ ]
66
+ }
67
+ ],
68
+ "memories": [
69
+ {
70
+ "id": "buffer",
71
+ "size": "lfoWidth"
72
+ },
73
+ {
74
+ "id": "temp",
75
+ "size": 1
76
+ }
77
+ ],
78
+ "registers": []
79
+ }
80
+ ---
81
+ @section header
82
+ @if lfoSel == 0
83
+ @equals lfo RMP0
84
+ @equals lfo_rate RMP0_RATE
85
+ @else
86
+ @equals lfo RMP1
87
+ @equals lfo_rate RMP1_RATE
88
+ @endif
89
+
90
+ @section init
91
+ ; Initialize Ramp LFO
92
+ skp run, done_init
93
+ wldr ${lfoSel}, ${semitones}, ${lfoWidth}
94
+ done_init:
95
+
96
+ @section main
97
+ ; Write input to delay buffer
98
+ rdax ${input.in}, 1.0
99
+ wra ${mem.buffer}, 0.0
100
+
101
+ ; Update pitch shift rate via CV
102
+ @cv pitch_ctrl
103
+ wrax ${lfo_rate}, 0.0
104
+
105
+ ; Perform pitch shift (dual-tap for crossfading)
106
+ cho rda, ${lfo}, REG | COMPC, ${mem.buffer}
107
+ cho rda, ${lfo}, 0, ${mem.buffer} + 1
108
+ wra ${mem.temp}, 0.0
109
+
110
+ cho rda, ${lfo}, RPTR2 | COMPC, ${mem.buffer}
111
+ cho rda, ${lfo}, RPTR2, ${mem.buffer} + 1
112
+ cho sof, ${lfo}, NA | COMPC, 0.0
113
+ cho rda, ${lfo}, NA, ${mem.temp}
114
+
115
+ wrax ${output.out}, 0.0