| @@ -23,7 +23,12 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| AudioChannelSet::AudioChannelSet (uint32 c) : channels (c) {} | |||||
| AudioChannelSet::AudioChannelSet (uint32 c) : channels (static_cast<int64> (c)) | |||||
| { | |||||
| } | |||||
| AudioChannelSet::AudioChannelSet (const Array<ChannelType>& c) | AudioChannelSet::AudioChannelSet (const Array<ChannelType>& c) | ||||
| { | { | ||||
| for (auto channel : c) | for (auto channel : c) | ||||
| @@ -106,15 +111,18 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT | |||||
| case LFE2: return "Lfe2"; | case LFE2: return "Lfe2"; | ||||
| case leftSurroundSide: return "Lss"; | case leftSurroundSide: return "Lss"; | ||||
| case rightSurroundSide: return "Rss"; | case rightSurroundSide: return "Rss"; | ||||
| case ambisonicW: return "W"; | |||||
| case ambisonicX: return "X"; | |||||
| case ambisonicY: return "Y"; | |||||
| case ambisonicZ: return "Z"; | |||||
| case ambisonicACN0: return "ACN0"; | |||||
| case ambisonicACN1: return "ACN1"; | |||||
| case ambisonicACN2: return "ACN2"; | |||||
| case ambisonicACN3: return "ACN3"; | |||||
| case topSideLeft: return "Tsl"; | case topSideLeft: return "Tsl"; | ||||
| case topSideRight: return "Tsr"; | case topSideRight: return "Tsr"; | ||||
| default: break; | default: break; | ||||
| } | } | ||||
| if (type >= ambisonicACN4 && type <= ambisonicACN35) | |||||
| return "ACN" + String (type - ambisonicACN4 + 4); | |||||
| return {}; | return {}; | ||||
| } | } | ||||
| @@ -215,7 +223,26 @@ String AudioChannelSet::getDescription() const | |||||
| if (*this == pentagonal()) return "Pentagonal"; | if (*this == pentagonal()) return "Pentagonal"; | ||||
| if (*this == hexagonal()) return "Hexagonal"; | if (*this == hexagonal()) return "Hexagonal"; | ||||
| if (*this == octagonal()) return "Octagonal"; | if (*this == octagonal()) return "Octagonal"; | ||||
| if (*this == ambisonic()) return "Ambisonic"; | |||||
| // ambisonics | |||||
| { | |||||
| auto order = getAmbisonicOrder(); | |||||
| if (order >= 0) | |||||
| { | |||||
| String suffix; | |||||
| switch (order) | |||||
| { | |||||
| case 1: suffix = "st"; break; | |||||
| case 2: suffix = "nd"; break; | |||||
| case 3: suffix = "rd"; break; | |||||
| default: suffix = "th"; break; | |||||
| } | |||||
| return String (order) + suffix + " Order Ambisonics"; | |||||
| } | |||||
| } | |||||
| return "Unknown"; | return "Unknown"; | ||||
| } | } | ||||
| @@ -223,7 +250,7 @@ String AudioChannelSet::getDescription() const | |||||
| bool AudioChannelSet::isDiscreteLayout() const noexcept | bool AudioChannelSet::isDiscreteLayout() const noexcept | ||||
| { | { | ||||
| for (auto& speaker : getChannelTypes()) | for (auto& speaker : getChannelTypes()) | ||||
| if (speaker <= topSideRight) | |||||
| if (speaker <= ambisonicACN35) | |||||
| return false; | return false; | ||||
| return true; | return true; | ||||
| @@ -299,7 +326,6 @@ AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet | |||||
| AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << leftSurround) | (1u << rightSurround) | (1u << leftCentre) | (1u << rightCentre)); } | 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::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::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::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::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::hexagonal() { return AudioChannelSet ((1u << left) | (1u << right) | (1u << centre) | (1u << centreSurround) | (1u << leftSurroundRear) | (1u << rightSurroundRear)); } | ||||
| @@ -307,6 +333,30 @@ AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet | |||||
| 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::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::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::ambisonic (int order) | |||||
| { | |||||
| jassert (isPositiveAndBelow (order, 6)); | |||||
| if (order == 0) | |||||
| return AudioChannelSet ((uint32) (1 << ambisonicACN0)); | |||||
| AudioChannelSet set ((1u << ambisonicACN0) | (1u << ambisonicACN1) | (1u << ambisonicACN2) | (1u << ambisonicACN3)); | |||||
| auto numAmbisonicChannels = (order + 1) * (order + 1); | |||||
| set.channels.setRange (ambisonicACN4, numAmbisonicChannels - 4, true); | |||||
| return set; | |||||
| } | |||||
| int AudioChannelSet::getAmbisonicOrder() const | |||||
| { | |||||
| auto ambisonicOrder = getAmbisonicOrderForNumChannels (size()); | |||||
| if (ambisonicOrder >= 0) | |||||
| return (*this == ambisonic (ambisonicOrder) ? ambisonicOrder : -1); | |||||
| return -1; | |||||
| } | |||||
| AudioChannelSet AudioChannelSet::discreteChannels (int numChannels) | AudioChannelSet AudioChannelSet::discreteChannels (int numChannels) | ||||
| { | { | ||||
| @@ -368,7 +418,6 @@ Array<AudioChannelSet> AudioChannelSet::channelSetsWithNumberOfChannels (int num | |||||
| { | { | ||||
| retval.add (AudioChannelSet::quadraphonic()); | retval.add (AudioChannelSet::quadraphonic()); | ||||
| retval.add (AudioChannelSet::createLCRS()); | retval.add (AudioChannelSet::createLCRS()); | ||||
| retval.add (AudioChannelSet::ambisonic()); | |||||
| } | } | ||||
| else if (numChannels == 5) | else if (numChannels == 5) | ||||
| { | { | ||||
| @@ -395,6 +444,10 @@ Array<AudioChannelSet> AudioChannelSet::channelSetsWithNumberOfChannels (int num | |||||
| retval.add (AudioChannelSet::create7point1SDDS()); | retval.add (AudioChannelSet::create7point1SDDS()); | ||||
| retval.add (AudioChannelSet::octagonal()); | retval.add (AudioChannelSet::octagonal()); | ||||
| } | } | ||||
| auto order = getAmbisonicOrderForNumChannels (numChannels); | |||||
| if (order >= 0) | |||||
| retval.add (AudioChannelSet::ambisonic (order)); | |||||
| } | } | ||||
| return retval; | return retval; | ||||
| @@ -428,4 +481,106 @@ int32 AudioChannelSet::getWaveChannelMask() const noexcept | |||||
| return (channels.toInteger() >> 1); | return (channels.toInteger() >> 1); | ||||
| } | } | ||||
| //============================================================================== | |||||
| int JUCE_CALLTYPE AudioChannelSet::getAmbisonicOrderForNumChannels (int numChannels) | |||||
| { | |||||
| auto sqrtMinusOne = std::sqrt (static_cast<float> (numChannels)) - 1.0f; | |||||
| auto ambisonicOrder = jmax (0, static_cast<int> (std::floor (sqrtMinusOne))); | |||||
| if (ambisonicOrder > 5) | |||||
| return -1; | |||||
| return (static_cast<float> (ambisonicOrder) == sqrtMinusOne ? ambisonicOrder : -1); | |||||
| } | |||||
| //============================================================================== | |||||
| #if JUCE_UNIT_TESTS | |||||
| class AudioChannelSetUnitTest : public UnitTest | |||||
| { | |||||
| public: | |||||
| AudioChannelSetUnitTest() : UnitTest ("AudioChannelSetUnitTest", "Audio") {} | |||||
| void runTest() override | |||||
| { | |||||
| auto max = AudioChannelSet::maxChannelsOfNamedLayout; | |||||
| beginTest ("maxChannelsOfNamedLayout is non-discrete"); | |||||
| expect (AudioChannelSet::channelSetsWithNumberOfChannels (max).size() >= 2); | |||||
| beginTest ("channelSetsWithNumberOfChannels returns correct speaker count"); | |||||
| { | |||||
| for (auto ch = 1; ch <= max; ++ch) | |||||
| { | |||||
| auto channelSets = AudioChannelSet::channelSetsWithNumberOfChannels (ch); | |||||
| for (auto set : channelSets) | |||||
| expect (set.size() == ch); | |||||
| } | |||||
| } | |||||
| beginTest ("Ambisonics"); | |||||
| { | |||||
| uint64 mask = 0; | |||||
| mask |= (1ull << AudioChannelSet::ambisonicACN0); | |||||
| checkAmbisonic (mask, 0, "0th Order Ambisonics"); | |||||
| mask |= (1ull << AudioChannelSet::ambisonicACN1) | (1ull << AudioChannelSet::ambisonicACN2) | (1ull << AudioChannelSet::ambisonicACN3); | |||||
| checkAmbisonic (mask, 1, "1st Order Ambisonics"); | |||||
| mask |= (1ull << AudioChannelSet::ambisonicACN4) | (1ull << AudioChannelSet::ambisonicACN5) | (1ull << AudioChannelSet::ambisonicACN6) | |||||
| | (1ull << AudioChannelSet::ambisonicACN7) | (1ull << AudioChannelSet::ambisonicACN8); | |||||
| checkAmbisonic (mask, 2, "2nd Order Ambisonics"); | |||||
| mask |= (1ull << AudioChannelSet::ambisonicACN9) | (1ull << AudioChannelSet::ambisonicACN10) | (1ull << AudioChannelSet::ambisonicACN11) | |||||
| | (1ull << AudioChannelSet::ambisonicACN12) | (1ull << AudioChannelSet::ambisonicACN13) | (1ull << AudioChannelSet::ambisonicACN14) | |||||
| | (1ull << AudioChannelSet::ambisonicACN15); | |||||
| checkAmbisonic (mask, 3, "3rd Order Ambisonics"); | |||||
| mask |= (1ull << AudioChannelSet::ambisonicACN16) | (1ull << AudioChannelSet::ambisonicACN17) | (1ull << AudioChannelSet::ambisonicACN18) | |||||
| | (1ull << AudioChannelSet::ambisonicACN19) | (1ull << AudioChannelSet::ambisonicACN20) | (1ull << AudioChannelSet::ambisonicACN21) | |||||
| | (1ull << AudioChannelSet::ambisonicACN22) | (1ull << AudioChannelSet::ambisonicACN23) | (1ull << AudioChannelSet::ambisonicACN24); | |||||
| checkAmbisonic (mask, 4, "4th Order Ambisonics"); | |||||
| mask |= (1ull << AudioChannelSet::ambisonicACN25) | (1ull << AudioChannelSet::ambisonicACN26) | (1ull << AudioChannelSet::ambisonicACN27) | |||||
| | (1ull << AudioChannelSet::ambisonicACN28) | (1ull << AudioChannelSet::ambisonicACN29) | (1ull << AudioChannelSet::ambisonicACN30) | |||||
| | (1ull << AudioChannelSet::ambisonicACN31) | (1ull << AudioChannelSet::ambisonicACN32) | (1ull << AudioChannelSet::ambisonicACN33) | |||||
| | (1ull << AudioChannelSet::ambisonicACN34) | (1ull << AudioChannelSet::ambisonicACN35); | |||||
| checkAmbisonic (mask, 5, "5th Order Ambisonics"); | |||||
| } | |||||
| } | |||||
| private: | |||||
| void checkAmbisonic (uint64 mask, int order, const char* layoutName) | |||||
| { | |||||
| auto expected = AudioChannelSet::ambisonic (order); | |||||
| auto numChannels = expected.size(); | |||||
| expect (numChannels == BigInteger ((int64) mask).countNumberOfSetBits()); | |||||
| expect (channelSetFromMask (mask) == expected); | |||||
| expect (order == expected.getAmbisonicOrder()); | |||||
| expect (expected.getDescription() == layoutName); | |||||
| auto layouts = AudioChannelSet::channelSetsWithNumberOfChannels (numChannels); | |||||
| expect (layouts.contains (expected)); | |||||
| for (auto layout : layouts) | |||||
| expect (layout.getAmbisonicOrder() == (layout == expected ? order : -1)); | |||||
| } | |||||
| static AudioChannelSet channelSetFromMask (uint64 mask) | |||||
| { | |||||
| Array<AudioChannelSet::ChannelType> channels; | |||||
| for (int bit = 0; bit <= 62; ++bit) | |||||
| if ((mask & (1ull << bit)) != 0) | |||||
| channels.add (static_cast<AudioChannelSet::ChannelType> (bit)); | |||||
| return AudioChannelSet::channelSetWithChannels (channels); | |||||
| } | |||||
| }; | |||||
| static AudioChannelSetUnitTest audioChannelSetUnitTest; | |||||
| #endif | |||||
| } // namespace juce | } // namespace juce | ||||
| @@ -208,13 +208,6 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Creates a set for ambisonic surround setups (ambisonicW, ambisonicX, ambisonicY, ambisonicZ). | |||||
| Is equivalent to: kBFormat (VST), n/a (AAX), kAudioChannelLayoutTag_Ambisonic_B_Format (CoreAudio) | |||||
| */ | |||||
| static AudioChannelSet JUCE_CALLTYPE ambisonic(); | |||||
| /** Creates a set for quadraphonic surround setup (left, right, leftSurround, rightSurround) | /** Creates a set for quadraphonic surround setup (left, right, leftSurround, rightSurround) | ||||
| Is equivalent to: k40Music (VST), AAX_eStemFormat_Quad (AAX), kAudioChannelLayoutTag_Quadraphonic (CoreAudio) | Is equivalent to: k40Music (VST), AAX_eStemFormat_Quad (AAX), kAudioChannelLayoutTag_Quadraphonic (CoreAudio) | ||||
| @@ -246,6 +239,18 @@ public: | |||||
| */ | */ | ||||
| static AudioChannelSet JUCE_CALLTYPE octagonal(); | static AudioChannelSet JUCE_CALLTYPE octagonal(); | ||||
| //============================================================================== | |||||
| /** Creates a set for ambisonic surround setups (ambisonicW, ambisonicX, ambisonicY, ambisonicZ). | |||||
| Is equivalent to: kAmbiXXXOrderACN (VST), AAX_eStemFormat_Ambi_XXX_ACN (AAX), kAudioChannelLayoutTag_HOA_ACN_SN3D (CoreAudio) | |||||
| */ | |||||
| static AudioChannelSet JUCE_CALLTYPE ambisonic (int order = 1); | |||||
| /** Returns the order of the ambisonic layout represented by this AudioChannelSet. If the | |||||
| AudioChannelSet is not an ambisonic layout, then this method will return -1. | |||||
| */ | |||||
| int getAmbisonicOrder() const; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Creates a set of untyped discrete channels. */ | /** Creates a set of untyped discrete channels. */ | ||||
| static AudioChannelSet JUCE_CALLTYPE discreteChannels (int numChannels); | static AudioChannelSet JUCE_CALLTYPE discreteChannels (int numChannels); | ||||
| @@ -269,10 +274,12 @@ public: | |||||
| { | { | ||||
| unknown = 0, | unknown = 0, | ||||
| //============================================================================== | |||||
| left = 1, // L | left = 1, // L | ||||
| right = 2, // R | right = 2, // R | ||||
| centre = 3, // C (sometimes M for mono) | centre = 3, // C (sometimes M for mono) | ||||
| //============================================================================== | |||||
| LFE = 4, | LFE = 4, | ||||
| leftSurround = 5, // Ls | leftSurround = 5, // Ls | ||||
| rightSurround = 6, // Rs | rightSurround = 6, // Rs | ||||
| @@ -295,17 +302,67 @@ public: | |||||
| wideLeft = 22, | wideLeft = 22, | ||||
| wideRight = 23, | wideRight = 23, | ||||
| ambisonicW = 24, | |||||
| ambisonicX = 25, | |||||
| ambisonicY = 26, | |||||
| ambisonicZ = 27, | |||||
| //============================================================================== | |||||
| // Used by Dolby Atmos 7.0.2 and 7.1.2 | // Used by Dolby Atmos 7.0.2 and 7.1.2 | ||||
| topSideLeft = 28, // Lts (AAX), Tsl (VST) | topSideLeft = 28, // Lts (AAX), Tsl (VST) | ||||
| topSideRight = 29, // Rts (AAX), Tsr (VST) | topSideRight = 29, // Rts (AAX), Tsr (VST) | ||||
| //============================================================================== | |||||
| // Ambisonic ACN formats - all channels are SN3D normalised | |||||
| // zero-th and first-order ambisonic ACN | |||||
| ambisonicACN0 = 24, | |||||
| ambisonicACN1 = 25, | |||||
| ambisonicACN2 = 26, | |||||
| ambisonicACN3 = 27, | |||||
| // second-order ambisonic | |||||
| ambisonicACN4 = 30, | |||||
| ambisonicACN5 = 31, | |||||
| ambisonicACN6 = 32, | |||||
| ambisonicACN7 = 33, | |||||
| ambisonicACN8 = 34, | |||||
| // third-order ambisonic | |||||
| ambisonicACN9 = 35, | |||||
| ambisonicACN10 = 36, | |||||
| ambisonicACN11 = 37, | |||||
| ambisonicACN12 = 38, | |||||
| ambisonicACN13 = 39, | |||||
| ambisonicACN14 = 40, | |||||
| ambisonicACN15 = 41, | |||||
| // fourth-order ambisonic | |||||
| ambisonicACN16 = 42, | |||||
| ambisonicACN17 = 43, | |||||
| ambisonicACN18 = 44, | |||||
| ambisonicACN19 = 45, | |||||
| ambisonicACN20 = 46, | |||||
| ambisonicACN21 = 47, | |||||
| ambisonicACN22 = 48, | |||||
| ambisonicACN23 = 49, | |||||
| ambisonicACN24 = 50, | |||||
| // fifth-order ambisonic | |||||
| ambisonicACN25 = 51, | |||||
| ambisonicACN26 = 52, | |||||
| ambisonicACN27 = 53, | |||||
| ambisonicACN28 = 54, | |||||
| ambisonicACN29 = 55, | |||||
| ambisonicACN30 = 56, | |||||
| ambisonicACN31 = 57, | |||||
| ambisonicACN32 = 58, | |||||
| ambisonicACN33 = 59, | |||||
| ambisonicACN34 = 60, | |||||
| ambisonicACN35 = 61, | |||||
| //============================================================================== | |||||
| ambisonicW = ambisonicACN0, | |||||
| ambisonicX = ambisonicACN3, | |||||
| ambisonicY = ambisonicACN1, | |||||
| ambisonicZ = ambisonicACN2, | |||||
| //============================================================================== | |||||
| discreteChannel0 = 64 /**< Non-typed individual channels are indexed upwards from this value. */ | discreteChannel0 = 64 /**< Non-typed individual channels are indexed upwards from this value. */ | ||||
| }; | }; | ||||
| @@ -321,7 +378,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| enum | enum | ||||
| { | { | ||||
| maxChannelsOfNamedLayout = 10 | |||||
| maxChannelsOfNamedLayout = 36 | |||||
| }; | }; | ||||
| /** Adds a channel to the set. */ | /** Adds a channel to the set. */ | ||||
| @@ -403,6 +460,9 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| explicit AudioChannelSet (uint32); | explicit AudioChannelSet (uint32); | ||||
| explicit AudioChannelSet (const Array<ChannelType>&); | explicit AudioChannelSet (const Array<ChannelType>&); | ||||
| //============================================================================== | |||||
| static int JUCE_CALLTYPE getAmbisonicOrderForNumChannels (int); | |||||
| }; | }; | ||||
| } // namespace juce | } // namespace juce | ||||
| @@ -52,6 +52,9 @@ struct CoreAudioLayouts | |||||
| */ | */ | ||||
| static AudioChannelLayoutTag toCoreAudio (const AudioChannelSet& set) | static AudioChannelLayoutTag toCoreAudio (const AudioChannelSet& set) | ||||
| { | { | ||||
| if (set.getAmbisonicOrder() >= 0) | |||||
| return kAudioChannelLayoutTag_HOA_ACN_SN3D | static_cast<unsigned> (set.size()); | |||||
| for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl) | for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl) | ||||
| { | { | ||||
| AudioChannelSet caSet; | AudioChannelSet caSet; | ||||
| @@ -125,6 +128,15 @@ struct CoreAudioLayouts | |||||
| } | } | ||||
| auto numChannels = tag & 0xffff; | auto numChannels = tag & 0xffff; | ||||
| if (tag >= kAudioChannelLayoutTag_HOA_ACN_SN3D && tag <= (kAudioChannelLayoutTag_HOA_ACN_SN3D | 0xffff)) | |||||
| { | |||||
| auto sqrtMinusOne = std::sqrt (static_cast<float> (numChannels)) - 1.0f; | |||||
| auto ambisonicOrder = jmax (0, static_cast<int> (std::floor (sqrtMinusOne))); | |||||
| if (static_cast<float> (ambisonicOrder) == sqrtMinusOne) | |||||
| return AudioChannelSet::ambisonic (ambisonicOrder).getChannelTypes(); | |||||
| } | |||||
| for (UInt32 i = 0; i < numChannels; ++i) | for (UInt32 i = 0; i < numChannels; ++i) | ||||
| speakers.add (static_cast<AudioChannelSet::ChannelType> (AudioChannelSet::discreteChannel0 + i)); | speakers.add (static_cast<AudioChannelSet::ChannelType> (AudioChannelSet::discreteChannel0 + i)); | ||||
| @@ -146,6 +158,9 @@ private: | |||||
| for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl) | for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl) | ||||
| tags.addIfNotAlreadyThere (tbl->tag); | tags.addIfNotAlreadyThere (tbl->tag); | ||||
| for (unsigned order = 0; order <= 5; ++order) | |||||
| tags.addIfNotAlreadyThere (kAudioChannelLayoutTag_HOA_ACN_SN3D | ((order + 1) * (order + 1))); | |||||
| return tags; | return tags; | ||||
| } | } | ||||
| @@ -605,6 +605,17 @@ class CoreAudioLayoutsUnitTest : public UnitTest | |||||
| public: | public: | ||||
| CoreAudioLayoutsUnitTest() : UnitTest ("Core Audio Layout <-> JUCE channel layout conversion", "Audio") {} | CoreAudioLayoutsUnitTest() : UnitTest ("Core Audio Layout <-> JUCE channel layout conversion", "Audio") {} | ||||
| // some ambisonic tags which are not explicitely defined | |||||
| enum | |||||
| { | |||||
| kAudioChannelLayoutTag_HOA_ACN_SN3D_0Order = kAudioChannelLayoutTag_HOA_ACN_SN3D | 1, | |||||
| kAudioChannelLayoutTag_HOA_ACN_SN3D_1Order = kAudioChannelLayoutTag_HOA_ACN_SN3D | 4, | |||||
| kAudioChannelLayoutTag_HOA_ACN_SN3D_2Order = kAudioChannelLayoutTag_HOA_ACN_SN3D | 9, | |||||
| kAudioChannelLayoutTag_HOA_ACN_SN3D_3Order = kAudioChannelLayoutTag_HOA_ACN_SN3D | 16, | |||||
| kAudioChannelLayoutTag_HOA_ACN_SN3D_4Order = kAudioChannelLayoutTag_HOA_ACN_SN3D | 25, | |||||
| kAudioChannelLayoutTag_HOA_ACN_SN3D_5Order = kAudioChannelLayoutTag_HOA_ACN_SN3D | 36 | |||||
| }; | |||||
| void runTest() override | void runTest() override | ||||
| { | { | ||||
| auto& knownTags = getAllKnownLayoutTags(); | auto& knownTags = getAllKnownLayoutTags(); | ||||
| @@ -703,7 +714,7 @@ private: | |||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MidSide), | DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MidSide), | ||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_XY), | DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_XY), | ||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_Binaural), | DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_Binaural), | ||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Ambisonic_B_Format, AudioChannelSet::ambisonic()), | |||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_Ambisonic_B_Format), | |||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Quadraphonic, AudioChannelSet::quadraphonic()), | DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Quadraphonic, AudioChannelSet::quadraphonic()), | ||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Pentagonal, AudioChannelSet::pentagonal()), | DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Pentagonal, AudioChannelSet::pentagonal()), | ||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Hexagonal, AudioChannelSet::hexagonal()), | DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_Hexagonal, AudioChannelSet::hexagonal()), | ||||
| @@ -818,7 +829,14 @@ private: | |||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_0_B), | DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_0_B), | ||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_1_A), | DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_1_A), | ||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_1_B), | DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_8_1_B), | ||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_1_D) | |||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_1_D), | |||||
| DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_DTS_6_1_D), | |||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_0Order, AudioChannelSet::ambisonic (0)), | |||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_1Order, AudioChannelSet::ambisonic (1)), | |||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_2Order, AudioChannelSet::ambisonic (2)), | |||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_3Order, AudioChannelSet::ambisonic (3)), | |||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_4Order, AudioChannelSet::ambisonic (4)), | |||||
| DEFINE_CHANNEL_LAYOUT_TAG_ENTRY (kAudioChannelLayoutTag_HOA_ACN_SN3D_5Order, AudioChannelSet::ambisonic (5)) | |||||
| }; | }; | ||||
| static Array<CoreAudioChannelLayoutTag> knownTags (tags, sizeof (tags) / sizeof (CoreAudioChannelLayoutTag)); | static Array<CoreAudioChannelLayoutTag> knownTags (tags, sizeof (tags) / sizeof (CoreAudioChannelLayoutTag)); | ||||
| @@ -144,6 +144,19 @@ namespace AAXClasses | |||||
| AudioChannelSet::ChannelType speakerOrder[10]; | AudioChannelSet::ChannelType speakerOrder[10]; | ||||
| }; | }; | ||||
| static AAX_EStemFormat stemFormatForAmbisonicOrder (int order) | |||||
| { | |||||
| switch (order) | |||||
| { | |||||
| case 1: return AAX_eStemFormat_Ambi_1_ACN; | |||||
| case 2: return AAX_eStemFormat_Ambi_2_ACN; | |||||
| case 3: return AAX_eStemFormat_Ambi_3_ACN; | |||||
| default: break; | |||||
| } | |||||
| return AAX_eStemFormat_INT32_MAX; | |||||
| } | |||||
| static AAXChannelStreamOrder aaxChannelOrder[] = | static AAXChannelStreamOrder aaxChannelOrder[] = | ||||
| { | { | ||||
| { 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_Mono, { AudioChannelSet::centre, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, | ||||
| @@ -180,7 +193,10 @@ namespace AAXClasses | |||||
| AAX_eStemFormat_7_0_DTS, | AAX_eStemFormat_7_0_DTS, | ||||
| AAX_eStemFormat_7_1_DTS, | AAX_eStemFormat_7_1_DTS, | ||||
| AAX_eStemFormat_7_0_2, | AAX_eStemFormat_7_0_2, | ||||
| AAX_eStemFormat_7_1_2 | |||||
| AAX_eStemFormat_7_1_2, | |||||
| AAX_eStemFormat_Ambi_1_ACN, | |||||
| AAX_eStemFormat_Ambi_2_ACN, | |||||
| AAX_eStemFormat_Ambi_3_ACN | |||||
| }; | }; | ||||
| static AAX_EStemFormat getFormatForAudioChannelSet (const AudioChannelSet& set, bool ignoreLayout) noexcept | static AAX_EStemFormat getFormatForAudioChannelSet (const AudioChannelSet& set, bool ignoreLayout) noexcept | ||||
| @@ -188,7 +204,9 @@ namespace AAXClasses | |||||
| // if the plug-in ignores layout, it is ok to convert between formats only by their numchannnels | // if the plug-in ignores layout, it is ok to convert between formats only by their numchannnels | ||||
| if (ignoreLayout) | if (ignoreLayout) | ||||
| { | { | ||||
| switch (set.size()) | |||||
| auto numChannels = set.size(); | |||||
| switch (numChannels) | |||||
| { | { | ||||
| case 0: return AAX_eStemFormat_None; | case 0: return AAX_eStemFormat_None; | ||||
| case 1: return AAX_eStemFormat_Mono; | case 1: return AAX_eStemFormat_Mono; | ||||
| @@ -201,8 +219,17 @@ namespace AAXClasses | |||||
| case 8: return AAX_eStemFormat_7_1_DTS; | case 8: return AAX_eStemFormat_7_1_DTS; | ||||
| case 9: return AAX_eStemFormat_7_0_2; | case 9: return AAX_eStemFormat_7_0_2; | ||||
| case 10: return AAX_eStemFormat_7_1_2; | case 10: return AAX_eStemFormat_7_1_2; | ||||
| default: return AAX_eStemFormat_INT32_MAX; | |||||
| default: break; | |||||
| } | } | ||||
| // check for ambisonics support | |||||
| auto sqrtMinusOne = std::sqrt (static_cast<float> (numChannels)) - 1.0f; | |||||
| auto ambisonicOrder = jmax (0, static_cast<int> (std::floor (sqrtMinusOne))); | |||||
| if (static_cast<float> (ambisonicOrder) == sqrtMinusOne) | |||||
| return stemFormatForAmbisonicOrder (ambisonicOrder); | |||||
| return AAX_eStemFormat_INT32_MAX; | |||||
| } | } | ||||
| if (set == AudioChannelSet::disabled()) return AAX_eStemFormat_None; | if (set == AudioChannelSet::disabled()) return AAX_eStemFormat_None; | ||||
| @@ -222,6 +249,10 @@ namespace AAXClasses | |||||
| if (set == AudioChannelSet::create7point0point2()) return AAX_eStemFormat_7_0_2; | if (set == AudioChannelSet::create7point0point2()) return AAX_eStemFormat_7_0_2; | ||||
| if (set == AudioChannelSet::create7point1point2()) return AAX_eStemFormat_7_1_2; | if (set == AudioChannelSet::create7point1point2()) return AAX_eStemFormat_7_1_2; | ||||
| auto order = set.getAmbisonicOrder(); | |||||
| if (order >= 0) | |||||
| return stemFormatForAmbisonicOrder (order); | |||||
| return AAX_eStemFormat_INT32_MAX; | return AAX_eStemFormat_INT32_MAX; | ||||
| } | } | ||||
| @@ -231,23 +262,26 @@ namespace AAXClasses | |||||
| { | { | ||||
| switch (format) | switch (format) | ||||
| { | { | ||||
| case AAX_eStemFormat_None: return AudioChannelSet::disabled(); | |||||
| case AAX_eStemFormat_Mono: return AudioChannelSet::mono(); | |||||
| case AAX_eStemFormat_Stereo: return AudioChannelSet::stereo(); | |||||
| case AAX_eStemFormat_LCR: return AudioChannelSet::createLCR(); | |||||
| case AAX_eStemFormat_LCRS: return AudioChannelSet::createLCRS(); | |||||
| case AAX_eStemFormat_Quad: return AudioChannelSet::quadraphonic(); | |||||
| case AAX_eStemFormat_5_0: return AudioChannelSet::create5point0(); | |||||
| case AAX_eStemFormat_5_1: return AudioChannelSet::create5point1(); | |||||
| case AAX_eStemFormat_6_0: return AudioChannelSet::create6point0(); | |||||
| case AAX_eStemFormat_6_1: return AudioChannelSet::create6point1(); | |||||
| case AAX_eStemFormat_7_0_SDDS: return AudioChannelSet::create7point0SDDS(); | |||||
| 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: return AudioChannelSet::disabled(); | |||||
| case AAX_eStemFormat_None: return AudioChannelSet::disabled(); | |||||
| case AAX_eStemFormat_Mono: return AudioChannelSet::mono(); | |||||
| case AAX_eStemFormat_Stereo: return AudioChannelSet::stereo(); | |||||
| case AAX_eStemFormat_LCR: return AudioChannelSet::createLCR(); | |||||
| case AAX_eStemFormat_LCRS: return AudioChannelSet::createLCRS(); | |||||
| case AAX_eStemFormat_Quad: return AudioChannelSet::quadraphonic(); | |||||
| case AAX_eStemFormat_5_0: return AudioChannelSet::create5point0(); | |||||
| case AAX_eStemFormat_5_1: return AudioChannelSet::create5point1(); | |||||
| case AAX_eStemFormat_6_0: return AudioChannelSet::create6point0(); | |||||
| case AAX_eStemFormat_6_1: return AudioChannelSet::create6point1(); | |||||
| case AAX_eStemFormat_7_0_SDDS: return AudioChannelSet::create7point0SDDS(); | |||||
| 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(); | |||||
| case AAX_eStemFormat_Ambi_1_ACN: return AudioChannelSet::ambisonic (1); | |||||
| case AAX_eStemFormat_Ambi_2_ACN: return AudioChannelSet::ambisonic (2); | |||||
| case AAX_eStemFormat_Ambi_3_ACN: return AudioChannelSet::ambisonic (3); | |||||
| default: return AudioChannelSet::disabled(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -283,9 +317,13 @@ namespace AAXClasses | |||||
| static int juceChannelIndexToAax (int juceIndex, const AudioChannelSet& channelSet) | static int juceChannelIndexToAax (int juceIndex, const AudioChannelSet& channelSet) | ||||
| { | { | ||||
| auto isAmbisonic = (channelSet.getAmbisonicOrder() >= 0); | |||||
| auto currentLayout = getFormatForAudioChannelSet (channelSet, false); | auto currentLayout = getFormatForAudioChannelSet (channelSet, false); | ||||
| int layoutIndex; | int layoutIndex; | ||||
| if (isAmbisonic && currentLayout != AAX_eStemFormat_INT32_MAX) | |||||
| return juceIndex; | |||||
| for (layoutIndex = 0; aaxChannelOrder[layoutIndex].aaxStemFormat != currentLayout; ++layoutIndex) | for (layoutIndex = 0; aaxChannelOrder[layoutIndex].aaxStemFormat != currentLayout; ++layoutIndex) | ||||
| if (aaxChannelOrder[layoutIndex].aaxStemFormat == 0) return juceIndex; | if (aaxChannelOrder[layoutIndex].aaxStemFormat == 0) return juceIndex; | ||||
| @@ -1915,6 +1953,12 @@ namespace AAXClasses | |||||
| { | { | ||||
| ScopedPointer<const AAX_IPropertyMap> props (featureInfo->AcquireProperties()); | ScopedPointer<const AAX_IPropertyMap> props (featureInfo->AcquireProperties()); | ||||
| // Due to a bug in ProTools 12.8, ProTools thinks that AAX_eStemFormat_Ambi_1_ACN is not supported | |||||
| // To workaround this bug, check if ProTools supports AAX_eStemFormat_Ambi_2_ACN, and, if yes, | |||||
| // we can safely assume that it will also support AAX_eStemFormat_Ambi_1_ACN | |||||
| if (stemFormat == AAX_eStemFormat_Ambi_1_ACN) | |||||
| stemFormat = AAX_eStemFormat_Ambi_2_ACN; | |||||
| if (props != nullptr && props->GetProperty ((AAX_EProperty) stemFormat, (AAX_CPropertyValue*) &supportLevel) != 0) | if (props != nullptr && props->GetProperty ((AAX_EProperty) stemFormat, (AAX_CPropertyValue*) &supportLevel) != 0) | ||||
| return (supportLevel == AAX_eSupportLevel_Supported); | return (supportLevel == AAX_eSupportLevel_Supported); | ||||
| } | } | ||||
| @@ -1168,8 +1168,6 @@ public: | |||||
| err = MusicDeviceBase::ChangeStreamFormat (scope, element, old, format); | err = MusicDeviceBase::ChangeStreamFormat (scope, element, old, format); | ||||
| DBG (set.getDescription()); | |||||
| if (err == noErr) | if (err == noErr) | ||||
| currentTag = CoreAudioLayouts::toCoreAudio (set); | currentTag = CoreAudioLayouts::toCoreAudio (set); | ||||
| @@ -133,6 +133,9 @@ static inline Steinberg::Vst::SpeakerArrangement getArrangementForNumChannels (i | |||||
| case 12: return k111; | case 12: return k111; | ||||
| case 13: return k130; | case 13: return k130; | ||||
| case 14: return k131; | case 14: return k131; | ||||
| #if VST_VERSION >= 0x030608 | |||||
| case 16: return kAmbi3rdOrderACN; | |||||
| #endif | |||||
| case 24: return (Steinberg::Vst::SpeakerArrangement) 1929904127; // k222 | case 24: return (Steinberg::Vst::SpeakerArrangement) 1929904127; // k222 | ||||
| default: break; | default: break; | ||||
| } | } | ||||
| @@ -160,9 +163,9 @@ static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set | |||||
| case AudioChannelSet::leftCentre: return kSpeakerLc; | case AudioChannelSet::leftCentre: return kSpeakerLc; | ||||
| case AudioChannelSet::rightCentre: return kSpeakerRc; | case AudioChannelSet::rightCentre: return kSpeakerRc; | ||||
| case AudioChannelSet::centreSurround: return kSpeakerCs; | case AudioChannelSet::centreSurround: return kSpeakerCs; | ||||
| case AudioChannelSet::leftSurroundSide: return (1 << 26); /* kSpeakerLcs */ | |||||
| case AudioChannelSet::rightSurroundSide: return (1 << 27); /* kSpeakerRcs */ | |||||
| case AudioChannelSet::topMiddle: return (1 << 11); /* kSpeakerTm */ | |||||
| case AudioChannelSet::leftSurroundSide: return (1ull << 26); /* kSpeakerLcs */ | |||||
| case AudioChannelSet::rightSurroundSide: return (1ull << 27); /* kSpeakerRcs */ | |||||
| case AudioChannelSet::topMiddle: return (1ull << 11); /* kSpeakerTm */ | |||||
| case AudioChannelSet::topFrontLeft: return kSpeakerTfl; | case AudioChannelSet::topFrontLeft: return kSpeakerTfl; | ||||
| case AudioChannelSet::topFrontCentre: return kSpeakerTfc; | case AudioChannelSet::topFrontCentre: return kSpeakerTfc; | ||||
| case AudioChannelSet::topFrontRight: return kSpeakerTfr; | case AudioChannelSet::topFrontRight: return kSpeakerTfr; | ||||
| @@ -174,12 +177,24 @@ static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set | |||||
| case AudioChannelSet::rightSurroundRear: return kSpeakerSr; | case AudioChannelSet::rightSurroundRear: return kSpeakerSr; | ||||
| case AudioChannelSet::wideLeft: return kSpeakerPl; | case AudioChannelSet::wideLeft: return kSpeakerPl; | ||||
| case AudioChannelSet::wideRight: return kSpeakerPr; | case AudioChannelSet::wideRight: return kSpeakerPr; | ||||
| case AudioChannelSet::ambisonicW: return (1 << 20); /* kSpeakerW */ | |||||
| 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::ambisonicACN0: return (1ull << 20); /* kSpeakerACN0 */ | |||||
| case AudioChannelSet::ambisonicACN1: return (1ull << 21); /* kSpeakerACN1 */ | |||||
| case AudioChannelSet::ambisonicACN2: return (1ull << 22); /* kSpeakerACN2 */ | |||||
| case AudioChannelSet::ambisonicACN3: return (1ull << 23); /* kSpeakerACN3 */ | |||||
| case AudioChannelSet::ambisonicACN4: return (1ull << 38); /* kSpeakerACN4 */ | |||||
| case AudioChannelSet::ambisonicACN5: return (1ull << 39); /* kSpeakerACN5 */ | |||||
| case AudioChannelSet::ambisonicACN6: return (1ull << 40); /* kSpeakerACN6 */ | |||||
| case AudioChannelSet::ambisonicACN7: return (1ull << 41); /* kSpeakerACN7 */ | |||||
| case AudioChannelSet::ambisonicACN8: return (1ull << 42); /* kSpeakerACN8 */ | |||||
| case AudioChannelSet::ambisonicACN9: return (1ull << 43); /* kSpeakerACN9 */ | |||||
| case AudioChannelSet::ambisonicACN10: return (1ull << 44); /* kSpeakerACN10 */ | |||||
| case AudioChannelSet::ambisonicACN11: return (1ull << 45); /* kSpeakerACN11 */ | |||||
| case AudioChannelSet::ambisonicACN12: return (1ull << 46); /* kSpeakerACN12 */ | |||||
| case AudioChannelSet::ambisonicACN13: return (1ull << 47); /* kSpeakerACN13 */ | |||||
| case AudioChannelSet::ambisonicACN14: return (1ull << 48); /* kSpeakerACN14 */ | |||||
| case AudioChannelSet::ambisonicACN15: return (1ull << 49); /* kSpeakerACN15 */ | |||||
| case AudioChannelSet::topSideLeft: return (1ull << 24); /* kSpeakerTsl */ | |||||
| case AudioChannelSet::topSideRight: return (1ull << 25); /* kSpeakerTsr */ | |||||
| case AudioChannelSet::discreteChannel0: return kSpeakerM; | case AudioChannelSet::discreteChannel0: return kSpeakerM; | ||||
| default: | default: | ||||
| @@ -189,9 +204,9 @@ static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set | |||||
| switch (static_cast<int> (type)) | switch (static_cast<int> (type)) | ||||
| { | { | ||||
| 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 */ | |||||
| case (int) AudioChannelSet::discreteChannel0 + 3: return (1ull << 28); /* kSpeakerBfl */ | |||||
| case (int) AudioChannelSet::discreteChannel0 + 4: return (1ull << 29); /* kSpeakerBfc */ | |||||
| case (int) AudioChannelSet::discreteChannel0 + 5: return (1ull << 30); /* kSpeakerBfr */ | |||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -217,7 +232,7 @@ static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::Speak | |||||
| case kSpeakerCs: return AudioChannelSet::centreSurround; | case kSpeakerCs: return AudioChannelSet::centreSurround; | ||||
| case kSpeakerSl: return AudioChannelSet::leftSurroundRear; | case kSpeakerSl: return AudioChannelSet::leftSurroundRear; | ||||
| case kSpeakerSr: return AudioChannelSet::rightSurroundRear; | case kSpeakerSr: return AudioChannelSet::rightSurroundRear; | ||||
| case (1 << 11): return AudioChannelSet::topMiddle; /* kSpeakerTm */ | |||||
| case (1ull << 11): return AudioChannelSet::topMiddle; /* kSpeakerTm */ | |||||
| case kSpeakerTfl: return AudioChannelSet::topFrontLeft; | case kSpeakerTfl: return AudioChannelSet::topFrontLeft; | ||||
| case kSpeakerTfc: return AudioChannelSet::topFrontCentre; | case kSpeakerTfc: return AudioChannelSet::topFrontCentre; | ||||
| case kSpeakerTfr: return AudioChannelSet::topFrontRight; | case kSpeakerTfr: return AudioChannelSet::topFrontRight; | ||||
| @@ -225,18 +240,30 @@ static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::Speak | |||||
| case kSpeakerTrc: return AudioChannelSet::topRearCentre; | case kSpeakerTrc: return AudioChannelSet::topRearCentre; | ||||
| case kSpeakerTrr: return AudioChannelSet::topRearRight; | case kSpeakerTrr: return AudioChannelSet::topRearRight; | ||||
| case kSpeakerLfe2: return AudioChannelSet::LFE2; | case kSpeakerLfe2: return AudioChannelSet::LFE2; | ||||
| case (1 << 19): return ((arr & kSpeakerC) != 0 ? AudioChannelSet::discreteChannel0 : AudioChannelSet::centre); | |||||
| case (1 << 20): return AudioChannelSet::ambisonicW; /* kSpeakerW */ | |||||
| 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 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 */ | |||||
| case (1 << 29): return static_cast<AudioChannelSet::ChannelType> ((int)AudioChannelSet::discreteChannel0 + 4); /* kSpeakerBfc */ | |||||
| case (1 << 30): return static_cast<AudioChannelSet::ChannelType> ((int)AudioChannelSet::discreteChannel0 + 5); /* kSpeakerBfr */ | |||||
| case (1ull << 19): return ((arr & kSpeakerC) != 0 ? AudioChannelSet::discreteChannel0 : AudioChannelSet::centre); | |||||
| case (1ull << 20): return AudioChannelSet::ambisonicACN0; /* kSpeakerACN0 */ | |||||
| case (1ull << 21): return AudioChannelSet::ambisonicACN1; /* kSpeakerACN1 */ | |||||
| case (1ull << 22): return AudioChannelSet::ambisonicACN2; /* kSpeakerACN2 */ | |||||
| case (1ull << 23): return AudioChannelSet::ambisonicACN3; /* kSpeakerACN3 */ | |||||
| case (1ull << 38): return AudioChannelSet::ambisonicACN4; /* kSpeakerACN4 */ | |||||
| case (1ull << 39): return AudioChannelSet::ambisonicACN5; /* kSpeakerACN5 */ | |||||
| case (1ull << 40): return AudioChannelSet::ambisonicACN6; /* kSpeakerACN6 */ | |||||
| case (1ull << 41): return AudioChannelSet::ambisonicACN7; /* kSpeakerACN7 */ | |||||
| case (1ull << 42): return AudioChannelSet::ambisonicACN8; /* kSpeakerACN8 */ | |||||
| case (1ull << 43): return AudioChannelSet::ambisonicACN9; /* kSpeakerACN9 */ | |||||
| case (1ull << 44): return AudioChannelSet::ambisonicACN10; /* kSpeakerACN10 */ | |||||
| case (1ull << 45): return AudioChannelSet::ambisonicACN11; /* kSpeakerACN11 */ | |||||
| case (1ull << 46): return AudioChannelSet::ambisonicACN12; /* kSpeakerACN12 */ | |||||
| case (1ull << 47): return AudioChannelSet::ambisonicACN13; /* kSpeakerACN13 */ | |||||
| case (1ull << 48): return AudioChannelSet::ambisonicACN14; /* kSpeakerACN14 */ | |||||
| 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 */ | |||||
| case (1ull << 28): return static_cast<AudioChannelSet::ChannelType> ((int)AudioChannelSet::discreteChannel0 + 3); /* kSpeakerBfl */ | |||||
| case (1ull << 29): return static_cast<AudioChannelSet::ChannelType> ((int)AudioChannelSet::discreteChannel0 + 4); /* kSpeakerBfc */ | |||||
| case (1ull << 30): return static_cast<AudioChannelSet::ChannelType> ((int)AudioChannelSet::discreteChannel0 + 5); /* kSpeakerBfr */ | |||||
| case kSpeakerPl: return AudioChannelSet::wideLeft; | case kSpeakerPl: return AudioChannelSet::wideLeft; | ||||
| case kSpeakerPr: return AudioChannelSet::wideRight; | case kSpeakerPr: return AudioChannelSet::wideRight; | ||||
| default: break; | default: break; | ||||
| @@ -274,6 +301,12 @@ static inline Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (cons | |||||
| else if (channels == AudioChannelSet::quadraphonic()) return k40Music; | else if (channels == AudioChannelSet::quadraphonic()) return k40Music; | ||||
| else if (channels == AudioChannelSet::create7point0point2()) return k71_2 & ~(Steinberg::Vst::kSpeakerLfe); | else if (channels == AudioChannelSet::create7point0point2()) return k71_2 & ~(Steinberg::Vst::kSpeakerLfe); | ||||
| else if (channels == AudioChannelSet::create7point1point2()) return k71_2; | else if (channels == AudioChannelSet::create7point1point2()) return k71_2; | ||||
| else if (channels == AudioChannelSet::ambisonic (0)) return (1ull << 20); | |||||
| else if (channels == AudioChannelSet::ambisonic (1)) return (1ull << 20) | (1ull << 21) | (1ull << 22) | (1ull << 23); | |||||
| #if VST_VERSION >= 0x030608 | |||||
| else if (channels == AudioChannelSet::ambisonic (2)) return kAmbi2cdOrderACN; | |||||
| else if (channels == AudioChannelSet::ambisonic (3)) return kAmbi3rdOrderACN; | |||||
| #endif | |||||
| Steinberg::Vst::SpeakerArrangement result = 0; | Steinberg::Vst::SpeakerArrangement result = 0; | ||||
| @@ -289,26 +322,32 @@ static inline AudioChannelSet getChannelSetForSpeakerArrangement (Steinberg::Vst | |||||
| { | { | ||||
| using namespace Steinberg::Vst::SpeakerArr; | 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 == kAmbi1stOrderACN) 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(); | |||||
| 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 == kAmbi1stOrderACN) 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(); | |||||
| else if (arr == (1 << 20)) return AudioChannelSet::ambisonic (0); | |||||
| else if (arr == ((1 << 20) | (1 << 21) | (1 << 22) | (1 << 23))) return AudioChannelSet::ambisonic (1); | |||||
| #if VST_VERSION >= 0x030608 | |||||
| else if (arr == kAmbi2cdOrderACN) return AudioChannelSet::ambisonic (2); | |||||
| else if (arr == kAmbi3rdOrderACN) return AudioChannelSet::ambisonic (3); | |||||
| #endif | |||||
| AudioChannelSet result; | AudioChannelSet result; | ||||
| @@ -1365,6 +1365,9 @@ int32 AudioProcessor::getAAXPluginIDForMainBusConfig (const AudioChannelSet& mai | |||||
| else if (set == AudioChannelSet::create7point1SDDS()) aaxFormatIndex = 13; | else if (set == AudioChannelSet::create7point1SDDS()) aaxFormatIndex = 13; | ||||
| else if (set == AudioChannelSet::create7point0point2()) aaxFormatIndex = 14; | else if (set == AudioChannelSet::create7point0point2()) aaxFormatIndex = 14; | ||||
| else if (set == AudioChannelSet::create7point1point2()) aaxFormatIndex = 15; | else if (set == AudioChannelSet::create7point1point2()) aaxFormatIndex = 15; | ||||
| else if (set == AudioChannelSet::ambisonic (1)) aaxFormatIndex = 16; | |||||
| else if (set == AudioChannelSet::ambisonic (2)) aaxFormatIndex = 17; | |||||
| else if (set == AudioChannelSet::ambisonic (3)) aaxFormatIndex = 18; | |||||
| else | else | ||||
| { | { | ||||
| // AAX does not support this format and the wrapper should not have | // AAX does not support this format and the wrapper should not have | ||||