Extending Juce support for Atmos beyond 7.1.2 channel set (including in Logic Pro via new layout tags)

Hi

Logic 10.7 recently added support for Atmos, and there are new channel layout tags to support this in CoreAudioBaseTypes.h. Can Juce be updated so that we can use this via the standard Juce AudioChannelSet channel configurations?

We would need Juce to go further than the existing 7.1.2 maximum (e.g. adding a create7point1point4, create7point1point6, etc), and to add awareness of Apple’s new kAudioChannelLayoutTag_Atmos_x tags (e.g. kAudioChannelLayoutTag_Atmos_7_1_4) which were introduced for macOS 10.15 Catalina so Logic can be made aware of plugin channel capabilities.

It would be good to be able to generally improve Juce’s understanding of beds higher than 7.1.2 as 7.1.4/6 / 9.x.y are becoming more widespread in Logic, Nuendo, Resolve, etc. Pro Tools is a little behind with a 7.1.2 maximum still, but it shouldn’t hold us back.

Thanks
Matt

1 Like

create7point1point4() exists but is not mapped to the new kAudioChannelLayoutTag_Atmos_7_1_4

I am about to test adding it and if successful will issue a PR.

Could you consider adding a create5point1point2 and create5point1point4 while you’re in there as both Nuendo and Logic can support those, also Nuendo can do a 7.1.6 option.

I am looking at those too. Currently I can’t find them in the CoreAudio Documentation.

https://developer.apple.com/documentation/coreaudiotypes/coreaudiotype_constants/1572101-audio_channel_layout_tags/

but I found them here:

the channel ordering is a minefield

I found the 5.1.4 ones in:
/Applications/Xcode-13.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/CoreAudioTypes.framework/Versions/A/Headers/CoreAudioBaseTypes.h

kAudioChannelLayoutTag_Atmos_5_1_2
kAudioChannelLayoutTag_Atmos_5_1_4

perfect - that’s really useful

especially as it includes the key to the abbreviations

1 Like

@reuk

I have just issued a pull request to add 7.1.4 support for AUs

the channel ordering seems to be following the logic of AudioUnit_7_0 but the tag is now:
kAudioChannelLayoutTag_Atmos

CoreAudioBaseTypes.h sets:
kAudioChannelLayoutTag_Logic_Atmos_7_1_4_A = kAudioChannelLayoutTag_Atmos_7_1_4

I was going to look at the other new layouts too as soon as I find time to test them:

kAudioChannelLayoutTag_Atmos_5_1_2              = (194U<<16) | 8,                       ///< L R C LFE Ls Rs Ltm Rtm
	kAudioChannelLayoutTag_Atmos_5_1_4              = (195U<<16) | 10,                      ///< L R C LFE Ls Rs Vhl Vhr Ltr Rtr
	kAudioChannelLayoutTag_Atmos_7_1_2              = (196U<<16) | 10,                      ///< L R C LFE Ls Rs Rls Rrs Ltm Rtm
	kAudioChannelLayoutTag_Atmos_7_1_4              = (192U<<16) | 12,                      ///< L R C LFE Ls Rs Rls Rrs Vhl Vhr Ltr Rtr
	kAudioChannelLayoutTag_Atmos_9_1_6              = (193U<<16) | 16,                      ///< L R C LFE Ls Rs Rls Rrs Lw Rw Vhl Vhr Ltm Rtm Ltr Rtr
1 Like

Thanks, I’ve added support here:

Please try out this change and let us know if you run into any problems.

Could a 7.1.6 be added while you’ve got the hood up? It would be beneficial for Nuendo.

It works fine on macOS 11.5.2 with XCode 13.1 but not on macOS 10.14.6 with XCode 11.0:

JUCE/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h:83:37: error: use of undeclared identifier 'kAudioChannelLayoutTag_Atmos_5_1_4
List { kAudioChannelLayoutTag_Atmos_5_1_4, { left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight } },

I’m not sure why it fails but are you sure of the MAC_OS_X_VERSION_10_15 here? This seems to require macOS 12.0 here, but I don’t know if it’s related.

Thanks, you’re absolutely right. It looks like kAudioChannelLayoutTag_Atmos_5_1_4 and kAudioChannelLayoutTag_Atmos_7_1_2 are only available on macOS 11.0 and up, while the other Atmos layouts are available on 10.15. I’ll fix that up shortly.

Yes, I’ve added that here:

1 Like

@reuk
just had a chance to test this. And for me, an AU using 7.1.4 does not produce an immediately usable channel order when used in LogicPro.

I think:

in juce_mac_CoreAudioLayouts.h - line 88:

{ kAudioChannelLayoutTag_Atmos_7_1_4, { left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight } },

should be reordered to:

{ kAudioChannelLayoutTag_Atmos_7_1_4, { left, right, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, centre, LFE, topRearLeft, topRearRight, leftSurroundRear, rightSurroundRear } },

I think that the Atmos channel order is a progression from kAudioChannelLayoutTag_AudioUnit_7_0.

With the above change, I can have a 7.1.4 process work for both vst3 and AU without having to reorder in my code. aka the channel order of the incoming buffer correspond to AudioChannelSet AudioChannelSet::create7point1point4()

If you agree then it would be worth testing / changing the other atmos layouts too.

Of course, I may have misunderstood something, in which case please correct me.

Could you provide a few more details about exactly what you’re doing, and how you’re using the new layouts? For the moment I’ll assume you’re using AudioChannelSet::create7point1point4() as the layout of the output bus of a synth.

I did the following:

  • Modify the AudioPluginDemo to use a surround output bus by default, and adjust isBusesLayoutSupported accordingly.
  • killall -9 AudioComponentRegistrar
  • auval -a then look for AudioPluginDemo
  • auval -v aumu Aufx Manu (validate the plugin I just built. The ID strings may be different on your system)
  • The plugin validates successfully, and the default format is correctly reported as being a 12-channel layout
  • Open a new project in Logic
  • Go to the project settings, Audio tab, and check that the surround format is 7.1.4
  • On an instrument track, try to instantiate the plugin we just built

When I follow the steps above, I see an option to instantiate using 7.1.4 channel layout. When I select it, the plugin loads successfully.

Getting Logic to recognise new channel layouts after the plugin is updated can be quite difficult. The only reasonably consistent technique I’ve found is to switch the plugin’s ID, kill the AudioComponentRegistrar, open and close Logic, and then put the ID back to the old value. There’s a chance that the AU cache got invalidated for some reason while you were rebuilding your project - I’d recommend switching back to the canonical develop branch state and checking whether the plugin continues to advertise the 7.1.4 channel layout.

I’d be very surprised if the change you suggested had any effect. As far as I can tell, the channel layouts are always added to an AudioChannelSet before they are used/compared, which should render the declaration order irrelevant. Perhaps I overlooked something, though, so I’ll take another look if you’re still running into problems after reverting your JUCE changes.

I’ve often found this helps encourage it to refresh, but now we have the ‘full audio unit reset’ option in the plugin manager too:
rm ~/Library/Caches/AudioUnitCache/com.apple.audiounits.cache
rm ~/Library/Preferences/com.apple.audio.InfoHelper.plist

thanks for the quick reply.

We are building a Binaural Monitoring Tool for 7.1.4. So essentially an FX that is inserted on a 7.1.4 track.

I am using AudioChannelSet::create7point1point4() and the plugin loads fine in Logic and reports as such.

Here is my test:
I have 12 mono tracks (spoken words left, right, etc) in Logic all routed to a 7.1.4 Group. Each panned (using Logic’s Panner) to one of the 12 speakers.
On the group, I insert Logic’s level meter (7.1.4) to ensure my pannings are correct. After this, I have inserted my plug-in.

in the processBlock I route the incoming channels, one by one to the first out.

    buffer.copyFrom(0, 0, buffer, 0, 0, buffer.getNumSamples());

	// Clear the output channels greater than 1
	for (auto i = 1; i < totalNumOutputChannels; ++i)
		buffer.clear(i, 0, buffer.getNumSamples());

build and test in Logic.
I hear: Left
then:

    buffer.copyFrom(0, 0, buffer, 1, 0, buffer.getNumSamples());

	// Clear the output channels greater than 1
	for (auto i = 1; i < totalNumOutputChannels; ++i)
		buffer.clear(i, 0, buffer.getNumSamples());

build and test in Logic.
I hear: Right
then:

    buffer.copyFrom(0, 0, buffer, 2, 0, buffer.getNumSamples());

	// Clear the output channels greater than 1
	for (auto i = 1; i < totalNumOutputChannels; ++i)
		buffer.clear(i, 0, buffer.getNumSamples());

build and test in Logic.
I hear: Left Surround Rear - but I was expecting to hear Centre

repeat for all other channels:
I then tried to fix the order by swapping Centre and LeftSurroundRear etc, but got yet another order when repeating this test.
After some trial and error, I found the above order that gave me the expected result to match the order of AudioChannelSet AudioChannelSet::create7point1point4() in the buffer

Thanks for the detailed explanation, it really helped in tracking down the problem.

In the CoreAudio headers there are some constants, with comments that explain the intended layout:

	kAudioChannelLayoutTag_Atmos_5_1_2              = (194U<<16) | 8,                       ///< L R C LFE Ls Rs Ltm Rtm
	kAudioChannelLayoutTag_Atmos_5_1_4              = (195U<<16) | 10,                      ///< L R C LFE Ls Rs Vhl Vhr Ltr Rtr
	kAudioChannelLayoutTag_Atmos_7_1_2              = (196U<<16) | 10,                      ///< L R C LFE Ls Rs Rls Rrs Ltm Rtm
	kAudioChannelLayoutTag_Atmos_7_1_4              = (192U<<16) | 12,                      ///< L R C LFE Ls Rs Rls Rrs Vhl Vhr Ltr Rtr
	kAudioChannelLayoutTag_Atmos_9_1_6              = (193U<<16) | 16,                      ///< L R C LFE Ls Rs Rls Rrs Lw Rw Vhl Vhr Ltm Rtm Ltr Rtr

The 7.1.4 layout here is the channel arrangement I’m using in the SpeakerLayoutTable.

What I’d missed is that there are some additional definitions further down the file:

    kAudioChannelLayoutTag_Logic_Atmos_7_1_4_A      = kAudioChannelLayoutTag_Atmos_7_1_4,   ///< L R C LFE Ls Rs Rls Rrs Vhl Vhr Ltr Rtr
    kAudioChannelLayoutTag_Logic_Atmos_7_1_4_B      = (202U<<16) | 12,                      ///< L R Rls Rrs Ls Rs C LFE Vhl Vhr Ltr Rtr

So there are actually two different Logic 7.1.4 layouts (!?) and it looks like the one that Logic chooses to use is the “B” version. I can’t find any documentation for these keys, so it’s not clear why there are two different arrangements for the same layout.

The really weird part is that my test plugin consistently reports the “A” layout, and even seems to receive calls to SetAudioChannelLayout with an AudioChannelLayoutTag of kAudioChannelLayoutTag_Atmos_7_1_4, so it looks like Logic knows fully well what channel order the plugin is using, but chooses to ignore it.

If I add the “B” version to the SpeakerLayoutTable instead, then I can get Logic and the plugin to agree on the channel order (attached gif is a noise generator that emits noise on each channel in turn and prints the channel type name of the current channel, built using the “B” layout).

trimmed

So, this change seems to work in Logic, but I’m not convinced it’s portable to other hosts. The change means that all AU plugins using a 7.1.4 layout will request a layout of kAudioChannelLayoutTag_Logic_Atmos_7_1_4_B rather than kAudioChannelLayoutTag_Atmos_7_1_4, and I’m not sure whether that’s the correct behaviour. The Logic B constant is only defined in the 12.0 SDK and up, whereas the normal Atmos constant is defined in the 10.15 SDK, so I’d expect a broader range of projects to understand the plain Atmos key.

At the moment I think there’s a chance this is a bug in Logic. I’m going to investigate a bit more before making any changes to JUCE.

1 Like

It gets weirder. I’ve tested a bit now on an x86 and an Arm machine, both running macOS 12 and Logic 10.7.1.

On the x86 machine, Logic appears to use the “A” layout, and ignores requests from the plugin to use the “B” layout.

On the Arm machine, Logic appears to use the “B” layout, and ignores requests from the plugin to use the “A” layout. In addition, when I have a few plugins in series on the same channel strip, the output from inserts lower down the channel strip seems to appear at the inputs of earlier inserts on the same channel!

In the attached gif, I’m testing with a custom plugin that displays input levels on each input channel, and produces noise on a single channel at a time. Both Logic’s level meter, and the first custom plugin instance appear to see the output of the second custom plugin instance.

trimmed

I also tested out the same setup, but using the 5.1.2 configuration. I see exactly the same problems there (in-channel feedback, incorrectly-ordered channels) on the Arm machine, but everything works as expected on x86. I have no idea why the channel ordering is wrong for the 5.1.2 configuration: there is only a single AudioChannelLayoutTag denoting a 5.1.2 layout, and the description of this layout indicates that the centre channel is third in the layout, but Logic on Arm uses a different order.

It would be useful to know what system(s) you’ve tested on there. If you were seeing breakage on Arm, then that might suggest that Logic’s channel layout really does depend somewhat on the machine architecture. If you were seeing breakage on x86, then there’s something else going on that I don’t yet understand.

Does it make a difference on ARM whether Logic is running under Rosetta?

Yes, under Rosetta 2 I also don’t see the feedback issue, but the channel orders still seem to be incorrect.