Host Development: How To Stop a Transport


#1

With my Juce based host, I seem to be having occasional issues with stopping the transport properly. Every now and then, after a stop, I see a NI Reaktor 5 plugin sending constant -1.0 for a certain span of time, resulting in a harsh digital “phooomp!”, almost blasting my speakers. The plugin then becomes silent (input still indicated, but no output). Other plugins play nicely. I’ve received a report of EWQL PLAY on Windows also causing trouble after STOP, but could not reproduce that.

So I wonder how a proper implementation of a host transport is supposed to look like. What my transport currently does:

  1. Stream an AudioProcessorGraph hooked into an AudioProcessorPlayer
  2. Supply the graph with an AudioPlayhead that is incremented/modified in advance to each render call
  3. On STOP, playhead.isPlaying = false and playhead.timeInSeconds, playhead.ppqPosition are no longer incremented

I wonder if I am missing something. Should timeInSeconds/ppqPosition continue to be incremented with each render call, even if the transport is stopped? Am I seeing a threading issue, i.e. the render callback possibly suspended/blocked for some reason?

Should I put “transport commands” (start, stop, locate, tempo change, etc) in a queue and have the render callback execute these as part of the render loop himself? (currently I have a lock around the playhead).

This sort of issue is extremely difficult to debug. How did you implement your transport? Any hint is much appreciated!


#2

My transport doesn’t use AudioPlayhead but instead a custom Time class. We have an early version so the pluggins aren’t synchronized with the trasnport yet but the rest is exactly the same as your version and we don’t have such problems, so it’s probably a problem with AudioPlayhead/the way you use it …


#3

I just downloaded the Reactor 5 Player and tried the Factory Collection. It seemed to act a bit strange in my host but then I tried it in Logic and it did the same thing there. There were no sound issues but the space drone thing doesn’t stop when the transport was stopped and the meter for Newscool appears to go to full when transport is stopped (the meter in the module itself, not the main “out” meter). Anyway, from the limited testing my host seems ok with it.

I have a graph with a playhead, no queues, no locks on the playhead. I have a bool that I flip for play/stopped, time and ppqs are stopped when the transport is stopped. Time position is incremented in an audio callback which is ordered after the graph’s callback.


#4

Thanks for your quick responses. Looks like this might also be a Reaktor 5 bug. I’m seeing the quirks with R5’s FlatBlaster 2.0.2 (a multi-band finalizer).

My host can’t do without a AudioPlayhead, because I need clock/time sync for all hosted plugins.


#5

Update: Apple’s MultiBandCompressor AU shows the same behavior. Hence this is not a bug of the NI plugin. I’d rather suspect an issue with the AudioProcessorGraph, or the way I am using it :frowning:


#6

Yeah that seems strange, no issues with AUMultibandCompressor here. Is the graph being modified when stopped?


#7

No. Only the AudioPlayhead is modified. I’ll check whether the render call is delayed or suspended for some reason. Although I have no idea how to debug this yet.


#8

Update: The issue did not yet occur anymore after I changed the way transport commands are dispatched: I am now adding commands (START, STOP, LOCATE, TEMPO, …) to a fifo queue that is read and processed by the audio device callback thread as part of its render loop. This basically only modifies the AudioPlayhead and dependent sample counters (light weight).

Previously I was doing this on the message thread, temporarily locking the render callback. It seems obvious that this messed with something that was almost impossible to debug. I glad it works now :smiley: