Files
looper/docs/1-multichannel.md
Loic Coenen 60a8bdcfe8 feat: add unbind command (note 63) to reset bind_channel to 0
Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
2026-05-09 11:14:52 +00:00

4.3 KiB
Raw Blame History

MultiChannel & Bind Feature

The looper supports up to 16 independent channels (numbered 015).
Channel0 is always present and connected to the looper:input / looper:output audio ports.
Additional channels can be created and removed dynamically using MIDI commands.

MIDI Ports

  • looper:control receives MIDI noteon events for channel management and state toggling.
  • looper:clock receives MIDI clock messages (0xFA, 0xFC, 0xFB) that affect channel0 only.

ControlKey Modifier

Hold the control key (MIDI note64) pressed before sending another note to put the looper in “command mode”.
While controlkey is active, the next noteon (with velocity > 0) performs a special action instead of its direct mapping.
The control key is released either by sending noteoff (note64 or any note) or by sending a noteon while controlkey is already active (the action is performed and controlkey is cleared).

Available Commands (under control key)

Note Action
015 Bind the next control+62 toggle to the channel with that index.
60 Add a new dynamic channel (creates channelX_input / channelX_output ports).
61 Remove the highestnumbered active channel (excluding channel0).
62 Toggle the current bound channel through its state machine:
IDLE → RECORD → LOOPING → PAUSED → LOOPING → … (each press advances one step).
63 Unbind reset the bound channel back to 0.

Notes:

  • The default bound channel is 0. If you never send a bind command, control+62 controls channel0.
  • To bind a different channel, send control + note <16> (e.g., control + note5 binds channel5).
  • Bind is sticky it stays until overwritten by another bind command.
  • To unbind (reset to channel0), send control + note63.

Direct Mapping (without control key)

For backward compatibility, the following notes work without the controlkey modifier:

Note Action
1 Toggle channel0 state (IDLE→RECORD→LOOPING→PAUSED→LOOPING…).
60 Add a dynamic channel (same as control+60).
61 Remove the highestnumbered active channel (same as control+61).

Example Usage

  1. Record a loop on channel0 (using direct note1)

    • Send noteon, note1, velocity127 → channel0 enters RECORD.
    • Play some audio into looper:input.
    • Send noteon, note1, velocity127 again → channel0 enters LOOPING.
    • The recorded audio repeats indefinitely.
  2. Use the controlkey to toggle channel0

    • Send noteon, note64 (control key).
    • Then send noteon, note62 → toggles channel0 (IDLE→RECORD).
    • Send noteon, note64 again, then noteon, note62 again → RECORD→LOOPING.
  3. Add a new channel and bind it

    • Send noteon, note64 + noteon, note60 → creates channel1.
    • Send noteon, note64 + noteon, note1 → binds channel1.
    • Now control+62 toggles channel1 instead of channel0.
    • Record audio on channel1 by sending control+62 twice.
  4. Remove a dynamic channel

    • Send noteon, note64 + noteon, note61 → removes the highestnumbered active channel (e.g., channel1).

Notes

  • The looper must be connected to a running JACK server.
  • Channel buffers hold up to 5 seconds of audio at 48kHz.
  • After removal, the channels audio ports are unregistered on the next mainloop cycle (deferred to avoid race conditions).
  • The bind index is stored as an integer (015); values outside 015 are ignored (the note is processed as a command rather than a bind).