Cocoa Flat Namespace - Audio Unit UI issues

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

Hey,

My contact with Audio Unit development is very recent. I have only done one plugin so far. Now I'm trying to generalize the common parts so I can easily make more plugins.

There is a warning on the top of all Cocoa files of the Audio Unit samples saying:

// It is important to rename ALL ui classes when using the XCode Audio Unit with Cocoa View template
// Cocoa has a flat namespace, and if you use the default filenames, it is possible that you will
// get a namespace collision with classes from the cocoa view of a previously loaded audio unit.

I think I have been facing myself with this issue now that I'm trying to generalize the common parts. For instance, I have the following two classes: IAuView, IAuViewFactory. I was trying to make something extend this classes by simply making something like:

Code: Select all

// XPTOAuView.h

#include "IAuView.h"

@interface XPTOView : IAuView
{

}

// XPTOAuViewFactory.h

#include "IAuViewFactory.h"

@interface XPTOView : IAuViewFactory
{

}
But this doesn't work. I think I'm crashing with the lack of profound knowledge of Cocoa. I'm thinking in a C++ style.

If I use IAuViewFactory to create the UI of the new plugin, the one I had already doesn't even open the Window so I think I'm feeling the pain of Cocoa flat namespace.

What is the solution for this problem? I don't want to replicate files with the same content every time I make a plugin. Why doesn't inheritance work on Cocoa? What am I doing wrong?

Post

sinosoidal wrote: What is the solution for this problem? I don't want to replicate files with the same content every time I make a plugin. Why doesn't inheritance work on Cocoa? What am I doing wrong?
Well, the global namespace is just retarded (welcome to the 1970s), but there's not much one can do about it. Just about the best solution is to use the C-preprocessor to prefix all your Objective-C classes with some plugin specific #define (or -D compiler flag).

Post

Hi,

Thanks for the quick reply. Is there any example you can point me out? I'm not sure about it.

Also, I'm not sure if the other problem I'm having will be solved with this as when I pass XPTOAuViewFactory to Audio Unit UI instantiation nothing happens which makes me believe that for some reason the class extension is not working properly.

Thanks!

Regards,

Nuno

Post

If don't want to use the facilities provided by your C++ compiler, note that the Obj-C runtime lets you create custom classes at runtime, you can then use an UUID to have some unique class name.

In Dplug we had no other choice than doing that: https://github.com/AuburnSounds/Dplug/b ... dow.d#L446

It's tricky as hell so better use the mystran's solution if you can.
Checkout our VST3/VST2/AU/AAX/LV2:
Inner Pitch | Lens | Couture | Panagement | Graillon

Post


Post

Thanks!

I will give it a look.

Regards

Nuno

Post

Thanks for this link! It helped a lot.

Regards,

Nuno

Post

Guillaume Piolat wrote:If don't want to use the facilities provided by your C++ compiler, note that the Obj-C runtime lets you create custom classes at runtime, you can then use an UUID to have some unique class name.

In Dplug we had no other choice than doing that: https://github.com/AuburnSounds/Dplug/b ... dow.d#L446

It's tricky as hell so better use the mystran's solution if you can.
We do the same for most our Cocoa classes, however I don't think it works for the Audio Unit View factory (not sure as we tried it a long time ago...), as the AUViewFactory class is loaded from the bundle using its name, which probably does not work for dynamically generated ObjC classes. Do you have a different experience?

Post

Blue Cat Audio wrote: We do the same for most our Cocoa classes, however I don't think it works for the Audio Unit View factory (not sure as we tried it a long time ago...), as the AUViewFactory class is loaded from the bundle using its name, which probably does not work for dynamically generated ObjC classes. Do you have a different experience?
I've already forgotten the specifics of this, but looking at our plug-ins there isn't the name of the AUViewFactory in the Info.plist.

Instead it does this when receiving the kAudioUnitProperty_CocoaUI opcode, this idea comes from Iplug: https://github.com/olilarkin/wdl-ol/blo ... U.cpp#L912:

Code: Select all

               case kAudioUnitProperty_CocoaUI: // 31
                {
                    if ( _client.hasGUI() )
                    {
                        *pDataSize = AudioUnitCocoaViewInfo.sizeof;
                        if (pData)
                        {
                            // View class generated and named here
                            const(char)[] factoryClassName = registerCocoaViewFactory(); 
                            CFBundleRef pBundle = CFBundleGetMainBundle();
                            CFURLRef url = CFBundleCopyBundleURL(pBundle);
                            AudioUnitCocoaViewInfo* pViewInfo = cast(AudioUnitCocoaViewInfo*) pData;
                            pViewInfo.mCocoaAUViewBundleLocation = url;
                            pViewInfo.mCocoaAUViewClass[0] = toCFString(factoryClassName);
                        }
                        return noErr;
                    }
                    else
                        return kAudioUnitErr_InvalidProperty;
                }
I'm afraid you would have to ask Cockos instead.
Checkout our VST3/VST2/AU/AAX/LV2:
Inner Pitch | Lens | Couture | Panagement | Graillon

Post

Yes, the kAudioUnitProperty_CocoaUI opcode is indeed the way to implement it. But from what I could see in the Github repository, they do use a static CocoaViewFactory which name is changed using a macro (VIEW_CLASS_STR).

If I remember well, the ObjC class loader will not be able to find classes that have been registered dynamically: the host will use the [NSBundle classNamed: ] method that returns only "static" classes.

Post

Because we compile a single binary for AU, VST2, VST3 and AAX (with all the different entry points of course), we can't prefix (unless I'm missing something). So we just brutally copy that binary for each plug-in API and patch it. Each Cocoa class has some identifier like UHE_COCOA_BLAHBLAH_ID_classname, which we find as plain ASCII string and overwrite with the plug-in name and API identifier. Afterwards we product sign, EDEN sign, product build, sign again.

Has worked for several years, doesn't seem to be an issue there.

Post

Blue Cat Audio wrote:Yes, the kAudioUnitProperty_CocoaUI opcode is indeed the way to implement it. But from what I could see in the Github repository, they do use a static CocoaViewFactory which name is changed using a macro (VIEW_CLASS_STR).

If I remember well, the ObjC class loader will not be able to find classes that have been registered dynamically: the host will use the [NSBundle classNamed: ] method that returns only "static" classes.
Now I remember this particular nightmare.
To create a CocoaViewFactory successfully it has to follow the AUCocoaUIBase protocol, else the host won't take it. However, from the client point of view this Protocol can't be found by name.

So just having the right methods is not sufficient, you also have to create a similar protocol, with the right signatures, that the host will mistake as the one it knows.

After a lot of trial and errors, this is what I came up with:
https://github.com/AuburnSounds/Dplug/b ... tory.d#L99

Works from OS X 10.7 to 10.13
Checkout our VST3/VST2/AU/AAX/LV2:
Inner Pitch | Lens | Couture | Panagement | Graillon

Post

Urs wrote:Because we compile a single binary for AU, VST2, VST3 and AAX (with all the different entry points of course), we can't prefix (unless I'm missing something). So we just brutally copy that binary for each plug-in API and patch it. Each Cocoa class has some identifier like UHE_COCOA_BLAHBLAH_ID_classname, which we find as plain ASCII string and overwrite with the plug-in name and API identifier. Afterwards we product sign, EDEN sign, product build, sign again.

Has worked for several years, doesn't seem to be an issue there.
I remember some GUI libraries that used to use a similar trick some time ago (can't remember the name though!). It should indeed work fine as long as they do not change the way ObjC class names are stored in binaries (which is very unlikely to happen).

Post

Guillaume Piolat wrote: Now I remember this particular nightmare.
To create a CocoaViewFactory successfully it has to follow the AUCocoaUIBase protocol, else the host won't take it. However, from the client point of view this Protocol can't be found by name.

So just having the right methods is not sufficient, you also have to create a similar protocol, with the right signatures, that the host will mistake as the one it knows.

After a lot of trial and errors, this is what I came up with:
https://github.com/AuburnSounds/Dplug/b ... tory.d#L99

Works from OS X 10.7 to 10.13
Maybe that was the issue, indeed. Can't remember what was exactly tried at the time, though!

Post

Just in case someone has the same problem in the future: the issue for us was not the AUCocoaUIBase protocol definition, but the fact that objective C classes generated at runtime have to be reported as defined by the main application bundle (and not the plug-in).

Post Reply

Return to “DSP and Plugin Development”