AudioUnit synth: Wrong channel layouts reported by auval when using isBusesLayoutSupported

Hi!

I am observing a discrepancy between the channel configurations I allow using isBusesLayoutSupported and the channel layouts reported by auval.
I started with a blank audio plugin project for investigating the issues I’m having. The plugin is a synth with MIDI input, I’m using JUCE 5.1.1.

I want to have one output bus which supports only Quadraphonic or 5.1. auval reports more/different configurations though, and I can’t figure out why.

Processor c’tor:

ChannelConfigTestPluginAudioProcessor::ChannelConfigTestPluginAudioProcessor()
     : AudioProcessor (BusesProperties().withOutput ("Output", AudioChannelSet::quadraphonic(), true))
{
}

isBusesLayoutSupported:

bool ChannelConfigTestPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
    if (   layouts.getMainOutputChannelSet() != AudioChannelSet::quadraphonic()
        && layouts.getMainOutputChannelSet() != AudioChannelSet::create5point1())
        return false;
    
    return true;
}

auval output (excerpt - everything passes):

FORMAT TESTS:

Reported Channel Capabilities (explicit):
      [0, 4]  [0, 6]  

No Input, Output Chans:
0-1   0-2   0-4   0-5   0-6   0-7   0-8
            X           X                 

# # AudioChannelLayouts (6), Output Scope:
ChannelLayout is Writable: T
The Unit publishes the following Channel Layouts:
  0x790006, 0x6C0004, 0x7A0006, 0x7B0006, 0x7C0006, 0x840004, 

Is Audio Channel Layout Available:
Mono    Stereo  Binau.  AU_4    Ambi.   AU_5    AU_5_0  AU_6    AU_6_0  AU_7_0  AU_7_0F AU_8    AU_5_1  AU_6_1  AU_7_1  AU_7_1F 
                        X       X                                                                       X       X                               

So, auval is telling me that Ambisonics, 6.1 and 7.1 are supported. Quad is correct. No checkmark at 5.1.
I also observed that when I try to instantiate the plugin using aulab on a 5.1 track, it only offers me the 4 channel configuration.

As a sanity check I tested with the old channel config API as well (providing a list of possible in/outs in projucer). This works as expected, but lacks the speaker configuration info, so I’d really prefer to use the new API.

Maybe anyone here can shed some light on that?
Thanks!

PS: Great Job on JUCE 5.1.1 :slight_smile:

Ok thanks for the bug report. This is now fixed on develop with commit 0fd1a69.

The bug was triggered by what I think is a compiler bug (or at least a debugger bug) :frowning: (but I would love to be proven wrong). It’s triggered when trying to initialise CoreAudio’s AudioChannelLayout with braces initialisers like so:

AudioChannelLayoutTag someTag = kAudioChannelLayoutTag_Stereo
AudioChannelLayout layout {someTag}; 

Interestingly, trying to step over or into the above line with the debugger makes the debugger just leave the current function :open_mouth: - even when I try executing this in some standalone code like a console application. So I’m not sure exactly what code clang is producing for that line - but it’s definitely not leading to the desired results.

In any case, simply replacing the above with the following code:

AudioChannelLayoutTag someTag = kAudioChannelLayoutTag_Stereo
AudioChannelLayout layout;
layout.mChannelLayoutTag = someTag;

completely fixes the issue?!?.
 

Just for completeness, here is the definition of AudioChannelLayout in Apple’s headers:

struct AudioChannelLayout
{
	AudioChannelLayoutTag       mChannelLayoutTag;
	AudioChannelBitmap          mChannelBitmap;
	UInt32                      mNumberChannelDescriptions;
	AudioChannelDescription     mChannelDescriptions[1]; // this is a variable length array of mNumberChannelDescriptions elements

#if defined(__cplusplus) && CA_STRICT
public:
	AudioChannelLayout() {}
private:
	//  Copying and assigning a variable length struct is problematic so turn their use into a
	//  compile time error for easy spotting.
	AudioChannelLayout(const AudioChannelLayout&);
	AudioChannelLayout&         operator=(const AudioChannelLayout&);
#endif

};
typedef struct AudioChannelLayout AudioChannelLayout;
1 Like

I wonder if it’s related to the fact that this is a C struct…? If it was C++ I’d have expected a compiler warning/error when you use a braced initialiser that only specifies the first member.

2 Likes

According to the C++ standard that shouldn’t matter:

If the number of initializer clauses is less than the number of members or initializer list is completely empty, the remaining members are initialized by their default initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.

OK - false herring. It seems that Apple has silently upgraded auvaltool. Due to macOS’ system integrity protection, I keep a copy of auvaltool in /usr/local/bin for debugging - which was the older version.

At one point, I turned off system integrity protection and so some of my test projects use the auvaltool in /usr/bin and some of them use the one in /usr/local/bin.

Nevertheless, the debugger certainly doesn’t like the braces initialiser as it doesn’t seem to be able to step over or into it. That just added to confusion.

Now to the real bug: the auvaltool is doing something really confusing. If you look at the output of the old auvaltool it would look like this:

# # AudioChannelLayouts (6), Output Scope:
ChannelLayout is Writable: T
The Unit publishes the following Channel Layouts:
  0x790006, 0x6C0004, 0x7A0006, 0x7B0006, 0x7C0006, 0x840004, 

Is Audio Channel Layout Available:
Mono    Stereo  Binau.  AU_4    Ambi.   AU_5    AU_5_0  AU_6    AU_6_0  AU_7_0  AU_7_0F AU_8    AU_5_1  AU_6_1  AU_7_1  AU_7_1F 
						X                                                                       X                               

Current Format:AudioStreamBasicDescription:  4 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved
Current Format Tag = 0x6C0004, New Format Tag = 0x6C0004, Successsful

Current Format:AudioStreamBasicDescription:  4 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved
Current Format Tag = 0x6C0004, New Format Tag = 0x790006, Success - did not reset format with mis-matched layout

First of all, auvaltool begins with showing you a list of all the layouts in hexadecimal (0x790006, 0x6c0004, 0x7a0006, 0x7b0006, 0x7c0006, 0x840004). The least significant 16 bits are the number of channels in the layout, so all the tags that the AU reports are 4 and 6 channel layouts. In fact, if you look them up, this is exactly what the AU should report as the 6-channel layout tags are all the same layout (5.1 Surround) but with different speaker ordering. The same is true for the 4-channel layouts.

auvaltool then prints this “Mono Stereo Binau. AU_4…” list with crosses or no-crosses. These layouts are the more common layouts (and speaker ordering) used with AudioUnits. Up until today, I thought this list was really just a human-readable subset of the layout tags reported above (the hexadecimal numbers.

Then auvaltool actually tries setting the supported, most common AU layouts. You can see how auvaltool will try to only set those layouts that were marked with the x. This all makes sense.

Now look at the output of the new auvaltool:

# # AudioChannelLayouts (6), Output Scope:
ChannelLayout is Writable: T
The Unit publishes the following Channel Layouts:
  0x790006, 0x6C0004, 0x7A0006, 0x7B0006, 0x7C0006, 0x840004, 

Is Audio Channel Layout Available:
Mono    Stereo  Binau.  AU_4    Ambi.   AU_5    AU_5_0  AU_6    AU_6_0  AU_7_0  AU_7_0F AU_8    AU_5_1  AU_6_1  AU_7_1  AU_7_1F 
						X       X                                                                       X       X                               

Current Format:AudioStreamBasicDescription:  4 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved
Current Format Tag = 0x6C0004, New Format Tag = 0x6C0004, Successsful

Current Format:AudioStreamBasicDescription:  4 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved
Current Format Tag = 0x6C0004, New Format Tag = 0x790006, Success - did not reset format with mis-matched layout

Everything is the same except for where auval puts it’s crosses - which is just entirely confusing. First of all, the hex numbers are exactly the same. Specifically, the number of channels in those layouts are either 4 or 6. Yet, auvaltool still comes to the conclusion that the AU somehow supports AU_7 (which has 7 channels). But to confuse things even further, auvaltool then proceeds to only test the quadrophonic and Surround 5.1 layout?!? But in the step before it thought that the surround 5.1 layout isn’t even supported.

In any case, Logic does not seem to be affected. All though the auval result will be wrong, Logic Pro will still allow you to load it onto a 5.1 and quadrophonic track only.

I haven’t gotten around to testing again, but I also stepped through JUCE and Apple code up to the point where it looked like the format mapping JUCE<->AU-tags is absolutely correct. I added some printfs showing me the hex IDs as well as the mapped JUCE channel sets, plus what’s accepted and what’s rejected. All of this looked correct.

It is worth noting that the somewhat old Au Lab (last version from early 2012) appears to be behaving unpredictably and unreliably, sometimes the plugin doesn’t even show up even though there wasn’t any change. This initially led me to the conclusion that something might be wrong, the plugin not working in Au Lab plus weird auval output.

In the end, I bought Logic (I tried to avoid it, but well…), and indeed it appears to work correctly and as configured.

Bottomline seems to be that neither auval nor aulab can be trusted with regards to channel configurations…
Thanks a lot for investigating this, one would expect those developer tools to be more reliable, since they claim a somewhat authoritative role. I think it is safe to say now that the issue lies with auval :wink:

I’ll try to grab the old version of that tool somewhere.

Awesome support, keep up the good work.

OK - I’ve filed a bug report with Apple. The bug id is 33936533. I’ll keep this post updated.

Update: Apple have confirmed that this is a bug in a recent auval update. I’ll keep adding updates to this post.

Update: This bug is fixed. See post below!

2 Likes

Apple engineering has informed us that this bug is now fixed with macOS High Sierra 10.13.2 beta and will be released soon. I’ve tested it and can confirm that it is indeed fixed.

1 Like