Safe Mode for MIDI Controllers

I’d love to have safe mode available for pause and stop commands sent from a midi controller.

How might I achieve this with OSC? Or could this be implemented as a toggle when mapping pause / stop within the MIDI Assignments settings page?

Hey @mujo.live,

At the moment, Safe Mode (Settings → Playback) doesn’t apply to MIDI mapping or OSC-received commands, so it won’t protect pause/stop triggered from a controller.

The way to get that safeguard for MIDI-triggered commands is at the individual mapping level: in Settings → MIDI Mapping, OSC & Scripting → Edit MIDI Mapping, set the Trigger type for your Pause and/or Stop mappings to Double Press or Hold instead of the default. That way a single accidental tap won’t fire the command, as you get the same kind of deliberate confirmation Safe Mode gives elsewhere.

You can also see this in action in the official tutorial: MIDI Mapping trigger types and Safe Mode interaction

Would that work for your use case?

Thanks @agustinvolpe

My preferred controller uses MIDI CC not notes, so the trigger type options appear to be unavailable. Any ideas how I could work around this without having to translate CC to notes? Thanks

Hey @mujo.live,

Here’s a script you can drop into a Custom Script mapping on your CC that adds a double-press safeguard before it fires.

Set the Command for your CC mapping to Custom Script and paste this:

// Only react to the press, not the release.
// Adjust this check to match your controller — most send 127 on press
// and 0 on release, so you'd likely want: if (midi.value !== 127) return;
if (midi.value !== 0) return;

const WINDOW_MS = 600; // how long the second press has to arrive
const lastPress = shared("stopArmedAt", 0);

if (now() - lastPress < WINDOW_MS) {
  setShared("stopArmedAt", 0);
  sendOsc("/global/stop");
} else {
  setShared("stopArmedAt", now());
}

The first press just stores a timestamp and does nothing else. The second press only fires /global/stop if it lands within WINDOW_MS — press too slowly and it simply re-arms, which is exactly the safeguard you’re after. Bump WINDOW_MS up if 600ms feels too tight on your controller.

For Pause, duplicate this on the other CC mapping with a different key name (e.g. pauseArmedAt) and /global/pause. Shared variables are global across all scripts and devices, so reusing the same key on both would make them interfere with each other.

Let me know how it behaves on your end!