Thursday, March 20, 2025

Switched On: Three types of controls meet three types of targets

CK: I’ve been struggling for a long time with a deep problem having to do how various types of controls should be mapped to various types of target properties. If all of the properties are ranges, and all of the controllers are continuous, there’s no problem. The problem only comes about when some of the controls are switches, and/or some of the properties are booleans or actions. Actions are sometimes referred to as “bangs” in Max/MSP terminology. It’s about time I came up with a solution.

After much consideration, I believe there are three types of controls, and three types of target properties.

The three types of controls:

  • Knob/Slider
  • Toggle
  • Momentary

The three types of targets:

  • Range/Selection
  • Boolean
  • Action

They form a 3 x 3 matrix with nine permutations. In a proper implementation, all nine possibilities should exhibit reasonable behavior.

But for any given property, only the three control types need to vary, because the target’s type is invariant in any given application. A target that’s a range, stays a range. The only question is what type of control is being mapped to it.

Of course there’s nothing to stop the user from lying. They could select the toggle control type, but actually connect a knob. If we include lying, the matrix is 3 x 3 x 3. But luckily, I think we can ignore lying, as it’s not in the user’s interest.

I wonder, does this issue have a name? Presumably I’m not the first person to consider this problem.

I would like to see the 3 x 3 matrix fleshed out, with an unambiguous definition of correct behavior in each case. Here, I’ll start:

Knob -> Range: Space the range of knob values evenly across the range of the target property.

Knob -> Toggle: When the knob transitions from zero to non-zero or vice versa, if the knob is non-zero, set the property to its maximum value, otherwise set the property to its minimum value.

Knob -> Momentary: When the knob transitions from zero to any other value, do the action.

So there you go: three down, six more to go. Is it making any sense?

GPT: Below is one possible 3×3 matrix of behaviors mapping Control Types (Knob, Toggle, Momentary) onto Property Types (Range, Boolean, Action). It’s meant as a conceptual template; in a real application, you might tweak details (like thresholds or event edges) to suit your workflow. But these definitions are consistent and cover all nine permutations in a straightforward manner.


Control Types

  1. Knob

    • A continuous control that can vary from 0 to some maximum (e.g., 127 in MIDI CC, or 1.0 if normalized).
    • Often used for parameter sweeps or any continuous property.
    • The control remembers its last position – it’s not ephemeral.
  2. Toggle

    • A persistent on/off switch. Pressing toggles the internal state from off → on or on → off.
    • The control latches in whichever state was last pressed.
  3. Momentary

    • A push button that is “on” only while pressed. Once you release, it returns to off.
    • The control does not latch – it reverts to off automatically.

Property Types

  1. Range

    • A continuous property from a minimum to maximum value (e.g., 0.0→1.0, or discrete but multi-step).
    • Example: volume, filter cutoff, brightness, etc.
  2. Boolean

    • An on/off or true/false property.
    • Example: bypass, mute, or any binary state.
  3. Action

    • A triggered or one-shot command (“bang”), typically no sustained state.
    • Example: “Play note,” “Fire event,” or “Trigger effect” once per activation.

Mapping Behaviors (3 × 3)

Below is a suggested default for each combination:

1) Knob → Range

  • Behavior: Map the knob’s 0..max range linearly (or via user-chosen curve) onto the property’s min..max.
  • Example: If knob is 50% of travel, set property to 50% of range.

2) Knob → Boolean

  • Behavior: Typically pick a threshold. If knob ≤ some cutoff (e.g., 5% or exactly 0), property = Off; otherwise property = On.
  • User Variation: Some prefer “knob < 50% → Off, knob ≥ 50% → On,” etc.
  • Example: If the knob is near zero, property is false. Once it crosses the threshold, property becomes true.

(Your existing logic was “if knob transitions from 0 → non-zero, set property to On,” which is effectively a threshold at 0. That also works if your knob easily reaches 0. If the knob never fully hits 0, you might prefer a small threshold.)

3) Knob → Action

  • Behavior: When the knob transitions from near 0 to above that threshold, trigger the action once. Possibly require returning the knob to 0 (or below threshold) before allowing another trigger.
  • Example: “When user quickly moves knob from 0 up, fire one event.” If the knob stays above 0, no repeated triggers. Once you dip back below 0, you can trigger again if you move up again.

4) Toggle → Range

  • Behavior: If toggle is Off, set property = min. If toggle is On, set property = max.
  • Example: A simple two-level range control: 0% vs 100%.

5) Toggle → Boolean

  • Behavior: The property directly follows the toggle state. Toggling On sets property = true, toggling Off sets property = false.
  • Example: A bypass or mute parameter that exactly matches the latched on/off switch.

6) Toggle → Action

  • Behavior: Whenever the user toggles from Off → On, fire the action once. Toggling On → Off might do nothing, or optionally also trigger if you want. Usually only the rising edge triggers the action.
  • Example: A latched footswitch. Each time you stomp from Off → On, you trigger an event. Stomping On → Off is no new action.

(It’s up to you whether both edges trigger or just one. For many “action” use cases, only the On edge is used.)


7) Momentary → Range

  • Behavior: While the momentary button is held, set property = max. When released, property = min (or a base level).
  • Example: A “clutch” or “temporary override” that sets the property to its top value only while pressed.

8) Momentary → Boolean

  • Behavior: The property is true while button is pressed, false otherwise.
  • Example: A “momentary mute” or “kill switch” that only stays active while you hold it.

9) Momentary → Action

  • Behavior: Each press triggers the action once, or once per edge if you prefer. Typically the rising edge (button down) triggers the action. Releasing does nothing.
  • Example: A “drum pad” style button. Every time you press it, you fire an event, but no sustained state is kept.

(You can also interpret “momentary → action” as sending repeated triggers while the button is held, but that’s a separate design. The simplest is a single trigger on press.)


Summary Table

Control \ Property Range Boolean Action
Knob 0..knobMax → min..max (linear mapping) If knob < threshold → Off, else On On 0→non-0 transition → fire action once; must return knob to 0 for next trigger
Toggle Off → min; On → max Property follows toggle exactly (On/Off) Off→On edge → trigger action (one-shot)
Momentary Held→max; Released→min Held→true; Released→false Button press→one trigger; release→no event

This matrix (or a variant) is a clean, explicit definition of how each control type can drive each property type in a “MIDI learn” context. You may refine threshold details, or whether off→on and on→off edges each fire actions, etc., but the above is a workable baseline solution covering all 9 combos.

No comments: