1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

VST3: Add support for new wide/Atmos speaker layouts

This commit is contained in:
reuk 2024-05-30 13:57:42 +01:00
parent 34e454e3f1
commit a42a498f5e
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
4 changed files with 158 additions and 35 deletions

View file

@ -214,7 +214,6 @@ HarfBuzz Typeface implementation. New support for automatic font fallback
will be introduced in JUCE 8, and this will obviate much of the need for
CustomTypeface.
>>>>>>> 94454123d6 (Typeface: Implement platform typefaces using Harfbuzz hb_font_t)
## Change
@ -428,6 +427,48 @@ the licensing situation and encourages the creation of more open source software
without impacting personal use of the JUCE framework.
# Version 7.0.12
## Change
The function AudioChannelSet::create9point0point4, along with variants for
9.1.4, 9.0.6, and 9.1.6, used to correspond to VST3 layouts k90_4, k91_4,
k90_6, and k91_6 respectively. These functions now correspond to k90_4_W,
k91_4_W, k90_6_W, and k91_6_W respectively.
**Possible Issues**
VST3 plugins that used these AudioChannelSet layouts to specify initial bus
layouts, or to validate layouts in isBusesLayoutSupported, will now behave
differently.
For example, if the host wants to check whether the k90_4 layout is supported,
previously isBusesLayoutSupported() would have received the layout created by
create9point0point4(), but will now receive the layout created by
create9point0point4ITU().
**Workaround**
If you already have special-case handling for specific surround layouts,
e.g. to enable or disable them in isBusesLayoutSupported(), you may need to
add cases to handle the new AudioChannelSet::create*ITU() layout variants.
**Rationale**
Previously, the VST3 SDK only contained ITU higher-order surround layouts, but
the higher-order layouts specified in JUCE used Atmos speaker positions rather
than ITU speaker positions. This meant that JUCE had to remap speaker layouts
between Atmos/ITU formats when communicating with VST3 plugins. This was
confusing, as it required that the meaning of some channels was changed during
the conversion.
In newer versions of the VST3 SDK, new "wide" left and right speaker
definitions are available, allowing both ITU and Atmos surround layouts to be
represented. The change in JUCE surfaces this distinction to the user, allowing
them to determine e.g. whether the host has requested an ITU or an Atmos
layout, and to handle these cases separately if necessary.
# Version 7.0.10
## Change

View file

@ -268,33 +268,51 @@ public:
*/
static AudioChannelSet JUCE_CALLTYPE create7point1point6();
/** Creates a set for a 9.0.4 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
/** Creates a set for a 9.0.4 Atmos surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
Is equivalent to: k90_4 (VST3), AAX_eStemFormat_9_0_4 (AAX).
Is equivalent to: k90_4_W (VST3), AAX_eStemFormat_9_0_4 (AAX).
@see create9point0point4ITU()
*/
static AudioChannelSet JUCE_CALLTYPE create9point0point4();
/** Creates a set for a 9.1.4 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
/** Creates a set for a 9.1.4 Atmos surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight).
Is equivalent to: k91_4 (VST3), AAX_eStemFormat_9_1_4 (AAX).
Is equivalent to: k91_4_W (VST3), AAX_eStemFormat_9_1_4 (AAX).
@see create9point1point4ITU()
*/
static AudioChannelSet JUCE_CALLTYPE create9point1point4();
/** Creates a set for a 9.0.6 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight).
/** Creates a set for a 9.0.6 Atmos surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight).
Is equivalent to: k90_6 (VST3), AAX_eStemFormat_9_0_6 (AAX).
Is equivalent to: k90_6_W (VST3), AAX_eStemFormat_9_0_6 (AAX).
@see create9point0point6ITU()
*/
static AudioChannelSet JUCE_CALLTYPE create9point0point6();
/** Creates a set for a 9.1.6 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight).
/** Creates a set for a 9.1.6 Atmos surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight).
Note that the VST3 layout arranges the front speakers "L Lc C Rc R", but the JUCE layout
uses the arrangement "wideLeft left centre right wideRight". To maintain the relative
positions of the speakers, the channels will be remapped accordingly. This means that the
VST3 host's "L" channel will be received on a JUCE plugin's "wideLeft" channel, the
"Lc" channel will be received on a JUCE plugin's "left" channel, and so on.
Older versions of the VST3 SDK only supported ITU versions of the 9.0.4, 9.1.4, 9.0.6, and
9.1.6 layouts, which have the front-channel ordering "L Lc C Rc R".
To maintain the correct relative channel ordering, JUCE would perform the following mapping:
L -> wideLeft, Lc -> left, Rc -> right, R -> wideRight
Is equivalent to: k91_6 (VST3), kAudioChannelLayoutTag_Atmos_9_1_6 (CoreAudio).
The version of the VST3 SDK bundled with JUCE now supports Atmos versions of the above
layouts, which have the front-channel ordering "Lw L C R Rw". This order matches the
JUCE ordering, so no remapping is required.
create9point0point4(), create9point1point4(), create9point0point6(), and
create9point1point6() now correspond to the VST3 k90_4_W, k91_4_W, k90_6_W, and k91_6_W
Atmos layouts respectively.
If you need to support the old ITU layouts, use create9point0point4ITU(),
create9point1point4ITU(), create9point0point6ITU(), and create9point1point6ITU() instead.
Is equivalent to: k91_6_W (VST3), kAudioChannelLayoutTag_Atmos_9_1_6 (CoreAudio).
@see create9point1point6ITU()
*/
static AudioChannelSet JUCE_CALLTYPE create9point1point6();

View file

@ -269,6 +269,8 @@ static std::optional<Steinberg::Vst::Speaker> getSpeakerType (const AudioChannel
case AudioChannelSet::bottomRearLeft: return Steinberg::Vst::kSpeakerBrl;
case AudioChannelSet::bottomRearCentre: return Steinberg::Vst::kSpeakerBrc;
case AudioChannelSet::bottomRearRight: return Steinberg::Vst::kSpeakerBrr;
case AudioChannelSet::wideLeft: return Steinberg::Vst::kSpeakerLw;
case AudioChannelSet::wideRight: return Steinberg::Vst::kSpeakerRw;
case AudioChannelSet::discreteChannel0: return Steinberg::Vst::kSpeakerM;
@ -311,8 +313,6 @@ static std::optional<Steinberg::Vst::Speaker> getSpeakerType (const AudioChannel
case AudioChannelSet::ambisonicACN61:
case AudioChannelSet::ambisonicACN62:
case AudioChannelSet::ambisonicACN63:
case AudioChannelSet::wideLeft:
case AudioChannelSet::wideRight:
case AudioChannelSet::unknown:
break;
}
@ -383,6 +383,8 @@ static std::optional<AudioChannelSet::ChannelType> getChannelType (Steinberg::Vs
case Steinberg::Vst::kSpeakerBrl: return AudioChannelSet::bottomRearLeft;
case Steinberg::Vst::kSpeakerBrc: return AudioChannelSet::bottomRearCentre;
case Steinberg::Vst::kSpeakerBrr: return AudioChannelSet::bottomRearRight;
case Steinberg::Vst::kSpeakerLw: return AudioChannelSet::wideLeft;
case Steinberg::Vst::kSpeakerRw: return AudioChannelSet::wideRight;
}
return {};
@ -433,11 +435,15 @@ namespace detail
{ k71_6, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
{ k70_6, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
// The VST3 layout uses 'left/right' and 'left-of-center/right-of-center', but the JUCE layout uses 'left/right' and 'wide-left/wide-right'.
{ k91_4, { X::wideLeft, X::wideRight, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
{ k90_4, { X::wideLeft, X::wideRight, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
{ k91_6, { X::wideLeft, X::wideRight, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
{ k90_6, { X::wideLeft, X::wideRight, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
{ k90_4_W, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::wideLeft, X::wideRight } },
{ k91_4_W, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::wideLeft, X::wideRight } },
{ k90_6_W, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight, X::wideLeft, X::wideRight } },
{ k91_6_W, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight, X::wideLeft, X::wideRight } },
{ k90_4, { X::left, X::right, X::centre, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
{ k91_4, { X::left, X::right, X::centre, X::LFE, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } },
{ k90_6, { X::left, X::right, X::centre, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
{ k91_6, { X::left, X::right, X::centre, X::LFE, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } },
};
#if JUCE_DEBUG

View file

@ -57,9 +57,9 @@ public:
expect (map.getJuceChannelForVst3Channel (1) == 1); // R -> right
}
beginTest ("ChannelMapping for a 9.1.6 bus remaps the channels appropriately");
beginTest ("ChannelMapping for a k91_6 bus remaps the channels appropriately");
{
ChannelMapping map (AudioChannelSet::create9point1point6());
ChannelMapping map (AudioChannelSet::create9point1point6ITU());
expect (map.size() == 16);
// VST3 order is:
@ -80,6 +80,64 @@ public:
// Tsl
// Tsr
// JUCE order is:
// left
// right
// centre
// LFE
// leftSurround
// rightSurround
// leftCentre
// rightCentre
// leftSurroundSide
// rightSurroundSide
// topFrontLeft
// topRearRight
// topRearLeft
// topRearRight
// topSideLeft
// topSideRight
expect (map.getJuceChannelForVst3Channel (0) == 0); // L -> left
expect (map.getJuceChannelForVst3Channel (1) == 1); // R -> right
expect (map.getJuceChannelForVst3Channel (2) == 2); // C -> centre
expect (map.getJuceChannelForVst3Channel (3) == 3); // Lfe -> LFE
expect (map.getJuceChannelForVst3Channel (4) == 4); // Ls -> leftSurround
expect (map.getJuceChannelForVst3Channel (5) == 5); // Rs -> rightSurround
expect (map.getJuceChannelForVst3Channel (6) == 6); // Lc -> leftCentre
expect (map.getJuceChannelForVst3Channel (7) == 7); // Rc -> rightCentre
expect (map.getJuceChannelForVst3Channel (8) == 8); // Sl -> leftSurroundSide
expect (map.getJuceChannelForVst3Channel (9) == 9); // Sr -> rightSurroundSide
expect (map.getJuceChannelForVst3Channel (10) == 10); // Tfl -> topFrontLeft
expect (map.getJuceChannelForVst3Channel (11) == 11); // Tfr -> topFrontRight
expect (map.getJuceChannelForVst3Channel (12) == 12); // Trl -> topRearLeft
expect (map.getJuceChannelForVst3Channel (13) == 13); // Trr -> topRearRight
expect (map.getJuceChannelForVst3Channel (14) == 14); // Tsl -> topSideLeft
expect (map.getJuceChannelForVst3Channel (15) == 15); // Tsr -> topSideRight
}
beginTest ("ChannelMapping for a k91_6_W bus remaps the channels appropriately");
{
ChannelMapping map (AudioChannelSet::create9point1point6());
expect (map.size() == 16);
// VST3 order is:
// L
// R
// C
// Lfe
// Ls
// Rs
// Sl
// Sr
// Tfl
// Tfr
// Trl
// Trr
// Tsl
// Tsr
// Lw
// Rw
// JUCE order is:
// Left
// Right
// Centre
@ -97,22 +155,22 @@ public:
// Top Side Left
// Top Side Right
expect (map.getJuceChannelForVst3Channel (0) == 12); // L -> wideLeft
expect (map.getJuceChannelForVst3Channel (1) == 13); // R -> wideRight
expect (map.getJuceChannelForVst3Channel (0) == 0); // L -> left
expect (map.getJuceChannelForVst3Channel (1) == 1); // R -> right
expect (map.getJuceChannelForVst3Channel (2) == 2); // C -> centre
expect (map.getJuceChannelForVst3Channel (3) == 3); // Lfe -> LFE
expect (map.getJuceChannelForVst3Channel (4) == 10); // Ls -> leftSurroundRear
expect (map.getJuceChannelForVst3Channel (5) == 11); // Rs -> rightSurroundRear
expect (map.getJuceChannelForVst3Channel (6) == 0); // Lc -> left
expect (map.getJuceChannelForVst3Channel (7) == 1); // Rc -> right
expect (map.getJuceChannelForVst3Channel (8) == 4); // Sl -> leftSurroundSide
expect (map.getJuceChannelForVst3Channel (9) == 5); // Sl -> leftSurroundSide
expect (map.getJuceChannelForVst3Channel (10) == 6); // Tfl -> topFrontLeft
expect (map.getJuceChannelForVst3Channel (11) == 7); // Tfr -> topFrontRight
expect (map.getJuceChannelForVst3Channel (12) == 8); // Trl -> topRearLeft
expect (map.getJuceChannelForVst3Channel (13) == 9); // Trr -> topRearRight
expect (map.getJuceChannelForVst3Channel (14) == 14); // Tsl -> topSideLeft
expect (map.getJuceChannelForVst3Channel (15) == 15); // Tsr -> topSideRight
expect (map.getJuceChannelForVst3Channel (6) == 4); // Sl -> leftSurroundSide
expect (map.getJuceChannelForVst3Channel (7) == 5); // Sr -> rightSurroundSide
expect (map.getJuceChannelForVst3Channel (8) == 6); // Tfl -> topFrontLeft
expect (map.getJuceChannelForVst3Channel (9) == 7); // Tfr -> topFrontRight
expect (map.getJuceChannelForVst3Channel (10) == 8); // Trl -> topRearLeft
expect (map.getJuceChannelForVst3Channel (11) == 9); // Trr -> topRearRight
expect (map.getJuceChannelForVst3Channel (12) == 14); // Tsl -> topSideLeft
expect (map.getJuceChannelForVst3Channel (13) == 15); // Tsr -> topSideRight
expect (map.getJuceChannelForVst3Channel (14) == 12); // Lw -> wideLeft
expect (map.getJuceChannelForVst3Channel (15) == 13); // Lw -> wideRight
}
const auto blockSize = 128;