Audio Effect Development
Create standard SuperCollider audio effects for Bice-Box (delays, reverbs, filters, distortions, etc.).
Critical Rules
⚠️ FILENAME/DEFNAME MATCHING IS CRITICAL ⚠️
- defName MUST EXACTLY match filename (character for character!)
- ✅ CORRECT:
reverb.sc → var defName = \reverb;
- ✅ CORRECT:
ping_pong_delay.sc → var defName = \ping_pong_delay;
- ❌ WRONG:
happy-synth.sc → var defName = \happy_synth; (hyphen vs underscore!)
- ❌ WRONG:
my_effect.sc → var defName = \my-effect; (underscore vs hyphen!)
- If faders don't appear in UI, check filename vs defName first!
Other Critical Rules
- First THREE lines must be comments:
// shader: <name>, // category: <category>, and // description: <brief description>
- Description must be a single line (~60-80 chars): concise summary of what the effect does
- All variables in ONE block after parameters - NO
var declarations anywhere else
- Use specs defaults:
\param.kr(specs[\param].default)
- Mono-first: Process in mono, output
[processed, processed]
- Analysis out: Always mono signal to
analysis_out_bus
- Maximum 12 faders fit on screen - design parameters accordingly
Effect Template
// shader: oscilloscope
// category: Modulation
// description: Brief single-line summary of what this effect does
(
var defName = \effect_name; // ← MUST match filename exactly!
var specs = (
param1: ControlSpec(0.1, 10.0, 'exp', 0, 1.0, "x"),
mix: ControlSpec(0.0, 1.0, 'lin', 0, 0.5, "%")
);
var def = SynthDef(defName, {
// Standard parameters
var out = \out.kr(0);
var in_bus = \in_bus.kr(0);
var analysis_out_bus = \analysis_out_bus.kr;
var param1 = \param1.kr(specs[\param1].default);
var mix = \mix.kr(specs[\mix].default);
// ALL variables declared here!
var sig, dry, processed, mono_for_analysis;
// Processing
sig = In.ar(in_bus); // Mono input
dry = sig;
processed = sig * param1; // Your effect here
processed = XFade2.ar(dry, processed, mix * 2 - 1);
// Outputs
mono_for_analysis = processed;
Out.ar(analysis_out_bus, mono_for_analysis);
Out.ar(out, [processed, processed]);
});
def.add;
"Effect SynthDef 'effect_name' added".postln;
~setupEffect.value(defName, specs);
)
Feedback Effects Pattern
For delays, reverbs, and other feedback-based effects:
// Get feedback from previous iteration
var fbNode = LocalIn.ar(1);
// Create delay with input + feedback
var delayed = DelayC.ar(sig + fbNode, maxDelayTime, delayTime);
// Send feedback back (with feedback amount control)
LocalOut.ar(delayed * feedback);
Common ControlSpecs
// Linear 0-1 parameters (mix, level, etc.)
mix: ControlSpec(0.0, 1.0, 'lin', 0, 0.5, "%")
// Exponential frequency parameters
freq: ControlSpec(20, 2000, 'exp', 0, 440, "Hz")
// Gain/amplitude parameters
gain: ControlSpec(0.1, 5.0, 'exp', 0, 1.0, "x")
// Time-based parameters
delay: ControlSpec(0.001, 2.0, 'exp', 0, 0.1, "s")
Visualizer Comments
Add a visualizer comment as the first line to auto-load a visualizer when the effect loads:
- For GLSL shaders:
// shader: shader_name (loads from shaders/ directory)
- For p5.js sketches:
// p5: sketch_name (loads from visual/ directory)
Examples:
// shader: oscilloscope → loads shaders/oscilloscope.glsl
// shader: palpatine → loads shaders/palpatine_image.glsl (multi-pass)
// p5: tuner → loads visual/tuner.js
Note: Visualizer names must be unique across both directories.
Category Comments
Add a category comment on line 2 (after the visualizer comment) to organize effects in the UI:
// shader: oscilloscope
// category: Distortion
Example categories:
- Distortion - overdrive, fuzz, saturation, bitcrushing
- Modulation - chorus, flanger, phaser, tremolo, vibrato
- Delay - echo, ping-pong, tape delay, multi-tap
- Reverb - room, hall, shimmer, ambient
- Filter - wah, EQ, resonant filters
- Pitch - harmonizer, octaver, pitch shifter
- Dynamics - compressor, limiter, gate, expander
- Spectral - vocoder, freeze, FFT effects
- Lo-Fi - tape, vinyl, degradation, noise
- Utility - tuner, bypass, test tones
but feel free to create new categories as needed.
MCP Workflow
Recommended workflow for creating/updating effects:
Test syntax - Use test_supercollider_code to validate during development
mcp__bice-box__test_supercollider_code(scCode: "your code here")
Create/update - Use create_or_update_audio_effect to safely save
mcp__bice-box__create_or_update_audio_effect(
effectName: "my_effect",
scCode: "your code here",
makeActive: true // optional, loads effect immediately
)
Activate - Switch to your effect
mcp__bice-box__set_current_effect(effectName: "my_effect")
Tweak parameters - Adjust live values for testing
mcp__bice-box__set_effect_parameters(params: {
param1: 2.5,
mix: 0.7
})
Note: This only affects live session values. To change defaults, edit the .sc file.
Debug errors - If compilation fails, check logs
mcp__bice-box__read_logs(lines: 100, filter: "ERROR")
Common Patterns
Distortion/Saturation
processed = (sig * drive).tanh; // Soft clipping
processed = sig.distort; // Hard distortion
processed = sig.softclip; // Soft clipping
Filtering
processed = LPF.ar(sig, cutoff); // Low-pass
processed = HPF.ar(sig, cutoff); // High-pass
processed = RLPF.ar(sig, cutoff, rq); // Resonant low-pass
processed = MoogFF.ar(sig, cutoff, resonance); // Moog-style filter
Delay/Echo
processed = DelayC.ar(sig, maxDelay, delayTime); // Clean delay
processed = CombC.ar(sig, maxDelay, delayTime, decayTime); // Comb filter
Modulation
var lfo = SinOsc.kr(rate); // LFO for modulation
processed = sig * (1 + (depth * lfo)); // Amplitude modulation
Tips
- Start with simple effects and add complexity gradually
- Test with live audio input frequently
- Use sensible parameter ranges (exponential for frequency/time, linear for mix)
- Keep CPU usage in mind - avoid excessive nesting
- Use meaningful parameter names for better UI readability
1---2name: audio-effect3description: Create standard SuperCollider audio effects for Bice-Box (delays, reverbs, filters, distortions). Provides templates, ControlSpecs, common patterns, and MCP workflow for safely creating/updating effects.4---5
6# Audio Effect Development
7
8Create standard SuperCollider audio effects for Bice-Box (delays, reverbs, filters, distortions, etc.).
9
10## Critical Rules
11
12### ⚠️ FILENAME/DEFNAME MATCHING IS CRITICAL ⚠️
13- **defName MUST EXACTLY match filename** (character for character!)
14 - ✅ CORRECT: `reverb.sc` → `var defName = \reverb;`
15 - ✅ CORRECT: `ping_pong_delay.sc` → `var defName = \ping_pong_delay;`
16 - ❌ WRONG: `happy-synth.sc` → `var defName = \happy_synth;` (hyphen vs underscore!)
17 - ❌ WRONG: `my_effect.sc` → `var defName = \my-effect;` (underscore vs hyphen!)
18- **If faders don't appear in UI, check filename vs defName first!**
19
20### Other Critical Rules
21- **First THREE lines must be comments**: `// shader: <name>`, `// category: <category>`, and `// description: <brief description>`
22- **Description must be a single line** (~60-80 chars): concise summary of what the effect does
23- **All variables in ONE block** after parameters - NO `var` declarations anywhere else
24- **Use specs defaults**: `\param.kr(specs[\param].default)`
25- **Mono-first**: Process in mono, output `[processed, processed]`
26- **Analysis out**: Always mono signal to `analysis_out_bus`
27- **Maximum 12 faders** fit on screen - design parameters accordingly
28
29## Effect Template
30
31```supercollider
32// shader: oscilloscope
33// category: Modulation
34// description: Brief single-line summary of what this effect does
35(
36 var defName = \effect_name; // ← MUST match filename exactly!
37 var specs = (
38 param1: ControlSpec(0.1, 10.0, 'exp', 0, 1.0, "x"),
39 mix: ControlSpec(0.0, 1.0, 'lin', 0, 0.5, "%")
40 );
41
42 var def = SynthDef(defName, {
43 // Standard parameters
44 var out = \out.kr(0);
45 var in_bus = \in_bus.kr(0);
46 var analysis_out_bus = \analysis_out_bus.kr;
47 var param1 = \param1.kr(specs[\param1].default);
48 var mix = \mix.kr(specs[\mix].default);
49
50 // ALL variables declared here!
51 var sig, dry, processed, mono_for_analysis;
52
53 // Processing
54 sig = In.ar(in_bus); // Mono input
55 dry = sig;
56 processed = sig * param1; // Your effect here
57 processed = XFade2.ar(dry, processed, mix * 2 - 1);
58
59 // Outputs
60 mono_for_analysis = processed;
61 Out.ar(analysis_out_bus, mono_for_analysis);
62 Out.ar(out, [processed, processed]);
63 });
64 def.add;
65 "Effect SynthDef 'effect_name' added".postln;
66
67 ~setupEffect.value(defName, specs);
68)
69```
70
71## Feedback Effects Pattern
72
73For delays, reverbs, and other feedback-based effects:
74
75```supercollider
76// Get feedback from previous iteration
77var fbNode = LocalIn.ar(1);
78// Create delay with input + feedback
79var delayed = DelayC.ar(sig + fbNode, maxDelayTime, delayTime);
80// Send feedback back (with feedback amount control)
81LocalOut.ar(delayed * feedback);
82```
83
84## Common ControlSpecs
85
86```supercollider
87// Linear 0-1 parameters (mix, level, etc.)
88mix: ControlSpec(0.0, 1.0, 'lin', 0, 0.5, "%")
89
90// Exponential frequency parameters
91freq: ControlSpec(20, 2000, 'exp', 0, 440, "Hz")
92
93// Gain/amplitude parameters
94gain: ControlSpec(0.1, 5.0, 'exp', 0, 1.0, "x")
95
96// Time-based parameters
97delay: ControlSpec(0.001, 2.0, 'exp', 0, 0.1, "s")
98```
99
100## Visualizer Comments
101
102Add a visualizer comment as the first line to auto-load a visualizer when the effect loads:
103
104- **For GLSL shaders:** `// shader: shader_name` (loads from `shaders/` directory)
105- **For p5.js sketches:** `// p5: sketch_name` (loads from `visual/` directory)
106
107Examples:
108- `// shader: oscilloscope` → loads `shaders/oscilloscope.glsl`
109- `// shader: palpatine` → loads `shaders/palpatine_image.glsl` (multi-pass)
110- `// p5: tuner` → loads `visual/tuner.js`
111
112**Note:** Visualizer names must be unique across both directories.
113
114## Category Comments
115
116Add a category comment on line 2 (after the visualizer comment) to organize effects in the UI:
117
118```supercollider
119// shader: oscilloscope
120// category: Distortion
121```
122
123**Example categories:**
124- **Distortion** - overdrive, fuzz, saturation, bitcrushing
125- **Modulation** - chorus, flanger, phaser, tremolo, vibrato
126- **Delay** - echo, ping-pong, tape delay, multi-tap
127- **Reverb** - room, hall, shimmer, ambient
128- **Filter** - wah, EQ, resonant filters
129- **Pitch** - harmonizer, octaver, pitch shifter
130- **Dynamics** - compressor, limiter, gate, expander
131- **Spectral** - vocoder, freeze, FFT effects
132- **Lo-Fi** - tape, vinyl, degradation, noise
133- **Utility** - tuner, bypass, test tones
134
135but feel free to create new categories as needed.
136
137## MCP Workflow
138
139**Recommended workflow for creating/updating effects:**
140
1411. **Test syntax** - Use `test_supercollider_code` to validate during development
142 ```
143 mcp__bice-box__test_supercollider_code(scCode: "your code here")
144 ```
145
1462. **Create/update** - Use `create_or_update_audio_effect` to safely save
147 ```
148 mcp__bice-box__create_or_update_audio_effect(
149 effectName: "my_effect",
150 scCode: "your code here",
151 makeActive: true // optional, loads effect immediately
152 )
153 ```
154
1553. **Activate** - Switch to your effect
156 ```
157 mcp__bice-box__set_current_effect(effectName: "my_effect")
158 ```
159
1604. **Tweak parameters** - Adjust live values for testing
161 ```
162 mcp__bice-box__set_effect_parameters(params: {
163 param1: 2.5,
164 mix: 0.7
165 })
166 ```
167 Note: This only affects live session values. To change defaults, edit the `.sc` file.
168
1695. **Debug errors** - If compilation fails, check logs
170 ```
171 mcp__bice-box__read_logs(lines: 100, filter: "ERROR")
172 ```
173
174## Common Patterns
175
176### Distortion/Saturation
177```supercollider
178processed = (sig * drive).tanh; // Soft clipping
179processed = sig.distort; // Hard distortion
180processed = sig.softclip; // Soft clipping
181```
182
183### Filtering
184```supercollider
185processed = LPF.ar(sig, cutoff); // Low-pass
186processed = HPF.ar(sig, cutoff); // High-pass
187processed = RLPF.ar(sig, cutoff, rq); // Resonant low-pass
188processed = MoogFF.ar(sig, cutoff, resonance); // Moog-style filter
189```
190
191### Delay/Echo
192```supercollider
193processed = DelayC.ar(sig, maxDelay, delayTime); // Clean delay
194processed = CombC.ar(sig, maxDelay, delayTime, decayTime); // Comb filter
195```
196
197### Modulation
198```supercollider
199var lfo = SinOsc.kr(rate); // LFO for modulation
200processed = sig * (1 + (depth * lfo)); // Amplitude modulation
201```
202
203## Tips
204- Start with simple effects and add complexity gradually
205- Test with live audio input frequently
206- Use sensible parameter ranges (exponential for frequency/time, linear for mix)
207- Keep CPU usage in mind - avoid excessive nesting
208- Use meaningful parameter names for better UI readability