MIDI CC
This content is for v0.7. Switch to the latest version for up-to-date documentation.
Read MIDI Control Change (CC) values as signals and use them to modulate parameters in real time.
Reading CC Values
Section titled “Reading CC Values”Any channel
Section titled “Any channel”Cc(cc_num) creates a signal that reads the given CC number from any MIDI channel. The signal outputs a value from 0.0 to 1.0:
let cutoff_signal = Cc(74);Specific channel
Section titled “Specific channel”Cc(channel, cc_num) reads from a specific MIDI channel (0—15):
let cutoff_signal = Cc(0, 74);Both forms require an active MIDI input connection (see MIDI Input).
Channel behavior
Section titled “Channel behavior”Cc(cc_num) reads the last CC value received on any MIDI channel. This is convenient when you have a single controller and don’t care which channel it sends on.
Cc(channel, cc_num) isolates to a single channel (0—15). Use this when multiple controllers share the same CC numbers and you need to distinguish between them.
MIDI Learn
Section titled “MIDI Learn”Cc_learn() provides interactive MIDI learn. It blocks for up to 10 seconds, waiting for you to move a knob or fader:
- Displays
Waiting for CC input... (10s timeout)in the console - Once a CC message arrives, returns a signal bound to that exact channel and CC number
- Prints
Learned: Cc(channel, cc_num)— use this to hardcode the call later
let knob = Cc_learn();// Console: "Waiting for CC input... (10s timeout)"// Move a knob on your controller...// Console: "Learned: Cc(0, 74)"If no CC message is received within 10 seconds, an error is raised. An active MIDI input connection is required.
Workflow
Section titled “Workflow”Use Cc_learn() interactively to discover the right CC number, then replace it with a hardcoded Cc() call for your script:
// Step 1: discover the CC numberlet knob = Cc_learn();// Console: "Learned: Cc(0, 74)"
// Step 2: replace with hardcoded calllet knob = Cc(0, 74);Smoothing
Section titled “Smoothing”CC values arrive as discrete 7-bit steps (0—127). To eliminate zipper noise when modulating audio parameters, apply .smooth(time_ms):
let cutoff = Cc(74).smooth(50);The argument is the smoothing time in milliseconds. A one-pole lowpass filter interpolates between incoming values, producing a continuous signal.
Using CC Signals for Modulation
Section titled “Using CC Signals for Modulation”CC signals work anywhere a signal is accepted. Use << to route a signal into a parameter:
Filter cutoff
Section titled “Filter cutoff”midi_input_connect("USB Controller", "ctrl");
let synth = AudioTrack("synth");synth.filter.Cutoff << Cc(74).smooth(50);Expression pedal for volume
Section titled “Expression pedal for volume”let track = AudioTrack("keys");track.Gain << Cc(11).smooth(20);Modulation wheel for effect depth
Section titled “Modulation wheel for effect depth”let track = AudioTrack("pad");track.reverb.Mix << Cc(1).smooth(30);Common CC Numbers
Section titled “Common CC Numbers”| CC | Name | Typical Use |
|---|---|---|
| 1 | Mod Wheel | Vibrato, filter modulation |
| 7 | Volume | Channel volume |
| 10 | Pan | Stereo panning |
| 11 | Expression | Dynamic volume |
| 64 | Sustain | On/off (≥64 = on) |
| 74 | Brightness | Filter cutoff |
Multiple CC Sources
Section titled “Multiple CC Sources”Use multiple CCs to control different parameters simultaneously:
midi_input_connect("USB Controller", "ctrl");
let synth = AudioTrack("synth");
// Mod wheel controls vibrato depthsynth.vibrato.Depth << Cc(1).smooth(30).range(0, 1);
// CC 74 controls filter cutoffsynth.filter.Cutoff << Cc(74).smooth(50).range(200, 8000);
// Expression pedal controls volumesynth.Gain << Cc(11).smooth(20);Signal Methods
Section titled “Signal Methods”CC signals support all standard signal methods. See Signal Methods for the full list. Common ones:
| Method | Description |
|---|---|
.smooth(time_ms) | One-pole lowpass smoothing |
.range(min, max) | Scale output to a linear range |
.range_exp(min, max) | Scale output to an exponential range |
Example — map a CC to a frequency range with linear scaling:
let filter_freq = Cc(74).smooth(50).range(200, 8000);For parameters that feel more natural on a logarithmic scale (like frequency), use .range_exp():
let filter_freq = Cc(74).smooth(50).range_exp(200, 8000);Thread Safety
Section titled “Thread Safety”CC values are stored atomically and updated from the MIDI input thread. They are safe to read from the audio thread without locks, making them suitable for real-time parameter control.
See Also
Section titled “See Also”- MIDI Input — connect MIDI input devices
- MIDI Tracks — send patterns to MIDI outputs
- Signal Methods — full signal method reference