Re: Two Audio Units with the same View class. Only one shows in DAW.
Re: Two Audio Units with the same View class. Only one shows in DAW.
- Subject: Re: Two Audio Units with the same View class. Only one shows in DAW.
- From: Brian Willoughby <email@hidden>
- Date: Mon, 27 Nov 2017 23:13:53 -0800
Hi Jeff,
You mention that Carbon has a flat namespace, but it's important to note that
Cocoa has a flat namespace, too.
Languages like C and C++ use functions, which are linked by address. Loading
the same C or C++ code twice should probably only update the function
addresses, and if the new code is compatible with the old code then nothing
should break. It might be wasteful to load the same code twice, but it's a
simpler process that definitely overwrites any previous addresses during the
dynamic linking.
Objective C uses methods, which are looked up in a hash table by the runtime
rather than by following a linkable address. When dynamically loading a bundle,
such as an AudioUnit, the Objective C runtime adds information about all of the
methods in the bundle, whether they be category methods for existing classes or
instance methods for entirely new classes. I've never investigated the
consequences of loading the exact same classes twice, but I wouldn't be
surprised that the Objective C runtime gets confused when the second copy of
the same class gets loaded into its data structures. We already have warnings
about category methods, because the runtime does not make any guarantees if
there is more than one category method override in a collection of multiple
bundles. Similarly, I would expect that loading the same class twice is also
"not supported" by the runtime. Granted, the Objective C runtime has changed
many times over the years, particularly with ObjC2, and some of the most
dangerous features have been deprecated, but this still seems like going beyond
what is supported.
The AudioUnit documentation from Apple - what little there is - is plainly
explicit that each plugin must use a unique class name for its Cocoa UI.
Violating this requirement results in unpredictable results because it is
unsupported. You need to avoid having multiple plugins with the same ObjC
classes in them.
I'm actually surprised that Live does not call
GetProperty(kAudioUnitProperty_CocoaUI) for your second plugin. Without
accessing that property, Live should have no way of knowing anything about the
Cocoa UI, whether it's functional or not. You mention that no breakpoints in
-uiViewForAudioUnit:withSize: are hit, and that makes total sense, because that
is Objective C code in a class that has potentially been mangled to the point
of being inaccessible.
Are you absolutely certain that GetProperty(kAudioUnitProperty_CocoaUI) is not
being called on the second instance of your plugin? More importantly, are both
of your plugins sharing the same Manufacturer, Type and SubType? If they do not
have unique Manufacturer/Type/SubType identifiers, then Live is correct to
assume that the second instance is identical to the first in terms of the ObjC
information, even though the actual runtime information may have been mangled
enough that those classes no longer are accessible. Note that you cannot merely
change the Info.plist, because the Manufacturer/Type/SubType information is
also complied into the binary.
You probably need to find some way to make sure that the Cocoa UI bundle is not
loaded more than once. That means you probably cannot copy the CocoaUI bundle
into every plugin, but instead need to make sure that it's only part of one
bundle. Seems like your wrapper could be a separate plugin that provides the
generic UI, while all wrapped units would not have their own CocoaUI bundle
inside. Instead, wrapped plugins could refer to the CocoaUI for the wrapper.
Then again, I don't know whether your wrapper is installed separately, since
that might be confusing for users.
Brian Willoughby
On Nov 27, 2017, at 2:59 PM, Jeff McClintock <email@hidden> wrote:
>
> Hi All,
>
> I've written a wrapper to host my (non-AU) plugins in Audio Units.
>
> How it works is I built a single AU component (the "wrapper"), each target
> plugin is placed in a copy of the AU wrapper bundle, and I edit the wrappers
> "Info.plist" file to create (what looks like) a unique AU. My wrapper then
> forwards all AU function calls to the target plugin ("wraps" it).
>
> This all works pretty well until I load two different wrapped plugins into
> Ableton Live. Both plugins pass auval, both function OK as far as audio
> processing, but I can only open the view of the first plugin loaded. The
> other plugin refuses to show its view.
>
> Now, I realize Carbon has a "flat namespace" and auval warns me that "Class
> 'SynthEditPluginCocoaView_1344' is implemented in (both components). One of
> the two will be used. Which one is undefined."
>
> Correct me if I'm wrong, but I figured since both binaries are identical,
> then both View classes are identical and it doesn’t matter that Cocoa will
> use the same view class for both AUs.
>
> I placed breakpoints in the plugins, in the first plugin instance, Live calls
> GetProperty(kAudioUnitProperty_CocoaUI) and displays the view, in the second
> plugin, Live does not call this method, and does not instantiate the view
> class nor hit any breakpoints in the [uiViewForAudioUnit: withsize] creation
> function. It's like Live simply does not try to open the view.
>
> If I change my view class's name to make it unique, then rebuild and apply
> the new wrapper to one of the two plugins, then both plugin views open OK. So
> clearly there is some problem with having the same Cocoa class name in two
> plugins. I just don't understand why this is a problem? (when the classes are
> identical).
>
> Note: This wrapper is intended for non-techical end-users, I wish to avoid
> having to rebuild the wrapper for each target "wrapped" plugin.
>
> Any hints appreciated.
>
> Jeff McClintock
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden