Looking at this right now. I have the following idea. Please let me know if this makes sense:
As only CoreAudio seems to explicitly mention the FuMa channels, I will replace JUCE’s ambisonic W, X, Y, Z with the 1st order ACN channels and then add all the other higher order ACN channels to JUCE. So:
ambisonicACN0 = 24, // <- used to be ambisonicW
ambisonicACN1 = 25, // <- used to be ambisonicX
ambisonicACN2 = 26, // <- used to be ambisonicY
ambisonicACN3 = 27 // <- used to be ambisonicZ
...
For backward compatibility, I will add defines for the FuMa channel labels ambisonicW, … as follows
ambisonicW = ambisonicACN0,
ambisonicX = ambisonicACN3,
ambisonicY = ambisonicACN1,
ambisonicZ = ambisonicACN2,
As you see I’m ordering so that the channels match with ACN (according to this wiki article). This is actually a breaking change, as ambisonicX … amisonicZ will now have a different channel order. This ensures that the channels in any ambisonic JUCE audio buffer (FuMa or ACN) will always be in ACN order (if you access the channel buffer with a raw int like buffer[2] etc). The backends will ensure the channel re-ordering from FuMa 1st order to ACN 1st order. JUCE won’t support any higher order FuMa formats.
This is a slight breaking change if anybody relied on, the ordering of the FuMa channels, like this code, for example:
AudioChannelSet ambisonic = AudioChannelSet::ambisonic();
const int channelIdxOfWChannel = ambisonic.getChannelIndexForType (ambisonicW);
float* w = audioBuffer.getReadPointer (channelIdxOfWChannel + 0);
float* x = audioBuffer.getReadPointer (channelIdxOfWChannel + 1);
float* y = audioBuffer.getReadPointer (channelIdxOfWChannel + 2);
float* z = audioBuffer.getReadPointer (channelIdxOfWChannel + 3);
The following code would not break and have the benefit that the channel pointers would be correct regardless if the audio buffer is ACN or FuMa (as internally everything will be ordered as ACN):
AudioChannelSet ambisonic = AudioChannelSet::ambisonic();
float* w = audioBuffer.getReadPointer (ambisonic.getChannelIndexForType (ambisonicW));
float* x = audioBuffer.getReadPointer (ambisonic.getChannelIndexForType (ambisonicX));
float* y = audioBuffer.getReadPointer (ambisonic.getChannelIndexForType (ambisonicY));
float* z = audioBuffer.getReadPointer (ambisonic.getChannelIndexForType (ambisonicZ));
Do people think this approach is sensible?