Browse Source

Added support for Atmos 7.0.2 and 7.1.2 Surround formats

tags/2021-05-28
hogliux 7 years ago
parent
commit
82bc9da02c
5 changed files with 218 additions and 136 deletions
  1. +42
    -32
      modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp
  2. +17
    -1
      modules/juce_audio_basics/buffers/juce_AudioChannelSet.h
  3. +95
    -49
      modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp
  4. +48
    -40
      modules/juce_audio_processors/format_types/juce_VST3Common.h
  5. +16
    -14
      modules/juce_audio_processors/processors/juce_AudioProcessor.cpp

+ 42
- 32
modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp View File

@@ -68,6 +68,8 @@ String AudioChannelSet::getChannelTypeName (AudioChannelSet::ChannelType type)
case ambisonicX: return NEEDS_TRANS("Ambisonic X");
case ambisonicY: return NEEDS_TRANS("Ambisonic Y");
case ambisonicZ: return NEEDS_TRANS("Ambisonic Z");
case topSideLeft: return NEEDS_TRANS("Top Side Left");
case topSideRight: return NEEDS_TRANS("Top Side Right");
default: break;
}
@@ -108,6 +110,8 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT
case ambisonicX: return "X";
case ambisonicY: return "Y";
case ambisonicZ: return "Z";
case topSideLeft: return "Tsl";
case topSideRight: return "Tsr";
default: break;
}
@@ -147,6 +151,8 @@ AudioChannelSet::ChannelType AudioChannelSet::getChannelTypeFromAbbreviation (co
if (abbr == "X") return ambisonicX;
if (abbr == "Y") return ambisonicY;
if (abbr == "Z") return ambisonicZ;
if (abbr == "Tsl") return topSideLeft;
if (abbr == "Tsr") return topSideRight;
return unknown;
}
@@ -192,16 +198,18 @@ String AudioChannelSet::getDescription() const
if (*this == createLRS()) return "LRS";
if (*this == createLCRS()) return "LCRS";
if (*this == create5point0()) return "5.0 Surround";
if (*this == create5point1()) return "5.1 Surround";
if (*this == create6point0()) return "6.0 Surround";
if (*this == create6point1()) return "6.1 Surround";
if (*this == create6point0Music()) return "6.0 (Music) Surround";
if (*this == create6point1Music()) return "6.1 (Music) Surround";
if (*this == create7point0()) return "7.0 Surround";
if (*this == create7point1()) return "7.1 Surround";
if (*this == create7point0SDDS()) return "7.0 Surround SDDS";
if (*this == create7point1SDDS()) return "7.1 Surround SDDS";
if (*this == create5point0()) return "5.0 Surround";
if (*this == create5point1()) return "5.1 Surround";
if (*this == create6point0()) return "6.0 Surround";
if (*this == create6point1()) return "6.1 Surround";
if (*this == create6point0Music()) return "6.0 (Music) Surround";
if (*this == create6point1Music()) return "6.1 (Music) Surround";
if (*this == create7point0()) return "7.0 Surround";
if (*this == create7point1()) return "7.1 Surround";
if (*this == create7point0SDDS()) return "7.0 Surround SDDS";
if (*this == create7point1SDDS()) return "7.1 Surround SDDS";
if (*this == create7point0point2()) return "7.0.2 Surround";
if (*this == create7point1point2()) return "7.1.2 Surround";
if (*this == quadraphonic()) return "Quadraphonic";
if (*this == pentagonal()) return "Pentagonal";
@@ -215,7 +223,7 @@ String AudioChannelSet::getDescription() const
bool AudioChannelSet::isDiscreteLayout() const noexcept
{
for (auto& speaker : getChannelTypes())
if (speaker <= ambisonicZ)
if (speaker <= topSideRight)
return false;
return true;
@@ -275,27 +283,29 @@ void AudioChannelSet::removeChannel (ChannelType newChannel)
channels.clearBit (bit);
}
AudioChannelSet AudioChannelSet::disabled() { return {}; }
AudioChannelSet AudioChannelSet::mono() { return AudioChannelSet (1u << centre); }
AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ((1u << left) | (1u << right)); }
AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre)); }
AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << surround)); }
AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << surround)); }
AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround)); }
AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround)); }
AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); }
AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); }
AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); }
AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); }
AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); }
AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); }
AudioChannelSet AudioChannelSet::ambisonic() { return AudioChannelSet ((1u << ambisonicW) | (1u << ambisonicX) | (1u << ambisonicY) | (1u << ambisonicZ)); }
AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround)); }
AudioChannelSet AudioChannelSet::pentagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << centreSurround) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround) | (1u << wideLeft) | (1u << wideRight)); }
AudioChannelSet AudioChannelSet::disabled() { return {}; }
AudioChannelSet AudioChannelSet::mono() { return AudioChannelSet (1u << centre); }
AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ((1u << left) | (1u << right)); }
AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre)); }
AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << surround)); }
AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << surround)); }
AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround)); }
AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround)); }
AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); }
AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround)); }
AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); }
AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftSurroundSide) | (1u << rightSurroundSide)); }
AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); }
AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); }
AudioChannelSet AudioChannelSet::ambisonic() { return AudioChannelSet ((1u << ambisonicW) | (1u << ambisonicX) | (1u << ambisonicY) | (1u << ambisonicZ)); }
AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << leftSurround) | (1u << rightSurround)); }
AudioChannelSet AudioChannelSet::pentagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << centreSurround) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); }
AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << centreSurround) | (1u << wideLeft) | (1u << wideRight)); }
AudioChannelSet AudioChannelSet::create7point0point2() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topSideLeft) | (1u << topSideRight)); }
AudioChannelSet AudioChannelSet::create7point1point2() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << LFE) | (1u << leftSurroundSide) | (1u << rightSurroundSide) | (1u << leftSurroundRear) | (1u << rightSurroundRear) | (1u << topSideLeft) | (1u << topSideRight)); }
AudioChannelSet AudioChannelSet::discreteChannels (int numChannels)


+ 17
- 1
modules/juce_audio_basics/buffers/juce_AudioChannelSet.h View File

@@ -194,6 +194,18 @@ public:
*/
static AudioChannelSet JUCE_CALLTYPE create7point1SDDS();
/** Creates a set for Dolby Atmos 7.0.2 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight).
Is equivalent to: n/a (VST), AAX_eStemFormat_7_0_2 (AAX), n/a (CoreAudio)
*/
static AudioChannelSet JUCE_CALLTYPE create7point0point2();
/** Creates a set for Dolby Atmos 7.1.2 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE, topSideLeft, topSideRight).
Is equivalent to: k71_2 (VST), AAX_eStemFormat_7_1_2 (AAX), n/a (CoreAudio)
*/
static AudioChannelSet JUCE_CALLTYPE create7point1point2();
//==============================================================================
/** Creates a set for ambisonic surround setups (ambisonicW, ambisonicX, ambisonicY, ambisonicZ).
@@ -289,6 +301,10 @@ public:
ambisonicY = 26,
ambisonicZ = 27,
// Used by Dolby Atmos 7.0.2 and 7.1.2
topSideLeft = 28, // Lts (AAX), Tsl (VST)
topSideRight = 29, // Rts (AAX), Tsr (VST)
discreteChannel0 = 64 /**< Non-typed individual channels are indexed upwards from this value. */
};
@@ -305,7 +321,7 @@ public:
//==============================================================================
enum
{
maxChannelsOfNamedLayout = 8
maxChannelsOfNamedLayout = 10
};
/** Adds a channel to the set. */


+ 95
- 49
modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp View File

@@ -46,6 +46,10 @@
#pragma warning (disable : 4127 4512)
#endif
#include <AAX_Version.h>
static_assert (AAX_SDK_CURRENT_REVISION >= AAX_SDK_2p3p0_REVISION, "JUCE requires AAX SDK version 2.3.0 or higher");
#include <AAX_Exports.cpp>
#include <AAX_ICollection.h>
#include <AAX_IComponentDescriptor.h>
@@ -63,6 +67,9 @@
#include <AAX_IMIDINode.h>
#include <AAX_UtilsNative.h>
#include <AAX_Enums.h>
#include <AAX_IDescriptionHost.h>
#include <AAX_IFeatureInfo.h>
#include <AAX_UIDs.h>
#ifdef _MSC_VER
#pragma warning (pop)
@@ -134,25 +141,27 @@ namespace AAXClasses
struct AAXChannelStreamOrder
{
AAX_EStemFormat aaxStemFormat;
AudioChannelSet::ChannelType speakerOrder[8];
AudioChannelSet::ChannelType speakerOrder[10];
};
static AAXChannelStreamOrder aaxChannelOrder[] =
{
{AAX_eStemFormat_Mono, {AudioChannelSet::centre, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_Stereo, {AudioChannelSet::left, AudioChannelSet::right, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_LCR, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_LCRS, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::centreSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_Quad, {AudioChannelSet::left, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_5_0, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_5_1, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_6_0, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::centreSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_6_1, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::centreSurround, AudioChannelSet::rightSurround, AudioChannelSet::LFE, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_0_SDDS, {AudioChannelSet::left, AudioChannelSet::leftCentre, AudioChannelSet::centre, AudioChannelSet::rightCentre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_0_DTS, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_1_SDDS, {AudioChannelSet::left, AudioChannelSet::leftCentre, AudioChannelSet::centre, AudioChannelSet::rightCentre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::LFE}},
{AAX_eStemFormat_7_1_DTS, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE}},
{AAX_eStemFormat_None, {AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_Mono, {AudioChannelSet::centre, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_Stereo, {AudioChannelSet::left, AudioChannelSet::right, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_LCR, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_LCRS, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::centreSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_Quad, {AudioChannelSet::left, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_5_0, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_5_1, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_6_0, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::centreSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_6_1, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::centreSurround, AudioChannelSet::rightSurround, AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_0_SDDS, {AudioChannelSet::left, AudioChannelSet::leftCentre, AudioChannelSet::centre, AudioChannelSet::rightCentre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_0_DTS, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_1_SDDS, {AudioChannelSet::left, AudioChannelSet::leftCentre, AudioChannelSet::centre, AudioChannelSet::rightCentre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_1_DTS, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_0_2, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight, AudioChannelSet::unknown}},
{AAX_eStemFormat_7_1_2, {AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight}},
{AAX_eStemFormat_None, {AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown}},
};
static AAX_EStemFormat aaxFormats[] =
@@ -169,7 +178,9 @@ namespace AAXClasses
AAX_eStemFormat_7_0_SDDS,
AAX_eStemFormat_7_1_SDDS,
AAX_eStemFormat_7_0_DTS,
AAX_eStemFormat_7_1_DTS
AAX_eStemFormat_7_1_DTS,
AAX_eStemFormat_7_0_2,
AAX_eStemFormat_7_1_2
};
static AAX_EStemFormat getFormatForAudioChannelSet (const AudioChannelSet& set, bool ignoreLayout) noexcept
@@ -179,15 +190,17 @@ namespace AAXClasses
{
switch (set.size())
{
case 0: return AAX_eStemFormat_None;
case 1: return AAX_eStemFormat_Mono;
case 2: return AAX_eStemFormat_Stereo;
case 3: return AAX_eStemFormat_LCR;
case 4: return AAX_eStemFormat_Quad;
case 5: return AAX_eStemFormat_5_0;
case 6: return AAX_eStemFormat_5_1;
case 7: return AAX_eStemFormat_7_0_DTS;
case 8: return AAX_eStemFormat_7_1_DTS;
case 0: return AAX_eStemFormat_None;
case 1: return AAX_eStemFormat_Mono;
case 2: return AAX_eStemFormat_Stereo;
case 3: return AAX_eStemFormat_LCR;
case 4: return AAX_eStemFormat_Quad;
case 5: return AAX_eStemFormat_5_0;
case 6: return AAX_eStemFormat_5_1;
case 7: return AAX_eStemFormat_7_0_DTS;
case 8: return AAX_eStemFormat_7_1_DTS;
case 9: return AAX_eStemFormat_7_0_2;
case 10: return AAX_eStemFormat_7_1_2;
default:
break;
}
@@ -195,20 +208,22 @@ namespace AAXClasses
return AAX_eStemFormat_INT32_MAX;
}
if (set == AudioChannelSet::disabled()) return AAX_eStemFormat_None;
if (set == AudioChannelSet::mono()) return AAX_eStemFormat_Mono;
if (set == AudioChannelSet::stereo()) return AAX_eStemFormat_Stereo;
if (set == AudioChannelSet::createLCR()) return AAX_eStemFormat_LCR;
if (set == AudioChannelSet::createLCRS()) return AAX_eStemFormat_LCRS;
if (set == AudioChannelSet::quadraphonic()) return AAX_eStemFormat_Quad;
if (set == AudioChannelSet::create5point0()) return AAX_eStemFormat_5_0;
if (set == AudioChannelSet::create5point1()) return AAX_eStemFormat_5_1;
if (set == AudioChannelSet::create6point0()) return AAX_eStemFormat_6_0;
if (set == AudioChannelSet::create6point1()) return AAX_eStemFormat_6_1;
if (set == AudioChannelSet::create7point0()) return AAX_eStemFormat_7_0_DTS;
if (set == AudioChannelSet::create7point1()) return AAX_eStemFormat_7_1_DTS;
if (set == AudioChannelSet::create7point0SDDS()) return AAX_eStemFormat_7_0_SDDS;
if (set == AudioChannelSet::create7point1SDDS()) return AAX_eStemFormat_7_1_SDDS;
if (set == AudioChannelSet::disabled()) return AAX_eStemFormat_None;
if (set == AudioChannelSet::mono()) return AAX_eStemFormat_Mono;
if (set == AudioChannelSet::stereo()) return AAX_eStemFormat_Stereo;
if (set == AudioChannelSet::createLCR()) return AAX_eStemFormat_LCR;
if (set == AudioChannelSet::createLCRS()) return AAX_eStemFormat_LCRS;
if (set == AudioChannelSet::quadraphonic()) return AAX_eStemFormat_Quad;
if (set == AudioChannelSet::create5point0()) return AAX_eStemFormat_5_0;
if (set == AudioChannelSet::create5point1()) return AAX_eStemFormat_5_1;
if (set == AudioChannelSet::create6point0()) return AAX_eStemFormat_6_0;
if (set == AudioChannelSet::create6point1()) return AAX_eStemFormat_6_1;
if (set == AudioChannelSet::create7point0()) return AAX_eStemFormat_7_0_DTS;
if (set == AudioChannelSet::create7point1()) return AAX_eStemFormat_7_1_DTS;
if (set == AudioChannelSet::create7point0SDDS()) return AAX_eStemFormat_7_0_SDDS;
if (set == AudioChannelSet::create7point1SDDS()) return AAX_eStemFormat_7_1_SDDS;
if (set == AudioChannelSet::create7point0point2()) return AAX_eStemFormat_7_0_2;
if (set == AudioChannelSet::create7point1point2()) return AAX_eStemFormat_7_1_2;
return AAX_eStemFormat_INT32_MAX;
}
@@ -233,6 +248,8 @@ namespace AAXClasses
case AAX_eStemFormat_7_0_DTS: return AudioChannelSet::create7point0();
case AAX_eStemFormat_7_1_SDDS: return AudioChannelSet::create7point1SDDS();
case AAX_eStemFormat_7_1_DTS: return AudioChannelSet::create7point1();
case AAX_eStemFormat_7_0_2: return AudioChannelSet::create7point0point2();
case AAX_eStemFormat_7_1_2: return AudioChannelSet::create7point1point2();
default:
break;
}
@@ -267,8 +284,9 @@ namespace AAXClasses
const AAXChannelStreamOrder& channelOrder = aaxChannelOrder[layoutIndex];
const AudioChannelSet::ChannelType channelType = channelSet.getTypeOfChannel (static_cast<int> (juceIndex));
auto numSpeakers = numElementsInArray (channelOrder.speakerOrder);
for (int i = 0; i < 8 && channelOrder.speakerOrder[i] != 0; ++i)
for (int i = 0; i < numSpeakers && channelOrder.speakerOrder[i] != 0; ++i)
if (channelOrder.speakerOrder[i] == channelType)
return i;
@@ -1893,7 +1911,25 @@ namespace AAXClasses
check (desc.AddProcessProc_Native (algorithmProcessCallback, properties));
}
static void getPlugInDescription (AAX_IEffectDescriptor& descriptor)
static bool hostSupportsStemFormat (AAX_EStemFormat stemFormat, const AAX_IFeatureInfo* featureInfo)
{
if (featureInfo != nullptr)
{
AAX_ESupportLevel supportLevel;
if (featureInfo->SupportLevel (supportLevel) == AAX_SUCCESS && supportLevel == AAX_eSupportLevel_ByProperty)
{
ScopedPointer<const AAX_IPropertyMap> props (featureInfo->AcquireProperties());
if (props != nullptr && props->GetProperty ((AAX_EProperty) stemFormat, (AAX_CPropertyValue*) &supportLevel) != 0)
return (supportLevel == AAX_eSupportLevel_Supported);
}
}
return (AAX_STEM_FORMAT_INDEX (stemFormat) <= 12);
}
static void getPlugInDescription (AAX_IEffectDescriptor& descriptor, const AAX_IFeatureInfo* featureInfo)
{
PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_AAX;
ScopedPointer<AudioProcessor> plugin = createPluginFilterOfType (AudioProcessor::wrapperType_AAX);
@@ -1949,14 +1985,17 @@ namespace AAXClasses
AAX_EStemFormat aaxOutFormat = numOuts > 0 ? aaxFormats[outIdx] : AAX_eStemFormat_None;
AudioChannelSet outLayout = channelSetFromStemFormat (aaxOutFormat, false);
AudioProcessor::BusesLayout fullLayout;
if (! JuceAAX_Processor::fullBusesLayoutFromMainLayout (*plugin, inLayout, outLayout, fullLayout))
continue;
if (AAX_IComponentDescriptor* const desc = descriptor.NewComponentDescriptor())
if (hostSupportsStemFormat (aaxInFormat, featureInfo) && hostSupportsStemFormat (aaxOutFormat, featureInfo))
{
createDescriptor (*desc, fullLayout, *plugin, pluginIds, numMeters);
check (descriptor.AddComponent (desc));
AudioProcessor::BusesLayout fullLayout;
if (! JuceAAX_Processor::fullBusesLayoutFromMainLayout (*plugin, inLayout, outLayout, fullLayout))
continue;
if (AAX_IComponentDescriptor* const desc = descriptor.NewComponentDescriptor())
{
createDescriptor (*desc, fullLayout, *plugin, pluginIds, numMeters);
check (descriptor.AddComponent (desc));
}
}
}
}
@@ -1972,15 +2011,22 @@ void AAX_CALLBACK AAXClasses::algorithmProcessCallback (JUCEAlgorithmContext* co
AAXClasses::JuceAAX_Processor::algorithmCallback (instancesBegin, instancesEnd);
}
//==============================================================================
//==============================================================================
AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection*);
AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection* collection)
{
ScopedJuceInitialiser_GUI libraryInitialiser;
ScopedPointer<const AAX_IFeatureInfo> stemFormatFeatureInfo;
if (const auto* hostDescription = collection->DescriptionHost())
stemFormatFeatureInfo = hostDescription->AcquireFeatureProperties (AAXATTR_ClientFeature_StemFormat);
if (AAX_IEffectDescriptor* const descriptor = collection->NewDescriptor())
{
AAXClasses::getPlugInDescription (*descriptor);
AAXClasses::getPlugInDescription (*descriptor, stemFormatFeatureInfo);
collection->AddEffect (JUCE_STRINGIFY (JucePlugin_AAXIdentifier), descriptor);
collection->SetManufacturerName (JucePlugin_Manufacturer);


+ 48
- 40
modules/juce_audio_processors/format_types/juce_VST3Common.h View File

@@ -173,6 +173,8 @@ static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set
case AudioChannelSet::ambisonicX: return (1 << 21); /* kSpeakerX */
case AudioChannelSet::ambisonicY: return (1 << 22); /* kSpeakerY */
case AudioChannelSet::ambisonicZ: return (1 << 23); /* kSpeakerZ */
case AudioChannelSet::topSideLeft: return (1 << 24); /* kSpeakerTsl */
case AudioChannelSet::topSideRight: return (1 << 25); /* kSpeakerTsr */
case AudioChannelSet::discreteChannel0: return kSpeakerM;
default:
@@ -182,8 +184,6 @@ static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set
switch (static_cast<int> (type))
{
case (int) AudioChannelSet::discreteChannel0 + 1: return (1 << 24); /* kSpeakerTsl */
case (int) AudioChannelSet::discreteChannel0 + 2: return (1 << 25); /* kSpeakerTsr */
case (int) AudioChannelSet::discreteChannel0 + 3: return (1 << 28); /* kSpeakerBfl */
case (int) AudioChannelSet::discreteChannel0 + 4: return (1 << 29); /* kSpeakerBfc */
case (int) AudioChannelSet::discreteChannel0 + 5: return (1 << 30); /* kSpeakerBfr */
@@ -225,8 +225,8 @@ static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::Speak
case (1 << 21): return AudioChannelSet::ambisonicX; /* kSpeakerX */
case (1 << 22): return AudioChannelSet::ambisonicY; /* kSpeakerY */
case (1 << 23): return AudioChannelSet::ambisonicZ; /* kSpeakerZ */
case (1 << 24): return static_cast<AudioChannelSet::ChannelType> ((int)AudioChannelSet::discreteChannel0 + 1); /* kSpeakerTsl */
case (1 << 25): return static_cast<AudioChannelSet::ChannelType> ((int)AudioChannelSet::discreteChannel0 + 2); /* kSpeakerTsr */
case (1 << 24): return AudioChannelSet::topSideLeft; /* kSpeakerTsl */
case (1 << 25): return AudioChannelSet::topSideRight; /* kSpeakerTsr */
case (1 << 26): return AudioChannelSet::leftSurroundSide; /* kSpeakerLcs */
case (1 << 27): return AudioChannelSet::rightSurroundSide; /* kSpeakerRcs */
case (1 << 28): return static_cast<AudioChannelSet::ChannelType> ((int)AudioChannelSet::discreteChannel0 + 3); /* kSpeakerBfl */
@@ -247,24 +247,28 @@ static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::Speak
static inline Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (const AudioChannelSet& channels) noexcept
{
if (channels == AudioChannelSet::disabled()) return Steinberg::Vst::SpeakerArr::kEmpty;
else if (channels == AudioChannelSet::mono()) return Steinberg::Vst::SpeakerArr::kMono;
else if (channels == AudioChannelSet::stereo()) return Steinberg::Vst::SpeakerArr::kStereo;
else if (channels == AudioChannelSet::createLCR()) return Steinberg::Vst::SpeakerArr::k30Cine;
else if (channels == AudioChannelSet::createLRS()) return Steinberg::Vst::SpeakerArr::k30Music;
else if (channels == AudioChannelSet::createLCRS()) return Steinberg::Vst::SpeakerArr::k40Cine;
else if (channels == AudioChannelSet::create5point0()) return Steinberg::Vst::SpeakerArr::k50;
else if (channels == AudioChannelSet::create5point1()) return Steinberg::Vst::SpeakerArr::k51;
else if (channels == AudioChannelSet::create6point0()) return Steinberg::Vst::SpeakerArr::k60Cine;
else if (channels == AudioChannelSet::create6point1()) return Steinberg::Vst::SpeakerArr::k61Cine;
else if (channels == AudioChannelSet::create6point0Music()) return Steinberg::Vst::SpeakerArr::k60Music;
else if (channels == AudioChannelSet::create6point1Music()) return Steinberg::Vst::SpeakerArr::k61Music;
else if (channels == AudioChannelSet::create7point0()) return Steinberg::Vst::SpeakerArr::k70Music;
else if (channels == AudioChannelSet::create7point0SDDS()) return Steinberg::Vst::SpeakerArr::k70Cine;
else if (channels == AudioChannelSet::create7point1()) return Steinberg::Vst::SpeakerArr::k71CineSideFill;
else if (channels == AudioChannelSet::create7point1SDDS()) return Steinberg::Vst::SpeakerArr::k71Cine;
else if (channels == AudioChannelSet::ambisonic()) return Steinberg::Vst::SpeakerArr::kBFormat;
else if (channels == AudioChannelSet::quadraphonic()) return Steinberg::Vst::SpeakerArr::k40Music;
using namespace Steinberg::Vst::SpeakerArr;
if (channels == AudioChannelSet::disabled()) return kEmpty;
else if (channels == AudioChannelSet::mono()) return kMono;
else if (channels == AudioChannelSet::stereo()) return kStereo;
else if (channels == AudioChannelSet::createLCR()) return k30Cine;
else if (channels == AudioChannelSet::createLRS()) return k30Music;
else if (channels == AudioChannelSet::createLCRS()) return k40Cine;
else if (channels == AudioChannelSet::create5point0()) return k50;
else if (channels == AudioChannelSet::create5point1()) return k51;
else if (channels == AudioChannelSet::create6point0()) return k60Cine;
else if (channels == AudioChannelSet::create6point1()) return k61Cine;
else if (channels == AudioChannelSet::create6point0Music()) return k60Music;
else if (channels == AudioChannelSet::create6point1Music()) return k61Music;
else if (channels == AudioChannelSet::create7point0()) return k70Music;
else if (channels == AudioChannelSet::create7point0SDDS()) return k70Cine;
else if (channels == AudioChannelSet::create7point1()) return k71CineSideFill;
else if (channels == AudioChannelSet::create7point1SDDS()) return k71Cine;
else if (channels == AudioChannelSet::ambisonic()) return kBFormat;
else if (channels == AudioChannelSet::quadraphonic()) return k40Music;
else if (channels == AudioChannelSet::create7point0point2()) return k71_2 & ~(Steinberg::Vst::kSpeakerLfe);
else if (channels == AudioChannelSet::create7point1point2()) return k71_2;
Steinberg::Vst::SpeakerArrangement result = 0;
@@ -278,24 +282,28 @@ static inline Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (cons
static inline AudioChannelSet getChannelSetForSpeakerArrangement (Steinberg::Vst::SpeakerArrangement arr) noexcept
{
if (arr == Steinberg::Vst::SpeakerArr::kEmpty) return AudioChannelSet::disabled();
else if (arr == Steinberg::Vst::SpeakerArr::kMono) return AudioChannelSet::mono();
else if (arr == Steinberg::Vst::SpeakerArr::kStereo) return AudioChannelSet::stereo();
else if (arr == Steinberg::Vst::SpeakerArr::k30Cine) return AudioChannelSet::createLCR();
else if (arr == Steinberg::Vst::SpeakerArr::k30Music) return AudioChannelSet::createLRS();
else if (arr == Steinberg::Vst::SpeakerArr::k40Cine) return AudioChannelSet::createLCRS();
else if (arr == Steinberg::Vst::SpeakerArr::k50) return AudioChannelSet::create5point0();
else if (arr == Steinberg::Vst::SpeakerArr::k51) return AudioChannelSet::create5point1();
else if (arr == Steinberg::Vst::SpeakerArr::k60Cine) return AudioChannelSet::create6point0();
else if (arr == Steinberg::Vst::SpeakerArr::k61Cine) return AudioChannelSet::create6point1();
else if (arr == Steinberg::Vst::SpeakerArr::k60Music) return AudioChannelSet::create6point0Music();
else if (arr == Steinberg::Vst::SpeakerArr::k61Music) return AudioChannelSet::create6point1Music();
else if (arr == Steinberg::Vst::SpeakerArr::k70Music) return AudioChannelSet::create7point0();
else if (arr == Steinberg::Vst::SpeakerArr::k70Cine) return AudioChannelSet::create7point0SDDS();
else if (arr == Steinberg::Vst::SpeakerArr::k71CineSideFill) return AudioChannelSet::create7point1();
else if (arr == Steinberg::Vst::SpeakerArr::k71Cine) return AudioChannelSet::create7point1SDDS();
else if (arr == Steinberg::Vst::SpeakerArr::kBFormat) return AudioChannelSet::ambisonic();
else if (arr == Steinberg::Vst::SpeakerArr::k40Music) return AudioChannelSet::quadraphonic();
using namespace Steinberg::Vst::SpeakerArr;
if (arr == kEmpty) return AudioChannelSet::disabled();
else if (arr == kMono) return AudioChannelSet::mono();
else if (arr == kStereo) return AudioChannelSet::stereo();
else if (arr == k30Cine) return AudioChannelSet::createLCR();
else if (arr == k30Music) return AudioChannelSet::createLRS();
else if (arr == k40Cine) return AudioChannelSet::createLCRS();
else if (arr == k50) return AudioChannelSet::create5point0();
else if (arr == k51) return AudioChannelSet::create5point1();
else if (arr == k60Cine) return AudioChannelSet::create6point0();
else if (arr == k61Cine) return AudioChannelSet::create6point1();
else if (arr == k60Music) return AudioChannelSet::create6point0Music();
else if (arr == k61Music) return AudioChannelSet::create6point1Music();
else if (arr == k70Music) return AudioChannelSet::create7point0();
else if (arr == k70Cine) return AudioChannelSet::create7point0SDDS();
else if (arr == k71CineSideFill) return AudioChannelSet::create7point1();
else if (arr == k71Cine) return AudioChannelSet::create7point1SDDS();
else if (arr == kBFormat) return AudioChannelSet::ambisonic();
else if (arr == k40Music) return AudioChannelSet::quadraphonic();
else if (arr == k71_2) return AudioChannelSet::create7point1point2();
else if (arr == (k71_2 & ~(Steinberg::Vst::kSpeakerLfe))) return AudioChannelSet::create7point0point2();
AudioChannelSet result;


+ 16
- 14
modules/juce_audio_processors/processors/juce_AudioProcessor.cpp View File

@@ -1349,20 +1349,22 @@ int32 AudioProcessor::getAAXPluginIDForMainBusConfig (const AudioChannelSet& mai
const AudioChannelSet& set = (isInput ? mainInputLayout : mainOutputLayout);
int aaxFormatIndex = 0;
if (set == AudioChannelSet::disabled()) aaxFormatIndex = 0;
else if (set == AudioChannelSet::mono()) aaxFormatIndex = 1;
else if (set == AudioChannelSet::stereo()) aaxFormatIndex = 2;
else if (set == AudioChannelSet::createLCR()) aaxFormatIndex = 3;
else if (set == AudioChannelSet::createLCRS()) aaxFormatIndex = 4;
else if (set == AudioChannelSet::quadraphonic()) aaxFormatIndex = 5;
else if (set == AudioChannelSet::create5point0()) aaxFormatIndex = 6;
else if (set == AudioChannelSet::create5point1()) aaxFormatIndex = 7;
else if (set == AudioChannelSet::create6point0()) aaxFormatIndex = 8;
else if (set == AudioChannelSet::create6point1()) aaxFormatIndex = 9;
else if (set == AudioChannelSet::create7point0()) aaxFormatIndex = 10;
else if (set == AudioChannelSet::create7point1()) aaxFormatIndex = 11;
else if (set == AudioChannelSet::create7point0SDDS()) aaxFormatIndex = 12;
else if (set == AudioChannelSet::create7point1SDDS()) aaxFormatIndex = 13;
if (set == AudioChannelSet::disabled()) aaxFormatIndex = 0;
else if (set == AudioChannelSet::mono()) aaxFormatIndex = 1;
else if (set == AudioChannelSet::stereo()) aaxFormatIndex = 2;
else if (set == AudioChannelSet::createLCR()) aaxFormatIndex = 3;
else if (set == AudioChannelSet::createLCRS()) aaxFormatIndex = 4;
else if (set == AudioChannelSet::quadraphonic()) aaxFormatIndex = 5;
else if (set == AudioChannelSet::create5point0()) aaxFormatIndex = 6;
else if (set == AudioChannelSet::create5point1()) aaxFormatIndex = 7;
else if (set == AudioChannelSet::create6point0()) aaxFormatIndex = 8;
else if (set == AudioChannelSet::create6point1()) aaxFormatIndex = 9;
else if (set == AudioChannelSet::create7point0()) aaxFormatIndex = 10;
else if (set == AudioChannelSet::create7point1()) aaxFormatIndex = 11;
else if (set == AudioChannelSet::create7point0SDDS()) aaxFormatIndex = 12;
else if (set == AudioChannelSet::create7point1SDDS()) aaxFormatIndex = 13;
else if (set == AudioChannelSet::create7point0point2()) aaxFormatIndex = 14;
else if (set == AudioChannelSet::create7point1point2()) aaxFormatIndex = 15;
else
{
// AAX does not support this format and the wrapper should not have


Loading…
Cancel
Save