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.

Controls are retained named values

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.

Place controls where they are used

This complete phrase places controls at their use sites:

Common Lisp
(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.

Perform or write: drag gestures

Modifiers separate a live gesture from an authored change:

Gesture on a knob or sliderLive valueSource textEvaluation
Plain dragChanges during the dragUnchangedNo form re-evaluation
Option-dragUnchangedChangesNo automatic evaluation
Command-dragKept until releaseChangesAssociated form executes once on release
Control-dragChanges during the dragChangesWrite-through control update
Shift with a dragFiner movementFollows the chosen modeFollows the chosen mode
Double-clickResets to the declaration’s reset valueFollows the chosen modeFollows 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.

Set and read values from code

Code can also set and read the same named value that a knob or slider holds:

Common Lisp
(set-control :level .8)
(get-control :cutoff)

MIDI knobs

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.

Map a controller knob

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:

Common Lisp
(mora.runtime:start-midi-input :device "Midi Fighter Twister")

(midi-map :cutoff
          :device "Midi Fighter Twister"
          :channel 1
          :cc 0
          :mode :absolute
          :takeover :pickup)

Input and output channel numbers

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

Documentation

Search the documentation

Results update as you type. Use the up and down arrow keys to choose a result and Enter to open it.