Query how Juce reorders channels

Hi Dylan, the order that getTypeOfChannel() returns is the Juce-internal order. Juce reorders the channels from the plugin format to it’s internal order so that you don’t have to. Just stick to the Juce order and you are fine, as long as the DAW also respects the format as set by the plugin format (VST3, AU, AAX etc.).

Bad example is Reaper and VST3, where Reaper does shit with higher channel counts. But Pro Tools should be fine. Our plugins use the new formats provided by AAX (up to 7th order Ambisonics, 9.1.6, etc.) and it works.

hmm im not getting that behavior in Pro Tools on a 7.1 bus, but i get the expected results in all my other tests so far;

is it possible this is just a juce bug with that specific DAW & bus type?
ill follow up here if I find anything…

Lets take AAX as an example. The 7.1 order in AAX differs to that of Juce. So if your plugin produces sound on the center channel, internally in Juce it is channel index 2 (starting with 0), but in AAX it is index 1. So if you implement meters, yours will show activity on the third channel, while Pro Tools shows activity on the second channel. That is normal. If you want to match the channel order and the metering, you have to keep a list of the different matches for each plugin format at least. We don’t do it. Only few people notice the difference in the metering and almost nobody cares if the signal sounds on the correct speaker eventually.

yeah this is what i always knew and still brings me to the same question originally which is why isnt this protools specific AAX ordering corrected internally in JUCE?

this becomes an issue when the plugin is not mixing to non-discrete channel layouts but uses them because the host DAW doesnt supply a bus size needed for discrete channels (for example in this case it does matter that the meters match because there is no “center” channel in the plugin, we are only using it because there is no ideal bus type that matches on that DAW)

for what its worth i can only get things to work by doing the following:

if(!chanset.isDiscreteLayout()) { // Check for DAW specific instructions
        if (hostType.isProTools() && chanset.size() == 8 && chanset.getDescription().contains(juce::String("7.1 Surround"))){
            // TODO: Remove this and figure out why we cannot use what is in "else" on PT 7.1
            chan_types[0] = juce::AudioChannelSet::ChannelType::left;
            chan_types[1] = juce::AudioChannelSet::ChannelType::centre;
            chan_types[2] = juce::AudioChannelSet::ChannelType::right;
            chan_types[3] = juce::AudioChannelSet::ChannelType::leftSurroundSide;
            chan_types[4] = juce::AudioChannelSet::ChannelType::rightSurroundSide;
            chan_types[5] = juce::AudioChannelSet::ChannelType::leftSurroundRear;
            chan_types[6] = juce::AudioChannelSet::ChannelType::rightSurroundRear;
            chan_types[7] = juce::AudioChannelSet::ChannelType::LFE;
        } else {
            // Get the index of each channel supplied via JUCE
            for (int i = 0; i < numOutputChannels; i ++) {
                chan_types[i] = chanset.getTypeOfChannel(i);
            }
        }
        // Apply the index
        for (int i = 0; i < numOutputChannels; i ++) {
            output_channel_indices[i] = chanset.getChannelIndexForType(chan_types[i]);
        }
    }

which to me seems to counteract the point of a function named getTypeOfChannel(int)
additionally i used to have to make such a correction for ProTools Quadraphonic and some others but now everything so far seems to pass my tests except the 7.1 bus type, so maybe its just a bug?

I have the same use case. I ended up hacking together some classes that map back from JUCE order to the original order using code from the AAX and VST3 wrappers. It also maps the channels at the end of processBlock() such that the JUCE remapping will be cancelled out. It’s a real pain and it would be nice to have the functionality to do that directly in JUCE. Better still, all plugin formats would allow for buses to be defined with discrete channels like VST2…

1 Like

yeah the real longterm solution is the removal of the concept of “surround tagged” bus types and everything be discrete

but bar that @pstitt01 i used to manually map things but i am discovering the for loop i wrote above works in my tests in most multichannel DAWs so far (im early in testing tho)

at the risk of asking too much: are there DAWs & bus layouts you found that needed this and can we share amongst us to try to figure out how to contribute it to JUCE? My thoughts are that ideally this could be internal to JUCE but requires contribution to catch all the cases?

I think the way juce currently works is most convenient to not introduce magic numbers and pseudo-standard-ordering.
For instance in Logic you can freely select between different channel order displays. My ProTools is currently expired, but IIRC it was possible there too.

So there goes the standard of a channel order…

But maybe I didn’t understand your use case. I found it most solid to rely on the methods you find in AudioChannelSet getTypeOfChannel(int) and getChannelIndexForType (ChannelType)

My code didn’t make it into production so I didn’t test in a lot of DAWs yet, so I’m not sure about exceptions. I was simply undo-ing JUCE’s internal mapping so the channels are in whatever order the DAW gets them to the plugin. It doesn’t account for any changes the DAW might apply before that. As @daniel mentions, there are settings to change the channel ordering in some DAWs and I don’t know how that interacts with what reaches the plugin…

Logic is a good example. When you change the visible order of the channels in logic it does not change the order of channels communicated to the plugin and therefore the plugin is not capable of knowing how Logic displays the channels. So you won’t be able to match that.

Also the idea that all plugin formats should support discrete channel layouts is not really a good idea because it will be an even bigger pain in the ass for users than it is already. If you want to mix something onto 7.1.4 bus, you do not want to think about channel orders of different plugins. So what would really be needed is that the channel orders are standardized across all formats and all DAWs. But at this point i think that is just a dream…

1 Like

The whole thing is a pain. There should really be some way to support non-standard layouts in all plugin formats. I totally understand the choices made. As long as you stick with standard layouts everything is actually nice and easy. As soon as you need something outside of a defined layout things get hairy.

For example, @dylanmach1, needs to be able to support Mach 1 routing (I imagine). Any ambisonic microphone manufacturer needs to ensure that the input to the plugin is in the same order they were recorded to the DAW. Myself, I would like to be able to support non-standard loudspeaker arrays. Currently the best option for that is to use an Ambisonic bus since that is a one-to-one mapping. Not so nice but at least it works.

I think we still don’t understand each other. There is no standard. Every plugin API does it differently, every DAW does it differently, even every user does it differently when the DAW allows them for good reason to display it differently.

That’s why the context information of the AudioChannelSet is the only thing to get you out of that PITA.

By non-standard I mean something that doesn’t use the labelled set of channels (L, R, C, Ls, Rs, etc.). For example, a tetrahedral ambisonic microphone has 4 channels that don’t align with the channels of, say, a quad layout. There is currently no way to handle these sort of cases but it’s essential to know their order for the plugin to process them correctly.

I totally agree that if you are using a layout like 5.1/7.1.4 etc. then the AudioChannelSet works great and saves a lot of trouble.

Don’t you speak of FOA? That is supported by Juce and whereever a DAW provides FOA channels it can be used directly. Of course if you want to output your FOA channels to a quad layout, that is indeed hairy. But isn’t that hairy by itself already?

1 Like

Yes, the output of the plugin would be FOA and is the easy bit but in the input is 4 raw microphone capsules in A-format. For this particular case we could use a FOA bus as the input to avoid mapping as a work-around.

However, take an 8-capsule “second-order” microphone (e.g. Spatial Mic or OctoMic). Those 8 channels should have a known order for the plugin to process correctly. If you use a 7.1 track then you need to know what mapping was performed by JUCE relative to how the channels are arranged in the DAW. The output is easy, we can use a standard 2OA layout.

Have another look at the AudioChannelSet, there is AmbisonicACN0 etc.

Also check how you write your isBusesLayoutSupported. You can make sure that the bus is indeed isAmbisonic() and getAmbisonicOrder().
This is where you communicate with the host what you want to support.

But as @fiedleraudio pointed out before, not every host actually sets those information properly.

I would be curious if there is a reordering happen if the host reports the channelset as isDiscrete() ? Would be mayhem.

Well, i am not sure what a 8 capsule mic is supposed to produce. But second order Ambisonics would be 9 channels. If you need to encode the signal from the Mic to Ambisonics, i guess it would be second order and then the second order Ambisonics channel format would be the way to go. Or am i completely wrong here?

The Ambisonics buses work great. It’s when you have the inputs from a microphone array that needs converted to Ambisonics that is (one case) where problems arise. The mic array does not have channels that correspond to any Ambisonic channel or to the usual L/R/C labels. Commercially available mics can range from 4 to 64 capsules.

Yes, you’re right. Ambisonic mic manufacturers have gone for a method where they omit with “R” channel and provide a 2OA signal with 9 channels but silent in one of them. The signals from the mics themselves are just raw mic signals that the plugin would covert to Ambisonics.

But when you record the 8 channels from the mic you should record to an 8-channel track. In Pro Tools this means selecting a 7.1 track because AFAIK you can’t record 8-channels to a 9-channel 2nd order track.

I feel like I’m not being clear here about the use cases for why some devs might want to be able to undo JUCE’s mapping or, better yet, have plugin formats allow arbitrary numbers of unlabelled channels. Let me know if I can clarify :slight_smile:

Got ya. But this scenario is a shortcoming of Pro Tools which does not offer an 8.0 track or as you say a generic 8-channel track. Juce is capable of connecting to a discrete 8-channel track with the channels just numbered and thats it.

It would definitely be better if AAX and VST3 added support to allow for these sort of cases. In the meantime, my solution has been to undo the mapping JUCE does in the VST3 and AAX wrappers. It would be nicer to just be able to tell JUCE not to do this mapping but then getChannelIndexForType() and similar functions probably need reimplemented, so I don’t see this happening.

Rather than have JUCE remap buffers from the input order to its own internal ordering it might be good to instead build a map of the input provided by the DAW and use that for getChannelIndexForType(). This way the channels don’t get reordered in the plugin and we can continue using getChannelIndexForType(). But I’m probably missing a good and obvious reason why JUCE sorts the channels to its own internal ordering.

Yeah, you actually do. Juce is serving as an abstraction layer, not only when it comes to operating systems, but also when it comes to plugin formats. So you have to write code which works across the different formats and you do not have to think about keeping up with the developments in these formats in combination with what DAWs are doing with it. An option for not having things reordered might be good though, but it must stay optional.

And when it comes to AAX you need to complain to Avid and about VST 3, talk to Steinberg.