My own Logic Pro X bypass flag

Hello,
as I know Logic Pro X doesn’t support processBlockBypassed() so we can’t perform any action when Logic Pro bypass is clicked.

But I wonder if is following idea well or not:
I found out that when I click in Logic Pro bypass, it stops my processBlock. So I think there must be some way to check if processBlock is running or not (is there anything like that?).
If it’s true. I could just set the timer in my plugin, and in timerCallback always check if processorBlock() is running. And if it’s not running, just perform some action.

Is it good idea?

Of course it’s not elegant solution, but maybe it’s better than nothing?

But actually I have no idea how to check if processBlock is running. Is there flag or something like that?

You would have to save the flag yourself in your AudioProcessor. We actually do this check in our plugins, to clear out meters and such for hosts that do what Logic is doing (bypassing by not calling processBlock() anymore).

A simple way is to keep an atomic “count” variable in the processor and have a timer that continuously tries to decrement the count. That way we’d know fairly shortly that we’re in a “bypassed” state since our processBlock() method hadn’t been called for some time.

Every time processBlock() is called we bump the count up to the threshold value. For example, if you had a 0.25Hz timer and a count threshold of 4, it would take about 1 second of being bypassed to know. Obviously you would probably want this a bit faster but that’s the basic premise.

Sorry, not sure if I understand. So shoul I just call someAtomicInt++; in the processBlock(), and then check in the timerCallback() if someAtomicInt was changed? Something like that?

https://developer.apple.com/documentation/audiotoolbox/auaudiounit/1387545-shouldbypasseffect?language=objc ???

https://developer.apple.com/documentation/audiotoolbox/auaudiounit/1387545-shouldbypasseffect?language=objc ???

I have no idea how to use it. I tried to declare: @property(atomic) BOOL shouldBypassEffect;

And I get error, no matter if I declare it as a member of class (for example AudioProcessor) or as a global value.

Now I see it’s objective-C, but my plugin is in C++

In super basic terms (without an atomic):

void processBlock(...) {
    someInt = 4;
    ...
}

void timerCallback() {
    if (someInt <= 0)
    {
        isBypassed = true;
    }
    else 
    {
        someInt--;
        isBypassed = false;
    }
}

This way if you need to change something about your GUI while you’re bypassed you’ll be able to keep that state in a variable (bool isBypassed).

It works fine for updating GUI stuff, but you can’t do audio things (like a fade out) since Logic isn’t giving you any audio buffers to write into.

1 Like

Unfortunately in Logic you never get any state changes about being bypassed. We have a bypass parameter implemented in our plugins and it doesn’t get updated when Logic’s bypass is enabled

weird. I wonder if Apple Developer support is aware of this.

Just curious, have you guys created a plain Audio Unit project in Xcode and checked that this boolean flag Apple provides never gets updated by logic? or sticking strictly with JUCE’s callbacks?

This way if you need to change something about your GUI while you’re bypassed you’ll be able to keep that state in a variable ( bool isBypassed ).

That’s great solution. Thanks. Do you also have such smart solution for fade out/in when click bypass?

just check the state of that variable in your pluginProcessor and use a ramp to fade in/out your samples.

But that variable is changed after it’s bypassed so it’s to late

Hey,
I found out that if I have my treshold value bump in each iteration through buffer samples, like that:

void processBlock(buffer)
{
    for(int sample=0; sample<buffer.getNumSamples(); sample++)
    {
        myAtomicBypassTresh = 4;
        ....
    }
}

And I have timer set to 1 millisecond, my:

void timerCallback()
{
    if(myAtomicBypassTresh<0) bypass();
    else myAtomicBypassTresh--;
}

is sometimes faster than that loop. I mean that during processBlock() is running, my timerCallback() sometimes reaches bypass() for short moment. How is that possible? Is it because I use atomic? How to avoid that. But I want to reach my bypass() as fast as possible.

See above ^

Continuing with my previous post, you can’t do fade outs for hosts that do this hard bypass (aka hosts that will stop calling processBlock() and don’t call processBlockBypassed()). You aren’t getting any audio buffers to write into at that point so it’s always going to result in a hard audio cut.

If you need your GUI to update on bypass you can use the timer method, but you’d want it to be slower than 1ms otherwise you’ll run into the problem you described

Ok, thanks. I am not happy with that fact, but what can we do?

@matkatmusic, I have a breakpoint set here:

https://github.com/WeAreROLI/JUCE/blob/master/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm#L611

And it’s not getting hit when I bypass my plugin in Logic. Although if it was, it looks like processBlockBypassed() still wouldn’t get called because of this conditional (I have a dedicated bypass parameter):

https://github.com/WeAreROLI/JUCE/blob/master/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm#L1756


@pajczur submitting a bug report to Logic is probably the only thing (they may ask for an example plugin that demonstrates the behavior)

@jules @ed95 @fabian you guys should check out @TonyAtHarrison’s post above, and let us know if this is a known bug with Logic and JUCE.

2 Likes