Guide
Inline controls
Knobs and sliders are retained named values that you can perform live, write into the source, set from code, or map to MIDI.
An inline control lets you either perform a value or edit the score. This page covers how knobs and sliders keep their values, what each drag gesture changes, how code reads and writes the same values, and how to connect controls to MIDI.
A knob or slider holds a retained, named value. You can change it with the mouse, from code, or through a MIDI mapping. Re-evaluating an unchanged declaration does not reset its performed value.
This complete phrase places controls at their use sites:
(d1! (>> (notes "f3 ab3 c4 eb4")
(s "psin")
(lpf (knob :cutoff 6000
:min 200
:max 16000
:curve :log
:unit :hz))
(gain (slider :level 1
:min 0
:max 1.5
:step .01))))The :cutoff knob sits inside lpf, and the :level slider sits inside gain. Each control is declared at the point in the pipeline where its value is used.
Modifiers separate a live gesture from an authored change:
| Gesture on a knob or slider | Live value | Source text | Evaluation |
|---|---|---|---|
| Plain drag | Changes during the drag | Unchanged | No form re-evaluation |
| Option-drag | Unchanged | Changes | No automatic evaluation |
| Command-drag | Kept until release | Changes | Associated form executes once on release |
| Control-drag | Changes during the drag | Changes | Write-through control update |
| Shift with a drag | Finer movement | Follows the chosen mode | Follows the chosen mode |
| Double-click | Resets to the declaration’s reset value | Follows the chosen mode | Follows the chosen mode |
Read the table by intent:
- To perform without touching the score, use a plain drag.
- To edit the score without changing what is playing, use Option-drag.
- To edit the score and evaluate the associated form once when you let go, use Command-drag.
- To change the live value and the source together, use Control-drag.
A source write replaces only the control’s tracked value expression.
Code can also set and read the same named value that a knob or slider holds:
(set-control :level .8)
(get-control :cutoff)midi-map and midi-learn connect named controls to incoming MIDI.
- Absolute controls support pickup behavior.
- Relative encoder modes must match the controller’s configured message format.
- Mapping registration is separate from explicitly opening the selected input device.
The API is not tied to one controller; MIDI Fighter Twister-style encoders are one application.
This example uses a MIDI Fighter Twister. The first form explicitly opens the input device; midi-map then registers the mapping for the :cutoff control:
(mora.runtime:start-midi-input :device "Midi Fighter Twister")
(midi-map :cutoff
:device "Midi Fighter Twister"
:channel 1
:cc 0
:mode :absolute
:takeover :pickup)MIDI output channels in the performance API and input channels in a widget map follow different numbering conventions. Check the corresponding signature in Studio’s contextual documentation instead of copying a channel number from one to the other. MIDI output is covered in MIDI and other outputs.
Source references
Repository-relative paths in the Mora source where these mechanisms are implemented.
-
src/studio/ui-gestures.lisp -
src/studio/render-inline-*.lisp