There’s a severe issue with the current implementation in aucocoaview.mm.
Imagine you have two AUv2 wrapped plugins, Plugin 1 (e.g. EQ) and Plugin 2 (e.g. a Compressor) which both use the same auwrapper.a library and thus sharing the same SMTG_AUCocoaUIBase_CLASS_NAME macro imported from aucocoaclassprefix.h.
Now consider the following scenario:
Load Logic (or any other AU host of your choice)
Instanciate Plugin 1 (EQ) → GUI shows up fine
Instanciate Plugin 2 (Compressor) → GUI fails to open, in some hosts you’ll see the generic view (sliders etc.)
Restarting Logic and then instanciating Plugin 2 (Compressor) in step 2. first will bring up Plugin 2’s GUI but not Plugin 1’s GUI in step 3. It fails the same way when more then two plugins are involved. Only instances of first plugin that is loaded will bring up their GUI.
Some further debugging revealed that the host will successfully query the CocoaUI factory class name via AUWrapper::GetProperty() → kAudioUnitProperty_CocoaUI in all cases but only in the plugin that is instanciated first the host will call into [SMTG_AUCocoaUIBase_CLASS_NAME (NSView*)uiViewForAudioUnit:(AudioUnit)inAU withSize:(NSSize)inPreferredSize].
I tried rebuilding auwrapper.a with a different SMTG_AUCocoaUIBase_CLASS_NAME macro and then relinked Plugin 2 (Compressor) and voilá, both plugins will bring up their GUI just fine. This hasn’t been the case in VST SDK v3.7.1, so I assume it has to do with the dynamic ObjCClassBuilder() mumbo jumbo that has been added along the way and which I don’t see any benefit in, because plugins from the same batch will have a common AUCocoaUIBase implementation with its unique name and thus it doesn’t matter which plugin gets to load the implementation first without running into clutter, no?
Please fix this ASAP, the current state is basically useless for production builds.
okay, please allow me a couple of questions and comments:
Why was it changed in the first place? In order to remove the “SMTG_CocoaAUViewXYZ class is implemented in both library A and library B. Which one will be used is undefined.” message?
If so I don’t think that’s a very good reason at all given that the underlying code is identical so the warning doesn’t really matter IMO. 2. I haven’t fully grasped why it doesn’t work anymore? Can the auwrapper implementation be patched to behave in the old way which has worked fine for years?
So I see smtg_target_add_auv2() creates a new namespace macro and we’re supposed to recompile the auwrapper files along with our wrapped plugin implementation, just so the Cocoa view wrapper has it’s own mangled labels for its AUCocoaView classes? Frankly, I don’t see the real benefit when the generated code is identical and having a precompiled static auwrapper lib seemed very elegant in that regard.
Thanks.
EDIT: I finally understood why this is happening. It’s the CFBundleRef bundle = GetCurrentBundle (); portion in line 1762 of auwrapper.mm which always points the host to the current plugin bundle which doesn’t implement its unique version of SMTG_AUCocoaUIBase_CLASS_NAME unless it’s “remangeled” through a recompile using the smtg_target_add_auv2() rule which generates a new version of aucocoaclassprefix.h.
So it can easily be patched by using the old way which works via
which takes whichever random bundle was loaded first containing the -mind you - same implementation of SMTG_AUCocoaUIBase_CLASS_NAME, but which works - perhaps producing the aforementioned warning on the system console which I think can be ignored due to the mentioned reasons.
Would it be possible to simply revert it to the above segment which will work in both cases, i.e. the old fashioned, “shared” way as well as the new way in which each target has it’s own namespace for the Cocoa view wrapper implementation?
Hi,
we had many bug report for using the same name for the view and we needed to move away from Ruby for generating the unique class name. In this context we decided to simplify the setup to generate an AU (because this was the biggest issue for most people). And the solution is to use the new cmake function.
I checked your proposal, but it does not work. Did you successfully build the SDK AU examples and did these examples show the UI in Garageband with your change?
Yes, here’s what I just did in order to make sure it does work:
Download and unzip the SDK 3.7.7 zip archive from the Steinberg site.
Place the CoreAudio / AudioUnit Framwork under vst3sdk/external.apple.coreaudio
Configure SDK via CMake → Generate from vanilla configuration and open Xcode project
Comment out lines 2580 - 2583 in auwrapper.mm as suggested by you
Apply the aforementioned patch in line 1762, i.e. replace: CFBundleRef bundle = GetCurrentBundle (); by const char* image = class_getImageName (objc_getClass (SMTG_MAKE_STRING(SMTG_AUCocoaUIBase_CLASS_NAME))); CFBundleRef bundle = GetBundleFromExecutable (image); NOTE: Please make sure to insert the correct class name macro SMTG_AUCocoaUIBase_CLASS_NAME as an argument to SMTG_MAKE_STRING() here!
Build again-au and noteexpressionsynth-au targets
Make sure there are no old builds of these plugins in /Library/Audio/Components as the build will place its own symlinks in ~/Library/Audio/Components
Start GarageBand create a blank session containing an audiotrack as well as an software instrument track
Instanciate again and notexpressionsynth on the respective tracks
Click on the little insert slots → GUIs will come up (see screenshots)
This was tested on the following setup:
Garageband 10.4.7
macOS Ventura 13.1
Apple MBP M1 (2020)
Thanks Ray,
I checked it out again today and now it worked. Sorry, I don’t know what went wrong last week.
I’ve added this fix so it will be part of the next update.