diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 55c63dd634..1f6d02f093 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -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 diff --git a/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h b/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h index 9de2a674a5..1d2edec24d 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h +++ b/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h @@ -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(); diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index 032e0f7c3d..5a8a089dc0 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -269,6 +269,8 @@ static std::optional 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 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 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 diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp index 2520a5de19..c020ae06ca 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp @@ -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;