Browse Source

Added higher-order ambisonics support to JUCE

tags/2021-05-28
hogliux 8 years ago
parent
commit
30269baed1
8 changed files with 425 additions and 93 deletions
  1. +164
    -9
      modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp
  2. +75
    -15
      modules/juce_audio_basics/buffers/juce_AudioChannelSet.h
  3. +15
    -0
      modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h
  4. +20
    -2
      modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp
  5. +64
    -20
      modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp
  6. +0
    -2
      modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  7. +84
    -45
      modules/juce_audio_processors/format_types/juce_VST3Common.h
  8. +3
    -0
      modules/juce_audio_processors/processors/juce_AudioProcessor.cpp

+ 164
- 9
modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp View File

@@ -23,7 +23,12 @@
namespace juce
{
AudioChannelSet::AudioChannelSet (uint32 c) : channels (c) {}
AudioChannelSet::AudioChannelSet (uint32 c) : channels (static_cast<int64> (c))
{
}
AudioChannelSet::AudioChannelSet (const Array<ChannelType>& c)
{
for (auto channel : c)
@@ -106,15 +111,18 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT
case LFE2: return "Lfe2";
case leftSurroundSide: return "Lss";
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 topSideRight: return "Tsr";
default: break;
}
if (type >= ambisonicACN4 && type <= ambisonicACN35)
return "ACN" + String (type - ambisonicACN4 + 4);
return {};
}
@@ -215,7 +223,26 @@ String AudioChannelSet::getDescription() const
if (*this == pentagonal()) return "Pentagonal";
if (*this == hexagonal()) return "Hexagonal";
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";
}
@@ -223,7 +250,7 @@ String AudioChannelSet::getDescription() const
bool AudioChannelSet::isDiscreteLayout() const noexcept
{
for (auto& speaker : getChannelTypes())
if (speaker <= topSideRight)
if (speaker <= ambisonicACN35)
return false;
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::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)); }
@@ -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::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)
{
@@ -368,7 +418,6 @@ Array<AudioChannelSet> AudioChannelSet::channelSetsWithNumberOfChannels (int num
{
retval.add (AudioChannelSet::quadraphonic());
retval.add (AudioChannelSet::createLCRS());
retval.add (AudioChannelSet::ambisonic());
}
else if (numChannels == 5)
{
@@ -395,6 +444,10 @@ Array<AudioChannelSet> AudioChannelSet::channelSetsWithNumberOfChannels (int num
retval.add (AudioChannelSet::create7point1SDDS());
retval.add (AudioChannelSet::octagonal());
}
auto order = getAmbisonicOrderForNumChannels (numChannels);
if (order >= 0)
retval.add (AudioChannelSet::ambisonic (order));
}
return retval;
@@ -428,4 +481,106 @@ int32 AudioChannelSet::getWaveChannelMask() const noexcept
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

+ 75
- 15
modules/juce_audio_basics/buffers/juce_AudioChannelSet.h View File

@@ -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)
Is equivalent to: k40Music (VST), AAX_eStemFormat_Quad (AAX), kAudioChannelLayoutTag_Quadraphonic (CoreAudio)
@@ -246,6 +239,18 @@ public:
*/
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. */
static AudioChannelSet JUCE_CALLTYPE discreteChannels (int numChannels);
@@ -269,10 +274,12 @@ public:
{
unknown = 0,
//==============================================================================
left = 1, // L
right = 2, // R
centre = 3, // C (sometimes M for mono)
//==============================================================================
LFE = 4,
leftSurround = 5, // Ls
rightSurround = 6, // Rs
@@ -295,17 +302,67 @@ public:
wideLeft = 22,
wideRight = 23,
ambisonicW = 24,
ambisonicX = 25,
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)
//==============================================================================
// 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. */
};
@@ -321,7 +378,7 @@ public:
//==============================================================================
enum
{
maxChannelsOfNamedLayout = 10
maxChannelsOfNamedLayout = 36
};
/** Adds a channel to the set. */
@@ -403,6 +460,9 @@ private:
//==============================================================================
explicit AudioChannelSet (uint32);
explicit AudioChannelSet (const Array<ChannelType>&);
//==============================================================================
static int JUCE_CALLTYPE getAmbisonicOrderForNumChannels (int);
};
} // namespace juce

+ 15
- 0
modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h View File

@@ -52,6 +52,9 @@ struct CoreAudioLayouts
*/
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)
{
AudioChannelSet caSet;
@@ -125,6 +128,15 @@ struct CoreAudioLayouts
}
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)
speakers.add (static_cast<AudioChannelSet::ChannelType> (AudioChannelSet::discreteChannel0 + i));
@@ -146,6 +158,9 @@ private:
for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl)
tags.addIfNotAlreadyThere (tbl->tag);
for (unsigned order = 0; order <= 5; ++order)
tags.addIfNotAlreadyThere (kAudioChannelLayoutTag_HOA_ACN_SN3D | ((order + 1) * (order + 1)));
return tags;
}


+ 20
- 2
modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp View File

@@ -605,6 +605,17 @@ class CoreAudioLayoutsUnitTest : public UnitTest
public:
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
{
auto& knownTags = getAllKnownLayoutTags();
@@ -703,7 +714,7 @@ private:
DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_MidSide),
DEFINE_CHANNEL_LAYOUT_DFL_ENTRY (kAudioChannelLayoutTag_XY),
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_Pentagonal, AudioChannelSet::pentagonal()),
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_1_A),
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));


+ 64
- 20
modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp View File

@@ -144,6 +144,19 @@ namespace AAXClasses
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[] =
{
{ 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_1_DTS,
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
@@ -188,7 +204,9 @@ namespace AAXClasses
// if the plug-in ignores layout, it is ok to convert between formats only by their numchannnels
if (ignoreLayout)
{
switch (set.size())
auto numChannels = set.size();
switch (numChannels)
{
case 0: return AAX_eStemFormat_None;
case 1: return AAX_eStemFormat_Mono;
@@ -201,8 +219,17 @@ namespace AAXClasses
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: 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;
@@ -222,6 +249,10 @@ namespace AAXClasses
if (set == AudioChannelSet::create7point0point2()) return AAX_eStemFormat_7_0_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;
}
@@ -231,23 +262,26 @@ namespace AAXClasses
{
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)
{
auto isAmbisonic = (channelSet.getAmbisonicOrder() >= 0);
auto currentLayout = getFormatForAudioChannelSet (channelSet, false);
int layoutIndex;
if (isAmbisonic && currentLayout != AAX_eStemFormat_INT32_MAX)
return juceIndex;
for (layoutIndex = 0; aaxChannelOrder[layoutIndex].aaxStemFormat != currentLayout; ++layoutIndex)
if (aaxChannelOrder[layoutIndex].aaxStemFormat == 0) return juceIndex;
@@ -1915,6 +1953,12 @@ namespace AAXClasses
{
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)
return (supportLevel == AAX_eSupportLevel_Supported);
}


+ 0
- 2
modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm View File

@@ -1168,8 +1168,6 @@ public:
err = MusicDeviceBase::ChangeStreamFormat (scope, element, old, format);
DBG (set.getDescription());
if (err == noErr)
currentTag = CoreAudioLayouts::toCoreAudio (set);


+ 84
- 45
modules/juce_audio_processors/format_types/juce_VST3Common.h View File

@@ -133,6 +133,9 @@ static inline Steinberg::Vst::SpeakerArrangement getArrangementForNumChannels (i
case 12: return k111;
case 13: return k130;
case 14: return k131;
#if VST_VERSION >= 0x030608
case 16: return kAmbi3rdOrderACN;
#endif
case 24: return (Steinberg::Vst::SpeakerArrangement) 1929904127; // k222
default: break;
}
@@ -160,9 +163,9 @@ static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set
case AudioChannelSet::leftCentre: return kSpeakerLc;
case AudioChannelSet::rightCentre: return kSpeakerRc;
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::topFrontCentre: return kSpeakerTfc;
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::wideLeft: return kSpeakerPl;
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;
default:
@@ -189,9 +204,9 @@ static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set
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:
break;
}
@@ -217,7 +232,7 @@ static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::Speak
case kSpeakerCs: return AudioChannelSet::centreSurround;
case kSpeakerSl: return AudioChannelSet::leftSurroundRear;
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 kSpeakerTfc: return AudioChannelSet::topFrontCentre;
case kSpeakerTfr: return AudioChannelSet::topFrontRight;
@@ -225,18 +240,30 @@ static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::Speak
case kSpeakerTrc: return AudioChannelSet::topRearCentre;
case kSpeakerTrr: return AudioChannelSet::topRearRight;
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 kSpeakerPr: return AudioChannelSet::wideRight;
default: break;
@@ -274,6 +301,12 @@ static inline Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (cons
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;
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;
@@ -289,26 +322,32 @@ static inline AudioChannelSet getChannelSetForSpeakerArrangement (Steinberg::Vst
{
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;


+ 3
- 0
modules/juce_audio_processors/processors/juce_AudioProcessor.cpp View File

@@ -1365,6 +1365,9 @@ int32 AudioProcessor::getAAXPluginIDForMainBusConfig (const AudioChannelSet& mai
else if (set == AudioChannelSet::create7point1SDDS()) aaxFormatIndex = 13;
else if (set == AudioChannelSet::create7point0point2()) aaxFormatIndex = 14;
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
{
// AAX does not support this format and the wrapper should not have


Loading…
Cancel
Save