Hello (first post so please be gentle!),
I’m quite a new user of GP and recent bought the Pro version. While setting up my rig for live performances, I have a reliably reproducible deadlock in Gig Performer 5.1.6 on macOS 26.3.1 (Apple Silicon). Audio stops, the UI remains superficially responsive (windows drag), but rackspace switching beachballs, audio output is silent, and the only way out is Force Quit. The app cannot be quit cleanly - the Save-changes confirmation modal beachballs immediately because the shouldClose handler hits the same lock.
Setup:
-
Gig Performer 5.1.6 (5.1.6)
-
macOS 26.3.1 (25D2128), Apple Silicon
-
Audio interface: Focusrite Scarlett 18i8 USB
-
Plugins in affected rackspaces: Spectrasonics Omnisphere 3.0.2c, Keyscape 1.5.2c
-
MIDI inputs: Apple IAC Driver Bus 1 (from REAPER 7.71), Nord Stage 2EX (USB MIDI), KL Essential 61 mk3 (USB MIDI)
Steps to reproduce:
-
Create a gig with one Global Rackspace and one Local Rackspace.
-
Global Rackspace: MIDI In (any source) →
Local GP Port(out). -
Local Rackspace:
MIDI In Local GP Port→ Omnisphere → audio out. -
Load any Omnisphere patch.
-
Send sustained MIDI to the Global Rackspace (hold a chord on a controller, or play a DAW track via IAC).
-
Within seconds, audio output stops. The Rackspaces sidebar stops responding to clicks. Force Quit is the only way to exit.
My actual gig is slightly richer than the above (Global Rackspace merges MIDI from three input sources and applies a Scriptlet for a -1 semitone transpose before the Local GP Port out) but that detail is not necessary to trigger the bug.
Topology that does NOT hang (with the same gig, same plugins, same MIDI input):
- Global Rackspace uses
To Rackspacesblock, local rackspaces useFrom Global Rackspaceblock. This is functionally equivalent for note routing but is unusable for me because it breaks patch-persist behaviour (MIDI floods all rackspaces simultaneously, which is why I switched to Local GP Port in the first place).
Sampling evidence:
I captured three sample(1) process snapshots at different points; all three are attached to this ticket:
-
GP5-2026-05-03-sample1-playback-hang.txt(sample 1) - taken during a REAPER-driven playback hang. -
GP5-2026-05-03-sample2-quit-modal-hang.txt(sample 2) - same GP process, taken ~13 minutes later whenCmd-Qproduced an immediately-beachballing “Save changes?” modal. -
GP5-2026-05-03-sample3-keyboard-only-hang.txt(sample 3) - after force-quit and restart, taken during a hang where REAPER was muted and only the keyboard was sending MIDI.
All three show the same shape:
-
303 threads total
-
Exactly 3 in
__psynch_mutexwait -
~292 in
__psynch_cvwait(GP worker pool, idle, waiting for jobs that never come) -
Remainder in normal idle states
-
No thread is doing CPU work. The lock holder is gone or part of a circular wait.
The audio IO thread’s blocking call site is bit-for-bit identical across all three samples, relative to the GP binary load address:
HALC_ProxyIOContext::IOWorkLoop()
→ GigPerformer5 +0x733c50
→ GigPerformer5 +0x737870
→ GigPerformer5 +0x805430
→ GigPerformer5 +0x7ab9a4
→ GigPerformer5 +0x7b06f8
→ GigPerformer5 +0x3f8dec
→ GigPerformer5 +0x4c8070
→ GigPerformer5 +0x7382e8 ← lock acquisition site (invariant)
→ _pthread_mutex_firstfit_lock_slow
→ __psynch_mutexwait
The CoreMIDI input thread (entry: MIDIProcess::MIDIInPortThread::Run → MIDIPacketList_Deliverer → LocalMIDIReceiver::connectEndpoint::$_1 callback into GP) also blocks on a mutex, via two different GP code paths depending on the MIDI message in flight:
Path A (samples 1 and 2):
LocalMIDIReceiver::connectEndpoint callback
→ +0x73fefc → +0x738768 → +0x3c87f8 → +0x6b8fac → +0x6aeb7c → +0x5d5944 → +0x740954 → MUTEX
Path B (sample 3):
LocalMIDIReceiver::connectEndpoint callback
→ +0x73fe24 → +0x738374 → +0x702628 → MUTEX
Once the deadlock has started, any UI event that touches the audio graph joins the queue:
Sample 2 (during Cmd-Q):
-[NSApplication terminate:]
→ -[NSApplication _shouldTerminate]
→ -[NSDocumentController _closeAllDocumentsWithDelegate:shouldTerminateSelector:]
→ GP shouldClose handler at +0x6594e8 → MUTEX
Sample 3 (during a sidebar click):
-[NSWindow _handleMouseDownEvent:]
→ GP click handler at +0x928b08 → +0x92dddc → +0x925dd8 → +0x94cacc
→ +0x280ed0 → +0x6ae9ac → +0x5d4530 → +0x3cc1d4 → MUTEX
So GP’s GUI handlers contend synchronously for the same audio engine lock with no “defer-on-contention” path, which is why every click after the initial hang adds another beachballed handler.
Things I have ruled out:
-
Memory pressure / runaway voices - physical footprint stays flat at ~10.4 GB (same as idle) across all three hangs.
-
Plugin GUI overhead - closing Omnisphere’s window before playback does not prevent the hang.
-
Omnisphere or Keyscape itself - when the topology is reverted to
To Rackspaces/From Global Rackspaceblock routing, the same gig with the same plugins never hangs, no matter how long the session runs. -
MIDI source - REAPER → IAC, Nord USB MIDI, KL USB MIDI all eventually trigger it with the Local GP Port topology. REAPER and IAC just trigger it fastest (denser MIDI).
-
MIDI doubling from the -1 transpose Scriptlet - confirmed single voice per note actually reaches Omnisphere; MIDI Monitor was logging at two routing points.
-
GPU / Core Animation stall - initially suspected from the first sample’s main-thread CA frames, but the second and third samples show the main thread directly in
_pthread_mutex_firstfit_lock_slow. The CA frames in sample 1 were a red herring. -
Audio buffer size as a root cause - buffer size influences how quickly audio silence manifests after the lock is held, but does not affect whether the deadlock occurs.
Many thanks in advance for any help you can give. I’m happy to provide anything else useful for reproducing or diagnosing.
Wayne B.
Sample files are in this folder on Google Drive: