VST3 HOA Support > 3rd order

One issue is that based on the current Definition of the Bus Arrangement it is not possible to extend to complex Speaker Arrangements or new Arrangements with a lot of channels like HOA 7order, without breaking compatibility with old released Plug-ins and hosts.
We are thinking to add a new dedicated interface defining a new way to describe Speaker Arrangement. Here a proposal:

//----------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
	
//------------------------------------------------------------------------
/** \defgroup vst3typedef VST 3 Data Types
*/
/*@{*/
//------------------------------------------------------------------------
// Speaker Arrangements Types
//------------------------------------------------------------------------
typedef uint64 ExtSpeakerArrangement;
/*@}*/

//------------------------------------------------------------------------
// Extended speaker Arrangement Macros
#define SPEAKER_ARRANGEMENT_FORMAT(enumVal, numChannels) \
	(((Speaker)1 << 63) | ((Speaker)enumVal << 16) | (numChannels & 0xFFFF))
#define SPEAKER_ARRANGEMENT_FORMAT_NUMCHANNELS(speakerArrFormat) \
	(static_cast<uint16> (speakerArrFormat & 0xFFFF))
#define SPEAKER_ARRANGEMENT_FORMAT_ENUM(speakerArrFormat) \
	(static_cast<uint16> ((speakerArrFormat >> 16) & 0xFFFF))
#define IS_SPEAKER_ARRANGEMENT_FORMAT(speakerArrFormat) \
	((speakerArrFormat & ((Speaker)1 << 63) != 0)

enum eSpeakerArrangementIndex : uint16
{
	kESAF_Empty = 0,		///< empty arrangement
	kESAF_Mono,				///< M
	kESAF_Stereo,			///< L R
	kESAF_StereoSurround,	///< Ls Rs
	kESAF_StereoCenter,		///< Lc Rc
	kESAF_StereoSide,		///< Sl Sr
	kESAF_StereoCLfe,		///< C Lfe
	kESAF_StereoTF,			///< Tfl Tfr
	kESAF_StereoTS,			///< Tsl Tsr
	kESAF_StereoTR,			///< Trl Trr
	kESAF_StereoBF,			///< Bfl Bfr

	kESAF_30Cine,			///<  L R C
	kESAF_30Music,			///<  L R S
	kESAF_31Cine,			///<  L R C   Lfe
	kESAF_31Music,			///<  L R Lfe S
	kESAF_40Cine,			///<  L R C   S (LCRS)
	kESAF_40Music,			///<  L R Ls  Rs (Quadro)
	kESAF_41Cine,			///<  L R C   Lfe S (LCRS+Lfe)
	kESAF_41Music,			///<  L R Lfe Ls Rs (Quadro+Lfe)
	kESAF_50,				///<  L R C   Ls Rs
	kESAF_51,				///<  L R C  Lfe Ls Rs
	kESAF_60Cine,			///<  L R C  Ls  Rs Cs
	kESAF_60Music,			///<  L R Ls Rs  Sl Sr
	kESAF_61Cine,			///<  L R C  Lfe Ls Rs Cs
	kESAF_61Music,			///<  L R Lfe Ls  Rs Sl Sr
	kESAF_70Cine,			///<  L R C   Ls  Rs Lc Rc
	kESAF_70Music,			///<  L R C   Ls  Rs Sl Sr
	kESAF_71Cine,			///<  L R C Lfe Ls Rs Lc Rc
	kESAF_71CineFullRear,	///<  L R C Lfe Ls Rs Lcs Rcs
	kESAF_71Music,			///<  L R C Lfe Ls Rs Sl Sr
	kESAF_80Cine,			///<  L R C Ls  Rs Lc Rc Cs
	kESAF_80Music,			///<  L R C Ls  Rs Cs Sl Sr
	kESAF_81Cine,			///<  L R C Lfe Ls Rs Lc Rc Cs
	kESAF_81Music,			///<  L R C Lfe Ls Rs Cs Sl Sr

	/*-----------*/
	/* 3D formats */
	/*-----------*/
	kESAF_80Cube,			///<  L R Ls Rs Tfl Tfr Trl Trr (40_4)
	kESAF_71CineTopCenter,	///<  L R C Lfe Ls Rs Cs Tc
	kESAF_71CineCenterHigh, ///<  L R C Lfe Ls Rs Cs Tfc
	kESAF_71CineFrontHigh,	///<  L R C Lfe Ls Rs Tfl Tfr
	kESAF_71CineSideHigh,	///<  L R C Lfe Ls Rs Tsl Tsr
	kESAF_81MPEG3D,			///<  L R Lfe Ls Rs Tfl Tfc Tfr Bfc 			(41_3_1)
	kESAF_50_4,				///<  L R C Ls Rs Tfl Tfr Trl Trr
	kESAF_51_4,				///<  L R C Lfe Ls Rs Tfl Tfr Trl Trr
	kESAF_70_2,				///<  L R C Ls Rs Sl Sr Tsl Tsr
	kESAF_71_2,				///<  L R C Lfe Ls Rs Sl Sr Tsl Tsr
	kESAF_100,				///<  L R C Ls Rs Tc Tfl Tfr Trl Trr			(50_5 TopC)
	kESAF_101,				///<  L R C Lfe Ls Rs Tc Tfl Tfr Trl Trr		(51_5 TopC)
	kESAF_102,				///<  L R C Lfe Ls Rs Tfl Tfc Tfr Trl Trr Lfe2	(52_5)
	kESAF_110,				///<  L R C Ls Rs Tc Tfl Tfc Tfr Trl Trr		(50_6 TopC)
	kESAF_111,				///<  L R C Lfe Ls Rs Tc Tfl Tfc Tfr Trl Trr	(51_6 TopC)
	kESAF_70_4,				///<  L R C Ls Rs Sl Sr Tfl Tfr Trl Trr
	kESAF_71_4,				///<  L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr
	kESAF_70_6,				///<  L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr
	kESAF_71_6,				///<  L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr
	kESAF_90_6,				///<  L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr Tsl Tsr
	kESAF_91_6,				///<  L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr

	kESAF_122,				///<  L R C Lfe Ls Rs Lc Rc Tfl Tfc Tfr Trl Trr Lfe2	(72_5)
	kESAF_130,				///<  L R C Ls Rs Sl Sr Tc Tfl Tfc Tfr Trl Trr			(70_6 TopC)
	kESAF_131,				///<  L R C Lfe Ls Rs Sl Sr Tc Tfl Tfc Tfr Trl Trr		(71_6 TopC)
	kESAF_140,				///<  L R Ls Rs Sl Sr Tfl Tfr Trl Trr Bfl Bfr Brl Brr	(60_4_4)
	kESAF_222,				///<  L R C Lfe Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr Lfe2 Tsl Tsr Bfl Bfc Bfr (102_9_3 TocC)

	/** First-Order up to 8th Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization */
	kESAF_Ambi1stOrderACN,
	kESAF_Ambi2cdOrderACN,
	kESAF_Ambi3rdOrderACN,
	kESAF_Ambi4thOrderACN,
	kESAF_Ambi5thOrderACN,
	kESAF_Ambi6thOrderACN,
	kESAF_Ambi7thOrderACN,
	kESAF_Ambi8thOrderACN,

};

//------------------------------------------------------------------------
enum eSpeakerArrangementFormat: uint64
{
	kSAF_Empty		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Empty, 0),
	kSAF_Mono		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Mono, 1),
	kSAF_Stereo		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Stereo, 2),
	kSAF_30Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_30Cine, 3),
	kSAF_30Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_30Music, 3),
	kSAF_31Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_31Cine, 4),
	kSAF_31Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_31Music, 4),
	kSAF_40Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_40Cine, 4),
	kSAF_40Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_40Music, 4),
	kSAF_41Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_41Cine, 5),
	kSAF_41Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_41Music, 5),
	kSAF_50			= SPEAKER_ARRANGEMENT_FORMAT (kESAF_50, 5),
	kSAF_51			= SPEAKER_ARRANGEMENT_FORMAT (kESAF_51, 6),
	kSAF_60Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_60Cine, 6),
	kSAF_60Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_60Music, 6),
	kSAF_61Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_61Cine, 7),
	kSAF_61Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_61Music, 7),
	kSAF_70Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_70Cine, 7),
	kSAF_70Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_70Music, 7),
	kSAF_71Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71Cine, 8),
	kSAF_71CineFullRear = SPEAKER_ARRANGEMENT_FORMAT (kESAF_71CineFullRear, 7),
	kSAF_71Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71Music, 8),
	kSAF_80Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_80Cine, 8),
	kSAF_80Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_80Music, 8),
	kSAF_81Cine		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_81Cine, 9),
	kSAF_81Music	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_81Music, 9),

	kSAF_Ambi1stOrderACN	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Ambi1stOrderACN, 4),
	kSAF_Ambi2cdOrderACN	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Ambi2cdOrderACN, 9),
	kSAF_Ambi3rdOrderACN	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Ambi3rdOrderACN, 16),
	kSAF_Ambi4thOrderACN	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Ambi4thOrderACN, 25),
	kSAF_Ambi5thOrderACN	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Ambi5thOrderACN, 36),
	kSAF_Ambi6thOrderACN	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Ambi6thOrderACN, 49),
	kSAF_Ambi7thOrderACN	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Ambi7thOrderACN, 64),
	kSAF_Ambi8thOrderACN	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_Ambi8thOrderACN, 81),

	kSAF_80Cube				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_80Cube, 8),			
	kSAF_71CineTopCenter	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71CineTopCenter, 8),
	kSAF_71CineCenterHigh	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71CineCenterHigh, 8),
	kSAF_71CineFrontHigh	= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71CineFrontHigh, 8),
	kSAF_71CineSideHigh		= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71CineSideHigh, 8),
	kSAF_81MPEG3D			= SPEAKER_ARRANGEMENT_FORMAT (kESAF_81MPEG3D, 9),
	kSAF_50_4				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_50_4, 9),
	kSAF_51_4				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_51_4, 10),
	kSAF_70_2				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_70_2, 9),
	kSAF_71_2				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71_2, 10),
	kSAF_70_4				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_70_4, 11),
	kSAF_71_4				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71_4, 12),
	kSAF_70_6				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_70_6, 13),
	kSAF_71_6				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_71_6, 14),
	kSAF_90_6				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_90_6, 15),
	kSAF_91_6				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_91_6, 16),
	
	kSAF_100				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_100, 10),			
	kSAF_101				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_101, 11),			
	kSAF_102				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_102, 12),			
	kSAF_110				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_110, 11),			
	kSAF_111				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_111, 12),			
	kSAF_122				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_122, 14),
	kSAF_130				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_130, 13),
	kSAF_131				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_131, 14),
	kSAF_140				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_140, 14),
	kSAF_222				= SPEAKER_ARRANGEMENT_FORMAT (kESAF_222, 24),
};


//------------------------------------------------------------------------
/** Extended IAudioProcessor interface for a component.
\ingroup vstIPlug vst370
- [plug imp]
- [extends IAudioProcessor]
- [released: 3.7.0]
- [optional]

This interface extends the \ref IAudioProcessor::setBusArrangements and \ref IAudioProcessor::getBusArrangement 
of \ref IAudioProcessor by using the ExtSpeakerArrangement type. This new definition allows to support more
 complex arrangement with more than 64 channels and is not based on bitmask combination.
\n
\see IAudioProcessor
\see IComponent*/
//------------------------------------------------------------------------
class IExtendedSpeakerArrangement: public FUnknown
{
public:
	//------------------------------------------------------------------------
	/** Try to set (from host) a predefined arrangement for inputs and outputs.
		The host should always deliver the same number of input and output buses than the Plug-in needs 
		(see \ref IComponent::getBusCount).
		The Plug-in returns kResultFalse if wanted arrangements are not supported.
		If the Plug-in accepts these arrangements, it should modify its buses to match the new arrangements
		(asked by the host with IComponent::getBusInfo () or IAudioProcessor::getExtBusArrangement ()) and then return kResultTrue.
		If the Plug-in does not accept these arrangements, but can adapt its current arrangements (according to the wanted ones),
		it should modify its buses arrangements and return kResultFalse. */
	virtual tresult PLUGIN_API setExtBusArrangements (ExtSpeakerArrangement* inputs, int32 numIns,
												      ExtSpeakerArrangement* outputs, int32 numOuts) = 0;

	/** Gets the bus arrangement for a given direction (input/output) and index.
		Note: IComponent::getBusInfo () and IAudioProcessor::getExtBusArrangement () should be always return the same 
		information about the buses arrangements. */
	virtual tresult PLUGIN_API getExtBusArrangement (BusDirection dir, int32 index, ExtSpeakerArrangement& arr) = 0;

//------------------------------------------------------------------------
	static const FUID iid;
};

What do you think about it ?