Idiot proof mode/safe range to exit LOOPFULL sections

I’m working with an artist who has a few song arrangements with a looping 8-bar section (LOOPFULL), during which one of the performers who has MIDI transport control will press Next to exit the loop. This will play an audio cue in their ears (roughly 5 seconds long) signalling that the loop will exit the next time it completes.

However, there have been a few occasions where they have accidentally triggered this just a fraction of a second before the loop completes, so it effectively exits the loop immediately but the 5 second audio cue plays out, resulting in much confusion.

I’m wondering if it would be possible to implement some sort of safe zone for exiting a loopfull section, so that for example you can’t exit a loop if it’s in the final bar of that section, i.e. if the loop is 8 bars long, you can only press Next to exit in the first 7 bars, after which the Next trigger won’t do anything until after it loops around again.

Is this possible/of any use to anyone else?

I’ve had exactly this issue pop up in performance a couple of times recently!

I actually started working on something the other day, which with simple testing seems to to the trick. Still need to test with our show file and in rehearsal.

  1. Use an OSC track in the session to update the value of a shared variable to denote which parts of the loop are ok to escape the loop and which parts are not

  2. Edit the script of your Go button to check if you’re in a loop, if yes, then check the value of the variable and fire ‘go’ as you need to

if(osc("/setlist/isInActiveSectionLoop"))
  {
    if(shared("enableGo") === "yes") {
      sendOsc("/setlist/go")
    } else {
      /* do nothing*/
    }
  }
else
  {sendOsc("/setlist/go")}

The next part of this is getting Ableset to listen for a ‘go’ and if it’s fired during the “no” period, wait until in “yes”, then send it. I’ve only just started testing this…

  1. In the above script, where it has “do nothing” insert something like setShared("cueGo", "yes");
  2. Then in the project script Listen for changes to the “enableGo” variable, and if the “cueGo” variable is set, fire “go”
onOscChange("/shared/enableGo", ([enableGo]) => {

  const isGoCued = shared("cueGo");

  if (enableGo === "yes" &&
      isGoCued === "yes") {
    sendOsc("/setlist/go");
    resetShared("cueGo");
  }

});

Hope it helps!

2 Likes

That’s a great approach @zacjohnsnz!

And @chris.topher, really good catch on that edge case!

Two things that might round it out for live use:

1. Visual feedback when Go is cued

The main risk with the current flow is that if the performer presses Go during the “no” window, nothing visibly happens, so they might start doubting and press again. Adding a cue light flash and/or a toast when cueGo might help close that gap:

// In the "do nothing" branch of the Go button script:
setShared("cueGo", "yes");
sendOsc("/notify/cue", "all", 500, "amber");
// Or, more explicit:
sendOsc("/notify/toast", "all", "Go queued", "Will exit after this loop", 2000);

If the Go button lives on a Canvas, you can also give it a dynamic background color so it lights up while cued:

${shared("cueGo") === "yes" ? "amber-500" : "green-700"}

2. Narrow the logic to +LOOPFULL sections only

If you use plain +LOOP elsewhere and don’t want this safe-zone logic interfering with it, you could try checking the loop mode first:

if (
  osc("/setlist/isInActiveSectionLoop") &&
  osc("/setlist/activeSectionLoopMode") === "loopfull"
) {
  // safe zone logic here
} else {
  sendOsc("/setlist/go");
}

That way the wrapper (the if condition) only kicks in for the sections where the cue-audio issue actually applies.

Hope that helps!

1 Like