@audiofab-io/fv1-core 0.6.1 → 0.6.2
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/simulator/FV1Simulator.js +1 -1
- package/package.json +1 -1
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
---
|
|
2
|
-
{
|
|
3
|
-
"type": "fx.tape_degrade",
|
|
4
|
-
"name": "Tape Degrader",
|
|
5
|
-
"category": "Effects",
|
|
6
|
-
"subcategory": "Lo-Fi",
|
|
7
|
-
"description": "Simulates tape wow, flutter, and top-end age loss.",
|
|
8
|
-
"color": "#24F2F2",
|
|
9
|
-
"width": 180,
|
|
10
|
-
"inputs": [
|
|
11
|
-
{
|
|
12
|
-
"id": "in",
|
|
13
|
-
"name": "Input",
|
|
14
|
-
"type": "audio",
|
|
15
|
-
"required": true
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"id": "wow_rate_cv",
|
|
19
|
-
"name": "Wow Rate",
|
|
20
|
-
"type": "control",
|
|
21
|
-
"required": false,
|
|
22
|
-
"parameter": "wow_rate"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"id": "wow_depth_cv",
|
|
26
|
-
"name": "Wow Depth",
|
|
27
|
-
"type": "control",
|
|
28
|
-
"required": false,
|
|
29
|
-
"parameter": "wow_depth"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"id": "flutter_rate_cv",
|
|
33
|
-
"name": "Flutter Rate",
|
|
34
|
-
"type": "control",
|
|
35
|
-
"required": false,
|
|
36
|
-
"parameter": "flutter_rate"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"id": "flutter_depth_cv",
|
|
40
|
-
"name": "Flutter Depth",
|
|
41
|
-
"type": "control",
|
|
42
|
-
"required": false,
|
|
43
|
-
"parameter": "flutter_depth"
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
"outputs": [
|
|
47
|
-
{
|
|
48
|
-
"id": "out",
|
|
49
|
-
"name": "Output",
|
|
50
|
-
"type": "audio"
|
|
51
|
-
}
|
|
52
|
-
],
|
|
53
|
-
"parameters": [
|
|
54
|
-
{
|
|
55
|
-
"id": "wow_rate",
|
|
56
|
-
"name": "Wow Rate (Hz)",
|
|
57
|
-
"type": "number",
|
|
58
|
-
"default": 0.5,
|
|
59
|
-
"min": 0.1,
|
|
60
|
-
"max": 2.0,
|
|
61
|
-
"step": 0.01,
|
|
62
|
-
"conversion": "HZ_TO_LFO_RATE"
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
"id": "wow_depth",
|
|
66
|
-
"name": "Wow Depth (ms)",
|
|
67
|
-
"type": "number",
|
|
68
|
-
"default": 1.5,
|
|
69
|
-
"min": 0,
|
|
70
|
-
"max": 5.0,
|
|
71
|
-
"step": 0.1,
|
|
72
|
-
"conversion": "MS_TO_LFO_RANGE"
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
"id": "flutter_rate",
|
|
76
|
-
"name": "Flutter Rate (Hz)",
|
|
77
|
-
"type": "number",
|
|
78
|
-
"default": 12.0,
|
|
79
|
-
"min": 5.0,
|
|
80
|
-
"max": 20.0,
|
|
81
|
-
"step": 0.1,
|
|
82
|
-
"conversion": "HZ_TO_LFO_RATE"
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"id": "flutter_depth",
|
|
86
|
-
"name": "Flutter Depth (ms)",
|
|
87
|
-
"type": "number",
|
|
88
|
-
"default": 0.2,
|
|
89
|
-
"min": 0,
|
|
90
|
-
"max": 1.5,
|
|
91
|
-
"step": 0.01,
|
|
92
|
-
"conversion": "MS_TO_LFO_RANGE"
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
"id": "age",
|
|
96
|
-
"name": "Tape Age (Tone)",
|
|
97
|
-
"type": "number",
|
|
98
|
-
"default": 0.3,
|
|
99
|
-
"min": 0.01,
|
|
100
|
-
"max": 1.0,
|
|
101
|
-
"step": 0.01,
|
|
102
|
-
"description": "1.0 is bright, lower is darker (aged tape)."
|
|
103
|
-
}
|
|
104
|
-
],
|
|
105
|
-
"memories": [
|
|
106
|
-
{
|
|
107
|
-
"id": "tape_buffer",
|
|
108
|
-
"size": 4096
|
|
109
|
-
}
|
|
110
|
-
],
|
|
111
|
-
"registers": [
|
|
112
|
-
"wow_temp",
|
|
113
|
-
"lpf_lp"
|
|
114
|
-
]
|
|
115
|
-
}
|
|
116
|
-
---
|
|
117
|
-
@section init
|
|
118
|
-
skp run, init_tape
|
|
119
|
-
wlds SIN0, ${wow_rate}, ${wow_depth}
|
|
120
|
-
wlds SIN1, ${flutter_rate}, ${flutter_depth}
|
|
121
|
-
init_tape:
|
|
122
|
-
|
|
123
|
-
@section main
|
|
124
|
-
; CV Modulation for Wow/Flutter
|
|
125
|
-
; Since rates are HZ_TO_LFO_RATE, we must scale them manually
|
|
126
|
-
@if pinConnected(wow_rate_cv)
|
|
127
|
-
rdax ${input.wow_rate_cv}, ${wow_rate} / 511.0
|
|
128
|
-
wrax SIN0_RATE, 0.0
|
|
129
|
-
@endif
|
|
130
|
-
|
|
131
|
-
; Depths are MS_TO_LFO_RANGE which goes up to 32767. So scale / 32767.0
|
|
132
|
-
@if pinConnected(wow_depth_cv)
|
|
133
|
-
rdax ${input.wow_depth_cv}, ${wow_depth} / 32767.0
|
|
134
|
-
wrax SIN0_RANGE, 0.0
|
|
135
|
-
@endif
|
|
136
|
-
|
|
137
|
-
@if pinConnected(flutter_rate_cv)
|
|
138
|
-
rdax ${input.flutter_rate_cv}, ${flutter_rate} / 511.0
|
|
139
|
-
wrax SIN1_RATE, 0.0
|
|
140
|
-
@endif
|
|
141
|
-
|
|
142
|
-
@if pinConnected(flutter_depth_cv)
|
|
143
|
-
rdax ${input.flutter_depth_cv}, ${flutter_depth} / 32767.0
|
|
144
|
-
wrax SIN1_RANGE, 0.0
|
|
145
|
-
@endif
|
|
146
|
-
|
|
147
|
-
; Write to Tape
|
|
148
|
-
rdax ${input.in}, 1.0
|
|
149
|
-
wra ${mem.tape_buffer}, 0.0
|
|
150
|
-
|
|
151
|
-
; Read Wow Tape Head (SIN0)
|
|
152
|
-
@equals center ${mem.tape_buffer} + 2048
|
|
153
|
-
cho rda, SIN0, SIN | REG | COMPC, ${center}
|
|
154
|
-
cho rda, SIN0, SIN, ${center} + 1
|
|
155
|
-
|
|
156
|
-
; Modulate with Flutter (SIN1) off the same base, summing them creates composite warble
|
|
157
|
-
; Actually, FV-1 CHO adds to ACC! So we just do another CHO RDA but without REG tracking?
|
|
158
|
-
; To maintain unity volume, we shouldn't add audio signals, we should add address offsets.
|
|
159
|
-
; But we can't add address offsets in SpinASM dynamically easily.
|
|
160
|
-
; Instead, we just read from the buffer with Flutter and average the two reads!
|
|
161
|
-
; Multiply Wow read by 0.5
|
|
162
|
-
sof 0.5, 0.0
|
|
163
|
-
wrax ${reg.wow_temp}, 0.0 ; Hold Wow audio separately from LPF state
|
|
164
|
-
|
|
165
|
-
; Read Flutter Tape Head (SIN1)
|
|
166
|
-
cho rda, SIN1, SIN | REG | COMPC, ${center}
|
|
167
|
-
cho rda, SIN1, SIN, ${center} + 1
|
|
168
|
-
sof 0.5, 0.0
|
|
169
|
-
|
|
170
|
-
; Combine Wow and Flutter audio signals
|
|
171
|
-
rdax ${reg.wow_temp}, 1.0
|
|
172
|
-
|
|
173
|
-
; Tape Age Degradation (1-Pole Lowpass: L_new = L_old + Age * (I - L_old))
|
|
174
|
-
; ACC = composite warble (wow*0.5 + flutter*0.5)
|
|
175
|
-
rdax ${reg.lpf_lp}, -1.0 ; ACC = I - L_old
|
|
176
|
-
sof ${param.age}, 0.0 ; ACC = Age * (I - L_old)
|
|
177
|
-
rdax ${reg.lpf_lp}, 1.0 ; ACC = L_old + Age * (I - L_old) = L_new
|
|
178
|
-
wrax ${reg.lpf_lp}, 1.0 ; Save new state and keep L_new in ACC
|
|
179
|
-
|
|
180
|
-
; Export
|
|
181
|
-
wrax ${output.out}, 0.0
|
|
1
|
+
---
|
|
2
|
+
{
|
|
3
|
+
"type": "fx.tape_degrade",
|
|
4
|
+
"name": "Tape Degrader",
|
|
5
|
+
"category": "Effects",
|
|
6
|
+
"subcategory": "Lo-Fi",
|
|
7
|
+
"description": "Simulates tape wow, flutter, and top-end age loss.",
|
|
8
|
+
"color": "#24F2F2",
|
|
9
|
+
"width": 180,
|
|
10
|
+
"inputs": [
|
|
11
|
+
{
|
|
12
|
+
"id": "in",
|
|
13
|
+
"name": "Input",
|
|
14
|
+
"type": "audio",
|
|
15
|
+
"required": true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "wow_rate_cv",
|
|
19
|
+
"name": "Wow Rate",
|
|
20
|
+
"type": "control",
|
|
21
|
+
"required": false,
|
|
22
|
+
"parameter": "wow_rate"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "wow_depth_cv",
|
|
26
|
+
"name": "Wow Depth",
|
|
27
|
+
"type": "control",
|
|
28
|
+
"required": false,
|
|
29
|
+
"parameter": "wow_depth"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "flutter_rate_cv",
|
|
33
|
+
"name": "Flutter Rate",
|
|
34
|
+
"type": "control",
|
|
35
|
+
"required": false,
|
|
36
|
+
"parameter": "flutter_rate"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "flutter_depth_cv",
|
|
40
|
+
"name": "Flutter Depth",
|
|
41
|
+
"type": "control",
|
|
42
|
+
"required": false,
|
|
43
|
+
"parameter": "flutter_depth"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"outputs": [
|
|
47
|
+
{
|
|
48
|
+
"id": "out",
|
|
49
|
+
"name": "Output",
|
|
50
|
+
"type": "audio"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"parameters": [
|
|
54
|
+
{
|
|
55
|
+
"id": "wow_rate",
|
|
56
|
+
"name": "Wow Rate (Hz)",
|
|
57
|
+
"type": "number",
|
|
58
|
+
"default": 0.5,
|
|
59
|
+
"min": 0.1,
|
|
60
|
+
"max": 2.0,
|
|
61
|
+
"step": 0.01,
|
|
62
|
+
"conversion": "HZ_TO_LFO_RATE"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "wow_depth",
|
|
66
|
+
"name": "Wow Depth (ms)",
|
|
67
|
+
"type": "number",
|
|
68
|
+
"default": 1.5,
|
|
69
|
+
"min": 0,
|
|
70
|
+
"max": 5.0,
|
|
71
|
+
"step": 0.1,
|
|
72
|
+
"conversion": "MS_TO_LFO_RANGE"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "flutter_rate",
|
|
76
|
+
"name": "Flutter Rate (Hz)",
|
|
77
|
+
"type": "number",
|
|
78
|
+
"default": 12.0,
|
|
79
|
+
"min": 5.0,
|
|
80
|
+
"max": 20.0,
|
|
81
|
+
"step": 0.1,
|
|
82
|
+
"conversion": "HZ_TO_LFO_RATE"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "flutter_depth",
|
|
86
|
+
"name": "Flutter Depth (ms)",
|
|
87
|
+
"type": "number",
|
|
88
|
+
"default": 0.2,
|
|
89
|
+
"min": 0,
|
|
90
|
+
"max": 1.5,
|
|
91
|
+
"step": 0.01,
|
|
92
|
+
"conversion": "MS_TO_LFO_RANGE"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "age",
|
|
96
|
+
"name": "Tape Age (Tone)",
|
|
97
|
+
"type": "number",
|
|
98
|
+
"default": 0.3,
|
|
99
|
+
"min": 0.01,
|
|
100
|
+
"max": 1.0,
|
|
101
|
+
"step": 0.01,
|
|
102
|
+
"description": "1.0 is bright, lower is darker (aged tape)."
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"memories": [
|
|
106
|
+
{
|
|
107
|
+
"id": "tape_buffer",
|
|
108
|
+
"size": 4096
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"registers": [
|
|
112
|
+
"wow_temp",
|
|
113
|
+
"lpf_lp"
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
---
|
|
117
|
+
@section init
|
|
118
|
+
skp run, init_tape
|
|
119
|
+
wlds SIN0, ${wow_rate}, ${wow_depth}
|
|
120
|
+
wlds SIN1, ${flutter_rate}, ${flutter_depth}
|
|
121
|
+
init_tape:
|
|
122
|
+
|
|
123
|
+
@section main
|
|
124
|
+
; CV Modulation for Wow/Flutter
|
|
125
|
+
; Since rates are HZ_TO_LFO_RATE, we must scale them manually
|
|
126
|
+
@if pinConnected(wow_rate_cv)
|
|
127
|
+
rdax ${input.wow_rate_cv}, ${wow_rate} / 511.0
|
|
128
|
+
wrax SIN0_RATE, 0.0
|
|
129
|
+
@endif
|
|
130
|
+
|
|
131
|
+
; Depths are MS_TO_LFO_RANGE which goes up to 32767. So scale / 32767.0
|
|
132
|
+
@if pinConnected(wow_depth_cv)
|
|
133
|
+
rdax ${input.wow_depth_cv}, ${wow_depth} / 32767.0
|
|
134
|
+
wrax SIN0_RANGE, 0.0
|
|
135
|
+
@endif
|
|
136
|
+
|
|
137
|
+
@if pinConnected(flutter_rate_cv)
|
|
138
|
+
rdax ${input.flutter_rate_cv}, ${flutter_rate} / 511.0
|
|
139
|
+
wrax SIN1_RATE, 0.0
|
|
140
|
+
@endif
|
|
141
|
+
|
|
142
|
+
@if pinConnected(flutter_depth_cv)
|
|
143
|
+
rdax ${input.flutter_depth_cv}, ${flutter_depth} / 32767.0
|
|
144
|
+
wrax SIN1_RANGE, 0.0
|
|
145
|
+
@endif
|
|
146
|
+
|
|
147
|
+
; Write to Tape
|
|
148
|
+
rdax ${input.in}, 1.0
|
|
149
|
+
wra ${mem.tape_buffer}, 0.0
|
|
150
|
+
|
|
151
|
+
; Read Wow Tape Head (SIN0)
|
|
152
|
+
@equals center ${mem.tape_buffer} + 2048
|
|
153
|
+
cho rda, SIN0, SIN | REG | COMPC, ${center}
|
|
154
|
+
cho rda, SIN0, SIN, ${center} + 1
|
|
155
|
+
|
|
156
|
+
; Modulate with Flutter (SIN1) off the same base, summing them creates composite warble
|
|
157
|
+
; Actually, FV-1 CHO adds to ACC! So we just do another CHO RDA but without REG tracking?
|
|
158
|
+
; To maintain unity volume, we shouldn't add audio signals, we should add address offsets.
|
|
159
|
+
; But we can't add address offsets in SpinASM dynamically easily.
|
|
160
|
+
; Instead, we just read from the buffer with Flutter and average the two reads!
|
|
161
|
+
; Multiply Wow read by 0.5
|
|
162
|
+
sof 0.5, 0.0
|
|
163
|
+
wrax ${reg.wow_temp}, 0.0 ; Hold Wow audio separately from LPF state
|
|
164
|
+
|
|
165
|
+
; Read Flutter Tape Head (SIN1)
|
|
166
|
+
cho rda, SIN1, SIN | REG | COMPC, ${center}
|
|
167
|
+
cho rda, SIN1, SIN, ${center} + 1
|
|
168
|
+
sof 0.5, 0.0
|
|
169
|
+
|
|
170
|
+
; Combine Wow and Flutter audio signals
|
|
171
|
+
rdax ${reg.wow_temp}, 1.0
|
|
172
|
+
|
|
173
|
+
; Tape Age Degradation (1-Pole Lowpass: L_new = L_old + Age * (I - L_old))
|
|
174
|
+
; ACC = composite warble (wow*0.5 + flutter*0.5)
|
|
175
|
+
rdax ${reg.lpf_lp}, -1.0 ; ACC = I - L_old
|
|
176
|
+
sof ${param.age}, 0.0 ; ACC = Age * (I - L_old)
|
|
177
|
+
rdax ${reg.lpf_lp}, 1.0 ; ACC = L_old + Age * (I - L_old) = L_new
|
|
178
|
+
wrax ${reg.lpf_lp}, 1.0 ; Save new state and keep L_new in ACC
|
|
179
|
+
|
|
180
|
+
; Export
|
|
181
|
+
wrax ${output.out}, 0.0
|
|
@@ -1,141 +1,141 @@
|
|
|
1
|
-
---
|
|
2
|
-
{
|
|
3
|
-
"type": "fx.chorus",
|
|
4
|
-
"name": "Chorus",
|
|
5
|
-
"category": "Effects",
|
|
6
|
-
"subcategory": "Modulation",
|
|
7
|
-
"description": "Classic chorus with LFO-modulated delay",
|
|
8
|
-
"color": "#24f2f2",
|
|
9
|
-
"width": 180,
|
|
10
|
-
"inputs": [
|
|
11
|
-
{
|
|
12
|
-
"id": "in",
|
|
13
|
-
"name": "Input",
|
|
14
|
-
"type": "audio",
|
|
15
|
-
"required": true
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"id": "lfo_rate",
|
|
19
|
-
"name": "LFO Rate",
|
|
20
|
-
"type": "control",
|
|
21
|
-
"required": false
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"id": "lfo_width",
|
|
25
|
-
"name": "LFO Width",
|
|
26
|
-
"type": "control",
|
|
27
|
-
"required": false
|
|
28
|
-
}
|
|
29
|
-
],
|
|
30
|
-
"outputs": [
|
|
31
|
-
{
|
|
32
|
-
"id": "out",
|
|
33
|
-
"name": "Output",
|
|
34
|
-
"type": "audio"
|
|
35
|
-
}
|
|
36
|
-
],
|
|
37
|
-
"parameters": [
|
|
38
|
-
{
|
|
39
|
-
"id": "baseDelay",
|
|
40
|
-
"name": "Base Delay (ms)",
|
|
41
|
-
"type": "number",
|
|
42
|
-
"default": 15,
|
|
43
|
-
"min": 1,
|
|
44
|
-
"max": 50,
|
|
45
|
-
"conversion": "MS_TO_SAMPLES",
|
|
46
|
-
"description": "Base delay time (center of modulation) in ms.",
|
|
47
|
-
"step": 0.1
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"id": "rate",
|
|
51
|
-
"name": "LFO Rate (Hz)",
|
|
52
|
-
"type": "number",
|
|
53
|
-
"default": 1.0,
|
|
54
|
-
"min": 0.05,
|
|
55
|
-
"max": 10,
|
|
56
|
-
"conversion": "HZ_TO_LFO_RATE",
|
|
57
|
-
"description": "Frequency of the chorus modulation in Hz.",
|
|
58
|
-
"step": 0.01
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
"id": "width",
|
|
62
|
-
"name": "LFO Width (ms)",
|
|
63
|
-
"type": "number",
|
|
64
|
-
"default": 1,
|
|
65
|
-
"min": 0,
|
|
66
|
-
"max": 10,
|
|
67
|
-
"conversion": "MS_TO_LFO_RANGE",
|
|
68
|
-
"description": "The width of modulation in ms.",
|
|
69
|
-
"step": 0.1
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
"id": "lfoSel",
|
|
73
|
-
"name": "LFO Select",
|
|
74
|
-
"type": "select",
|
|
75
|
-
"default": 0,
|
|
76
|
-
"options": [
|
|
77
|
-
{
|
|
78
|
-
"value": 0,
|
|
79
|
-
"label": "LFO 0"
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"value": 1,
|
|
83
|
-
"label": "LFO 1"
|
|
84
|
-
}
|
|
85
|
-
]
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
"memories": [
|
|
89
|
-
{
|
|
90
|
-
"id": "delayl",
|
|
91
|
-
"size": "${baseDelay} * 2"
|
|
92
|
-
}
|
|
93
|
-
],
|
|
94
|
-
"registers": [
|
|
95
|
-
]
|
|
96
|
-
}
|
|
97
|
-
---
|
|
98
|
-
@if isequalto lfoSel 0
|
|
99
|
-
@equals lfoNum SIN0
|
|
100
|
-
@equals lfoRateReg SIN0_RATE
|
|
101
|
-
@equals lfoRange SIN0_RANGE
|
|
102
|
-
@else
|
|
103
|
-
@equals lfoNum SIN1
|
|
104
|
-
@equals lfoRateReg SIN1_RATE
|
|
105
|
-
@equals lfoRange SIN1_RANGE
|
|
106
|
-
@endif
|
|
107
|
-
|
|
108
|
-
@section init
|
|
109
|
-
; Initialize LFO
|
|
110
|
-
skp run, done_lfo
|
|
111
|
-
wlds ${lfoNum}, ${rate}, ${width}
|
|
112
|
-
done_lfo:
|
|
113
|
-
|
|
114
|
-
@section main
|
|
115
|
-
@multiplyDouble lfo_depth_delay width 0.5
|
|
116
|
-
@multiplyDouble delay_mem_size baseDelay 2.0
|
|
117
|
-
@assert lfo_depth_delay < delay_mem_size, "Maximum LFO depth exceeds delay memory bounds. Increase base delay or decrease LFO depth."
|
|
118
|
-
|
|
119
|
-
; Chorus
|
|
120
|
-
rdax ${input.in}, 1.0
|
|
121
|
-
wra ${mem.delayl}, 0.0
|
|
122
|
-
|
|
123
|
-
@if pinConnected(lfo_rate)
|
|
124
|
-
rdax ${input.lfo_rate}, ${param.rate.max} / 511.0
|
|
125
|
-
sof 1.0, ${param.rate.min} / 511.0
|
|
126
|
-
wrax ${lfoRateReg}, 0.0
|
|
127
|
-
@endif
|
|
128
|
-
|
|
129
|
-
@if pinConnected(lfo_width)
|
|
130
|
-
rdax ${input.lfo_width}, ${param.width.max} / 32767.0
|
|
131
|
-
sof 1.0, ${param.width.min} / 32767.0
|
|
132
|
-
wrax ${lfoRange}, 0.0
|
|
133
|
-
@endif
|
|
134
|
-
|
|
135
|
-
; Read modulated tap (wet signal)
|
|
136
|
-
; center offset from start of delay line
|
|
137
|
-
@equals center ${mem.delayl} + ${baseDelay}
|
|
138
|
-
cho rda, ${lfoNum}, SIN | REG | COMPC, ${center}
|
|
139
|
-
cho rda, ${lfoNum}, SIN, ${center} + 1
|
|
140
|
-
|
|
141
|
-
wrax ${output.out}, 0.0
|
|
1
|
+
---
|
|
2
|
+
{
|
|
3
|
+
"type": "fx.chorus",
|
|
4
|
+
"name": "Chorus",
|
|
5
|
+
"category": "Effects",
|
|
6
|
+
"subcategory": "Modulation",
|
|
7
|
+
"description": "Classic chorus with LFO-modulated delay",
|
|
8
|
+
"color": "#24f2f2",
|
|
9
|
+
"width": 180,
|
|
10
|
+
"inputs": [
|
|
11
|
+
{
|
|
12
|
+
"id": "in",
|
|
13
|
+
"name": "Input",
|
|
14
|
+
"type": "audio",
|
|
15
|
+
"required": true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "lfo_rate",
|
|
19
|
+
"name": "LFO Rate",
|
|
20
|
+
"type": "control",
|
|
21
|
+
"required": false
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "lfo_width",
|
|
25
|
+
"name": "LFO Width",
|
|
26
|
+
"type": "control",
|
|
27
|
+
"required": false
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"outputs": [
|
|
31
|
+
{
|
|
32
|
+
"id": "out",
|
|
33
|
+
"name": "Output",
|
|
34
|
+
"type": "audio"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"parameters": [
|
|
38
|
+
{
|
|
39
|
+
"id": "baseDelay",
|
|
40
|
+
"name": "Base Delay (ms)",
|
|
41
|
+
"type": "number",
|
|
42
|
+
"default": 15,
|
|
43
|
+
"min": 1,
|
|
44
|
+
"max": 50,
|
|
45
|
+
"conversion": "MS_TO_SAMPLES",
|
|
46
|
+
"description": "Base delay time (center of modulation) in ms.",
|
|
47
|
+
"step": 0.1
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "rate",
|
|
51
|
+
"name": "LFO Rate (Hz)",
|
|
52
|
+
"type": "number",
|
|
53
|
+
"default": 1.0,
|
|
54
|
+
"min": 0.05,
|
|
55
|
+
"max": 10,
|
|
56
|
+
"conversion": "HZ_TO_LFO_RATE",
|
|
57
|
+
"description": "Frequency of the chorus modulation in Hz.",
|
|
58
|
+
"step": 0.01
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "width",
|
|
62
|
+
"name": "LFO Width (ms)",
|
|
63
|
+
"type": "number",
|
|
64
|
+
"default": 1,
|
|
65
|
+
"min": 0,
|
|
66
|
+
"max": 10,
|
|
67
|
+
"conversion": "MS_TO_LFO_RANGE",
|
|
68
|
+
"description": "The width of modulation in ms.",
|
|
69
|
+
"step": 0.1
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "lfoSel",
|
|
73
|
+
"name": "LFO Select",
|
|
74
|
+
"type": "select",
|
|
75
|
+
"default": 0,
|
|
76
|
+
"options": [
|
|
77
|
+
{
|
|
78
|
+
"value": 0,
|
|
79
|
+
"label": "LFO 0"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"value": 1,
|
|
83
|
+
"label": "LFO 1"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"memories": [
|
|
89
|
+
{
|
|
90
|
+
"id": "delayl",
|
|
91
|
+
"size": "${baseDelay} * 2"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"registers": [
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
---
|
|
98
|
+
@if isequalto lfoSel 0
|
|
99
|
+
@equals lfoNum SIN0
|
|
100
|
+
@equals lfoRateReg SIN0_RATE
|
|
101
|
+
@equals lfoRange SIN0_RANGE
|
|
102
|
+
@else
|
|
103
|
+
@equals lfoNum SIN1
|
|
104
|
+
@equals lfoRateReg SIN1_RATE
|
|
105
|
+
@equals lfoRange SIN1_RANGE
|
|
106
|
+
@endif
|
|
107
|
+
|
|
108
|
+
@section init
|
|
109
|
+
; Initialize LFO
|
|
110
|
+
skp run, done_lfo
|
|
111
|
+
wlds ${lfoNum}, ${rate}, ${width}
|
|
112
|
+
done_lfo:
|
|
113
|
+
|
|
114
|
+
@section main
|
|
115
|
+
@multiplyDouble lfo_depth_delay width 0.5
|
|
116
|
+
@multiplyDouble delay_mem_size baseDelay 2.0
|
|
117
|
+
@assert lfo_depth_delay < delay_mem_size, "Maximum LFO depth exceeds delay memory bounds. Increase base delay or decrease LFO depth."
|
|
118
|
+
|
|
119
|
+
; Chorus
|
|
120
|
+
rdax ${input.in}, 1.0
|
|
121
|
+
wra ${mem.delayl}, 0.0
|
|
122
|
+
|
|
123
|
+
@if pinConnected(lfo_rate)
|
|
124
|
+
rdax ${input.lfo_rate}, ${param.rate.max} / 511.0
|
|
125
|
+
sof 1.0, ${param.rate.min} / 511.0
|
|
126
|
+
wrax ${lfoRateReg}, 0.0
|
|
127
|
+
@endif
|
|
128
|
+
|
|
129
|
+
@if pinConnected(lfo_width)
|
|
130
|
+
rdax ${input.lfo_width}, ${param.width.max} / 32767.0
|
|
131
|
+
sof 1.0, ${param.width.min} / 32767.0
|
|
132
|
+
wrax ${lfoRange}, 0.0
|
|
133
|
+
@endif
|
|
134
|
+
|
|
135
|
+
; Read modulated tap (wet signal)
|
|
136
|
+
; center offset from start of delay line
|
|
137
|
+
@equals center ${mem.delayl} + ${baseDelay}
|
|
138
|
+
cho rda, ${lfoNum}, SIN | REG | COMPC, ${center}
|
|
139
|
+
cho rda, ${lfoNum}, SIN, ${center} + 1
|
|
140
|
+
|
|
141
|
+
wrax ${output.out}, 0.0
|