VST3 Speaker types to/from Juce Channel types wrapping mistakes


#1

Hi
I found some error in the juce_VST3Common.h channel types wrappers with Vst::Speaker types Sl/Sr and Lcs/Rcs being mixed up. One of the consequences being that Dolby Atmos arrangements such as 7.1.2 or 7.1.4 can’t be used in VST3.

So, basically, the following code:

static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::SpeakerArrangement arr, Steinberg::Vst::Speaker type) noexcept
{
    using namespace Steinberg::Vst;
	
    switch (type)
    {
       /* ... */
        case kSpeakerCs:    return AudioChannelSet::centreSurround;
        case kSpeakerSl:    return AudioChannelSet::leftSurroundRear;
        case kSpeakerSr:    return AudioChannelSet::rightSurroundRear;
        case (1ull << 11):  return AudioChannelSet::topMiddle;  /* kSpeakerTm */
        case kSpeakerTfl:   return AudioChannelSet::topFrontLeft;
        case kSpeakerTfc:   return AudioChannelSet::topFrontCentre;
        
		/* ... */
		
        case (1ull << 49):  return AudioChannelSet::ambisonicACN15; /* kSpeakerACN15 */
        case (1ull << 24):  return AudioChannelSet::topSideLeft;  /* kSpeakerTsl */
        case (1ull << 25):  return AudioChannelSet::topSideRight; /* kSpeakerTsr */
        case (1ull << 26):  return AudioChannelSet::leftSurroundSide;  /* kSpeakerLcs */
        case (1ull << 27):  return AudioChannelSet::rightSurroundSide; /* kSpeakerRcs */
        /* ... */
	}

	/* ... */
}

static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set, AudioChannelSet::ChannelType type) noexcept
{
    using namespace Steinberg::Vst;

    switch (type)
    {
       /* ... */
        case AudioChannelSet::leftSurroundSide:  return (1ull << 26); /* kSpeakerLcs */
        case AudioChannelSet::rightSurroundSide: return (1ull << 27); /* kSpeakerRcs */
        case AudioChannelSet::topMiddle:         return (1ull << 11); /* kSpeakerTm */
        
		/* ... */
		
        case AudioChannelSet::LFE2:              return kSpeakerLfe2;
        case AudioChannelSet::leftSurroundRear:  return kSpeakerSl;
        case AudioChannelSet::rightSurroundRear: return kSpeakerSr;
        case AudioChannelSet::wideLeft:          return kSpeakerPl;
        case AudioChannelSet::wideRight:         return kSpeakerPr;
       
	   /* ... */
        default:
            break;
    }

	/* ... */
	
}

should become:

static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::SpeakerArrangement arr, Steinberg::Vst::Speaker type) noexcept
{
    using namespace Steinberg::Vst;

    switch (type)
    {
       /* ... */
        case kSpeakerCs:    return AudioChannelSet::centreSurround;
        case kSpeakerSl:    return AudioChannelSet::leftSurroundSide;  
        case kSpeakerSr:    return AudioChannelSet::rightSurroundSide;
        case (1ull << 11):  return AudioChannelSet::topMiddle;  /* kSpeakerTm */
        case kSpeakerTfl:   return AudioChannelSet::topFrontLeft;
        case kSpeakerTfc:   return AudioChannelSet::topFrontCentre;
        
		/* ... */
		
        case (1ull << 49):  return AudioChannelSet::ambisonicACN15; /* kSpeakerACN15 */
        case (1ull << 24):  return AudioChannelSet::topSideLeft;  /* kSpeakerTsl */
        case (1ull << 25):  return AudioChannelSet::topSideRight; /* kSpeakerTsr */
        case (1ull << 26):  return AudioChannelSet::leftSurroundRear; /* kSpeakerLcs */
        case (1ull << 27):  return AudioChannelSet::rightSurroundRear; /* kSpeakerRcs */
        /* ... */
	}
	/* ... */
}

static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set, AudioChannelSet::ChannelType type) noexcept
{
    using namespace Steinberg::Vst;

    switch (type)
    {
       /* ... */
        case AudioChannelSet::leftSurroundSide:  return kSpeakerSl;
        case AudioChannelSet::rightSurroundSide: return kSpeakerSr; 
        case AudioChannelSet::topMiddle:         return (1ull << 11); /* kSpeakerTm */
        
		/* ... */
		
        case AudioChannelSet::LFE2:              return kSpeakerLfe2;
        case AudioChannelSet::leftSurroundRear:  return (1ull << 26); /* kSpeakerLcs */
        case AudioChannelSet::rightSurroundRear: return (1ull << 27); /* kSpeakerRcs */
        case AudioChannelSet::wideLeft:          return kSpeakerPl;
        case AudioChannelSet::wideRight:         return kSpeakerPr;
       
	   /* ... */
        default:
            break;
    }

	/* ... */
	
}

Can you please fix it ?

Steinberg Speaker types positions diagram below as a reminder:

vst3_speaker_types

Thanks

Fred
Merging Technologies


#2

Unfortunately it’s not that simple. This is due to the DTS layouts (AudioChannelSet::create7point0, AudioChannelSet::create7point1, …). Steinberg calls these layouts kSpeakerArr60Music, kSpeakerArr70Music, … but for some reason uses: kSpeakerSl, kSpeakerSr for the left and right rear speakers.

If I would adopt your change then a bunch of layouts would become inconsistent.

In which DAW do the Dolby Atmos configurations not work?


#3

We use some Juce::AudioChannelSet wrapping In Pyramix and we have about the same definition of Speaker Types as Juce and VST3 as you can see below: (excepted wide / Proxy Left and Right)

	"",		"None",
	"L",		"Left",
	"C",		"Center",
	"R",		"Right",
	"Ls",		"Surround Left",
	"Rs",		"Surround Right",
	"LFE",		"LFE",
	"Lc",		"Center Left",
	"Rc",		"Center Right",
	"Cs",		"Surround Center",
	"Sl",		"Side Left",
	"Sr",		"Side Right",
	"Lcs",		"Center Surround Left",
	"Rcs",		"Center Surround Right",
	"VoG",		"Voice of God", // == Top Middle (Tc) 
	"Tl",		"Top left", // == Top Front Left (Tfl)
	"Tc",		"Top Center", //  == Top Front Center (Tfc)
	"Tr",		"Top Right", //  == Top Front Right (Tfr)
	"Trl",		"Top Surround Left",
	"Trc",		"Top Surround Center",
	"Trr",		"Top Surround Right",
	"Tsl",		"Top Side Left",
	"Tsr",		"Top Side Right",
	"Bl",		"Bottom left",
	"Bc",		"Bottom Center",
	"Br",		"Bottom Right",
	"Brl",		"Bottom Surround Left",
	"Brc",		"Bottom Surround Center",
	"Brr",		"Bottom Surround Right",
	"Bsl",		"Bottom Side Left",
	"Bsr",		"Bottom Side Right",
	"VoD",		"Voice of Devil", // == Bottom middle
	"LFE2"		"LFE2"
	
	+ "Ambisonic ACN0-63 (1st to 7th order)"

But we dropped the DTS layouts since no precise definition is available. And honestly we don’t see much requests for these, unlike Atmos and Auro.
For 7.0 precisely we propose several layouts, one SDDS and 2 ITU:

  • the SDDS one ( L-R-C-Lc-Rc-Ls-Rs) (same as Steinberg’s k70Cine)
  • the ITU-I (0+7+0) one (L-R-C-Sl-Sr-Ls-Rs) (same as Steinberg’s k70Music)
  • the ITU-C (2+5+0) one (L-R-C-Ls-Rs-Tl-Tr) (same as Steinberg’s k71MPEG3D or k71CineFrontHigh without the Lfe).

Now to illustrate the problem of SideLeft/Right definitions, a concrete example: take Atmos 7.1.4
We define it in pyramix as follows: L C R Sl Sr Ls Rs Tl Tr Trl Trr Lfe

Fortunately, Vst3 sdk defines it the very same way:


with an extra alternative k111MPEG3D moniker.

So at the moment, if we try to map Pyramix Channel types to VST3 channel types with intermediate Juce Channel Type wrapping, we will end up with SideLeft and SideRight being replaced by BackLeftCenter (Lcs) and BackRightCenter (Rcs).

I understand that it’s tricky (actually impossible) to accommodate the various flavours of 7.0 Multichannel speaker layouts with a single create7point0() factory function, but more important than that is that the channel types definition really maps to what its moniker suggests… if the various channel types are available and consistent, format wise, both plug-ins and hosts sides can work-around the default layouts functions with their custom layout definitions.

Cheers

Fred
Merging Technologies


#4

Isn’t ITU-I (0+7+0) the same as DTS 7.0?


#5

If DTS 7.0 uses Side Left and Side Right, Surround Left and Surround Right, defined as such, then yes.
But in your create7Point0() function, you use the definition using Surround Left / Right (in place of Side Left/Right) and Surround Rear Left/Right (in place of Surround Left/Right). And at the end, to cope with VST3 SDK 70Music layout, you swap Side Left/Right and Surround Rear Left/Right; which is wrong, because you end up with placing the back channels above the Surround or Side channels. If you kept this definition, you should exceptionally swap Surround Left/Right and Side Left/Right, for this very layout, so the rear back channels are still behind the side channels.
I hope I’m not too confusing :slight_smile:
Overall, I think the DTS 7.0 definition using Side Left/Right makes it easier to handle the various other layouts.

Fred


#6

up?