AULab problem when reloading project


#1

Since I updated to JUCE tip I see this problem:

 

When I save a session in AULab with a JUCE plugin and try to reopen the file things go wrong and I get "The document "test.trak" could not be opened.". This happens with the JUCE demo plugin as the only plugin instanced. I can successfully create a new plugin instance however.

AULab is very convenient as a development host (can autoload a session on launch and does play nice with the debugger). This breaks it totally and is probably a bad sign as AULab is the official reference host. Some recent change somehow broke restoring the AULab session.

Am I the only one seeing this issue? I tested on two different macs, both running yosemite.


#2

"test.track" isn't a file that anything in juce would have created.. If it's one of your own files then maybe look at whatever code creates it - perhaps you had a mistake in your code that you used to get away with, but which is now being shown up by unrelated changes to the library code.


#3

test.trak is the name of a test session I made in AULab. None of my own code is involved in this problem.

 

My steps are

-Launch AULab

-create a Juce demo plugin instance

- save the sessions as "Test.trak"

- quit and relaunch AULab

- open "Test.trak" in AULab => problem happens.

 

If this happened only on one machine or with any of my code I wouldn't suspect a JUCE change has lead to the problem. This happens with the JUCE tip plugin example without any modifications.


#4

I went through the latest JUCE commits and the problem starts happening once "Add AudioUnit Multi-Output support" was added.

Once that code is in, sessions saved inside AULab cannot be loaded anymore. Old sessions still load fine. I believe it messes up something with AU channel configurations/mappings.

I believe the JUCE demo plugin does not use multichannels, but this change still breaks it for AULab.

 


#5
​
    UInt32 GetAudioChannelLayout (AudioUnitScope scope,
                                  AudioUnitElement element,
                                  AudioChannelLayout *outLayoutPtr,
                                  Boolean &outWritable)
    {
        if (element == 0)
        {
            outWritable = true;
            if (scope == kAudioUnitScope_Output)
            {
                return static_cast<UInt32> (findNumOutputChannels());
            }
            else if (scope == kAudioUnitScope_Input)
            {
               #if JucePlugin_IsSynth
                return 0;
               #else
                return static_cast<UInt32> (findNumInputChannels());
               #endif
            }
        }
        return JuceAUBaseClass::GetAudioChannelLayout(scope, element, outLayoutPtr, outWritable);
    }

This is the added code from that commit. IMHO it is defective in a number of ways and I'm surprised the built AUs do work at all. GetAudioChannelLayout() is not supposed to return the number of channels, but the number of bytes it intends to write to outLayoutPtr.

If outLayoutPtr is not null, it's required to fill this number of bytes in the buffer which this code does not.


#6

Thanks for reporting this. I'll have a look.


#7

Thanks for the quick action. Unfortunately it still doesn't work in AULab. I don't easily see what's wrong now, but I see AULab calls the method only when storing a session. I understand this method was added for Multi-Out AUs which I don't need, but the change still breaks my builds for mono/stereo plugins.. Maybe for non-multi-out, it could just revert to the old behaviour?

What is the purpose of this code? Now it's returning an audioChannelLayout that has "unused" as a name of "alloff" as flags for each channel.

The apple description of the unused thing is:

    kAudioChannelLabel_Unused                   = 0,            // channel is present, but has no intended use or destination


 I can see how that could confuse a host if it is returned for all channels.

AULab is probably one of the few hosts that even looks at these channel layouts and I guess that's why things are going awry.

 


#8

I believe I found a bug in the code in the meantime. I think this method is not supposed to return multiple AudioChannelLayout structs, but just one with the right number of channels. It's a variable length struct (= very bad style IMHO).

I tried to come up with working code, but no success so far. From past experience with creating an AU wrapper I believe this method is best left alone unless it's really absolutely needed. This is even recommended by Apple. If you look at the apple code there is a description of what the method should do and I don't think this is implemented correctly now. 

Return true for writable probably means the plugin can reconfigure for any layout. And the comment says the plugin is expected to return the currently used ACL, not create one from scratch. So if a plugin supports multiple layouts (such as mono/stereo), it probably shouldn't return the same thing for every call.

from AUScopeElement.cpp:


 

// As the AudioChannelLayout can be a variable length structure
// (though in most cases it won't be!!!)
// The size of the ACL is always returned by the method
// if outMapPtr is NOT-NULL, then AU should copy into this pointer (outMapPtr) the current ACL that it has in use.
// the AU should also return whether the property is writable (that is the client can provide any arbitrary ACL that the audio unit will then honour)
// or if the property is read only - which is the generally preferred mode.
// If the AU doesn't require an AudioChannelLayout, then just return 0.

UInt32 AUIOElement::GetAudioChannelLayout (AudioChannelLayout *outMapPtr, Boolean &outWritable)
{
    return 0;
}


#9

Hi pflugshaupt,

Yes, I've realized this and fixed the AU layout code in the meantime (sorry for the git noise). Still no success for AULab. So, I've added the fallback to the old code if the plug-in is only mono or stereo. Therefore, AU should be able to load/restore projects that use only mono/stereo channels. I've been trying to fix the multi channel support for weeks but I still feel it needs more work. I'll revisit it once I have more time.

Fabian


#10

Thanks! I can confirm the fallback works for me. 

I know this is very tricky stuff and different hosts handle multi-channel AUs quite differently so good luck finding a generally working implementation. I think a few years ago when I wrote my own AU wrapper, I didn't even use that GetAudioChannelLayout method. I do remember creating workarounds for different hosts because memory management of the additional channels was handled differently by different hosts. Hopefully the situation has improved in the meantime.

Maybe the AU standard is a bit overambitious with handling surround correctly leading to complicated setup stuff like this that ends up not being supported by 3rd parties anyways.

 


#11

The new JUCE 4.1 unfortunately partially brings back this issue with AULab.. Once I updated JUCE 4.1 and rebuilt my plugins I could no longer load old sessions where the plugins didn't return channel layouts. If I create a new session things seem fine so far, but it's still a bit of a problem as it would break released plugins in AULab if those were rebuilt with Juce 4.1. Considering AULab is the technical reference host this either is a bug in AULab or something is not 100% right the layouts. 

Could you bring back the fallback for non-multi-bus plugins?

 


#12

Also auval does produce a warning regarding the busses/channel formats now:


AU Validation Tool
Version: 1.6.1a1 
(..)
FORMAT TESTS:
Reported Channel Capabilities (explicit):
      [1, 1]  [1, 2]  [2, 2]  
Input/Output Channel Handling:
1-1   1-2   1-4   1-5   1-6   1-7   1-8   2-2   2-4   2-5   2-6   2-7   2-8   4-4   4-5   5-5   6-6   7-7   8-8
X     X                                   X                                                                       
ca_require: ValidFormat(inScope, inElement, newDesc) InvalidFormat /JUCE/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp:870

#13

Hunting for a fix I figured out some stuff.. The auval warnings have been there before. They show up for any plugin built with JUCE if it's built in debug configuration. There are many more and most of them are probably mostly harmless. But unrelated to the problem I see in AULab.

And now I see another plugin I worked on doesn't have the issue. I'll post again once I figure out more clearly what's going on.


#14

I personally think this is an issue with AULab. However, I've implemented the AU wrapper in such a way that the layout tag stuff is ignored if your setPreferredBusArrangement method does not care about the detailed layout. For example, the AU wrapper will recognize if your setPreferredBusArrangement is only interested in the number of channels, i.e. ignoring the detailed layout of the supplied channel set:

bool setPreferredBusArrangement (bool isInputBus, int busIndex, const AudioChannelSet& preferredSet)
{
   const int numChannels = preferredSet.size();
   // Do something with numChannels, isInputBus and busIndex only - ignoring the detailed layout of preferredSet...
   .
   .

}

In this case the LayoutTag related AU methods simply return 0 and the AULab bug won't be triggered. Does this make sense?


#15

Yep I saw that. My plugin in progress back then didn't load even as I overrided everything to just return 0. I have no more issues in the meantime, maybe it was just some weird bad builds. There is definitely a bug in AULab about this, but I agree you worked around it, so thanks!