Problems with AU plugins when loading Edit on background thread

I’m hitting this assertion when loading an Edit containing an external AU plugin. The assertion seems to be hit for every parameter.
@dave96 I’m wondering if you’re seeing the same issue in Waveform?
If not, I’m probably doing something wrong. Are there any gotchas when loading Edits on another thread? I saw here that it’s what you’re doing in Waveform.
I’m currently passing a custom edit loader object to the BackgroundJobManager, which in turn results in a call to loadEditFromFile (Engine&, const juce::File&, Edit::EditRole role = Edit::forEditing) on a background thread. When stepping through the debugger I can see the assertion is hit before this function returns, so I’m not really sure what to do differently on my part.

I’m on the tip of develop and MacOS 11.6.8.
And I’ve tested 4 different AU plugins from different manufacturers and they all do this. I haven’t reproduced this with any VST3’s.

Can you post the call stack when the assertion gets hit please?

tracktion::engine::AutomatableParameter::AutomationSourceList::AutomationSourceList(const tracktion::engine::AutomatableParameter &) tracktion_AutomatableParameter.cpp:358
tracktion::engine::AutomatableParameter::AutomationSourceList::AutomationSourceList(const tracktion::engine::AutomatableParameter &) tracktion_AutomatableParameter.cpp:357
std::make_unique<…>(const tracktion::engine::AutomatableParameter &) memory:2099
tracktion::engine::AutomatableParameter::getAutomationSourceList() const tracktion_AutomatableParameter.cpp:1117
tracktion::engine::AutomatableParameter::hasActiveModifierAssignments() const tracktion_AutomatableParameter.cpp:753
tracktion::engine::ExternalAutomatableParameter::handleAsyncUpdate() tracktion_ExternalAutomatableParameter.h:340
juce::AsyncUpdater::AsyncUpdaterMessage::messageCallback() juce_AsyncUpdater.cpp:34
juce::MessageQueue::deliverNextMessage() juce_MessageQueue_mac.h:81
juce::MessageQueue::runLoopCallback() juce_MessageQueue_mac.h:92
juce::MessageQueue::runLoopSourceCallback(void *) juce_MessageQueue_mac.h:100
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ 0x00007fff209c8cec
__CFRunLoopDoSource0 0x00007fff209c8c54
__CFRunLoopDoSources0 0x00007fff209c8a36
__CFRunLoopRun 0x00007fff209c73fc
CFRunLoopRunSpecific 0x00007fff209c69bc
RunCurrentEventLoopInMode 0x00007fff28c0fa83
ReceiveNextEventCommon 0x00007fff28c0f7e5
_BlockUntilNextEventMatchingListInModeWithFilter 0x00007fff28c0f583
_DPSNextEvent 0x00007fff231cfb12
-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] 0x00007fff231ce2e5
-[NSApplication run] 0x00007fff231c0609
juce::MessageManager::runDispatchLoop() juce_MessageManager_mac.mm:337
juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:265
juce::JUCEApplicationBase::main(int, const char **) juce_ApplicationBase.cpp:243
main Main.cpp:254
start 0x00007fff208ebf3d

And the async update is triggered here:

tracktion::engine::ExternalAutomatableParameter::parameterValueChanged(int, float) tracktion_ExternalAutomatableParameter.h:304
juce::AudioProcessorParameter::sendValueChangedMessageToListeners(float) juce_AudioProcessor.cpp:1596
juce::AudioUnitPluginInstance::eventCallback(const AudioUnitEvent &, float) juce_AudioUnitPluginFormat.mm:2086
juce::AudioUnitPluginInstance::eventListenerCallback(void *, void *, const AudioUnitEvent *, unsigned long long, float) juce_AudioUnitPluginFormat.mm:2124
AUEventListener::MessagesAreAvailable() 0x00007fff21ce875d
invocation function for block in CAEventReceiver::Impl::timerFired() 0x00007fff21ce8c2a
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ 0x00007fff209c8882
__CFRunLoopDoBlocks 0x00007fff209c8733
__CFRunLoopRun 0x00007fff209c740d
CFRunLoopRunSpecific 0x00007fff209c69bc
RunCurrentEventLoopInMode 0x00007fff28c0fa83
ReceiveNextEventCommon 0x00007fff28c0f7e5
_BlockUntilNextEventMatchingListInModeWithFilter 0x00007fff28c0f583
_DPSNextEvent 0x00007fff231cfb12
-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] 0x00007fff231ce2e5
-[NSApplication run] 0x00007fff231c0609
juce::MessageManager::runDispatchLoop() juce_MessageManager_mac.mm:337
juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:265
juce::JUCEApplicationBase::main(int, const char **) juce_ApplicationBase.cpp:243
main Main.cpp:254
start 0x00007fff208ebf3d

Ok, that’s odd that the parameters would be sending change messages straight after construction but I guess that case needs to be handled.

I guess the simplest fix would be this in ExternalAutomatableParameter:

if (! getEdit().isLoading() && hasActiveModifierAssignments())
    return;

Does that tweak fix it for you?

I’m not sure if that’s the best approach though as it might mean the parameter value gets out of sync with that of the plugin…

Yes that does for me!

Ok, I’ll have to think a bit about this before pushing that fix.

1 Like