Browse Source

Added support for enabling/disabling sidechains in AAX

tags/2021-05-28
hogliux 8 years ago
parent
commit
d13be21177
1 changed files with 126 additions and 50 deletions
  1. +126
    -50
      modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp

+ 126
- 50
modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp View File

@@ -537,13 +537,15 @@ namespace AAXClasses
//============================================================================== //==============================================================================
class JuceAAX_Processor : public AAX_CEffectParameters, class JuceAAX_Processor : public AAX_CEffectParameters,
public juce::AudioPlayHead, public juce::AudioPlayHead,
public AudioProcessorListener
public AudioProcessorListener,
private AsyncUpdater
{ {
public: public:
JuceAAX_Processor() JuceAAX_Processor()
: pluginInstance (createPluginFilterOfType (AudioProcessor::wrapperType_AAX)), : pluginInstance (createPluginFilterOfType (AudioProcessor::wrapperType_AAX)),
isPrepared (false), isPrepared (false),
sampleRate (0), lastBufferSize (1024), maxBufferSize (1024)
sampleRate (0), lastBufferSize (1024), maxBufferSize (1024),
hasSidechain (false), canDisableSidechain (false)
{ {
pluginInstance->setPlayHead (this); pluginInstance->setPlayHead (this);
pluginInstance->addListener (this); pluginInstance->addListener (this);
@@ -561,9 +563,13 @@ namespace AAXClasses
AAX_Result Uninitialize() override AAX_Result Uninitialize() override
{ {
cancelPendingUpdate();
if (isPrepared && pluginInstance != nullptr) if (isPrepared && pluginInstance != nullptr)
{ {
isPrepared = false; isPrepared = false;
processingSidechainChange.set (0);
pluginInstance->releaseResources(); pluginInstance->releaseResources();
} }
@@ -572,9 +578,13 @@ namespace AAXClasses
AAX_Result EffectInit() override AAX_Result EffectInit() override
{ {
cancelPendingUpdate();
AAX_Result err; AAX_Result err;
check (Controller()->GetSampleRate (&sampleRate)); check (Controller()->GetSampleRate (&sampleRate));
processingSidechainChange.set (0);
if ((err = preparePlugin()) != AAX_SUCCESS) if ((err = preparePlugin()) != AAX_SUCCESS)
return err; return err;
@@ -947,7 +957,24 @@ namespace AAXClasses
const int numOuts = pluginInstance->getTotalNumOutputChannels(); const int numOuts = pluginInstance->getTotalNumOutputChannels();
const int numMeters = aaxMeters.size(); const int numMeters = aaxMeters.size();
if (pluginInstance->isSuspended())
const bool processWantsSidechain = (sideChainBufferIdx != -1);
bool isSuspended = pluginInstance->isSuspended();
if (processingSidechainChange.get() == 0)
{
if (hasSidechain && canDisableSidechain
&& (sidechainDesired.get() != 0) != processWantsSidechain)
{
isSuspended = true;
sidechainDesired.set (processWantsSidechain ? 1 : 0);
processingSidechainChange.set (1);
triggerAsyncUpdate();
}
}
else
isSuspended = true;
if (isSuspended)
{ {
for (int i = 0; i < numOuts; ++i) for (int i = 0; i < numOuts; ++i)
FloatVectorOperations::clear (outputs[i], bufferSize); FloatVectorOperations::clear (outputs[i], bufferSize);
@@ -1007,38 +1034,39 @@ namespace AAXClasses
// In aax, the format of the aux and sidechain buses need to be fully determined // In aax, the format of the aux and sidechain buses need to be fully determined
// by the format on the main buses. This function tried to provide such a mapping. // by the format on the main buses. This function tried to provide such a mapping.
// Returns false if the in/out main layout is not supported // Returns false if the in/out main layout is not supported
static bool fullBusesLayoutFromMainLayout (AudioProcessor& p,
static bool fullBusesLayoutFromMainLayout (const AudioProcessor& p,
const AudioChannelSet& mainInput, const AudioChannelSet& mainOutput, const AudioChannelSet& mainInput, const AudioChannelSet& mainOutput,
AudioProcessor::BusesLayout& fullLayout) AudioProcessor::BusesLayout& fullLayout)
{ {
bool success = p.setBusesLayout (getDefaultLayout (p, true));
AudioProcessor::BusesLayout currentLayout = getDefaultLayout (p, true);
bool success = p.checkBusesLayoutSupported (currentLayout);
jassert (success); jassert (success);
ignoreUnused (success); ignoreUnused (success);
const int numInputBuses = p.getBusCount (true); const int numInputBuses = p.getBusCount (true);
const int numOutputBuses = p.getBusCount (false); const int numOutputBuses = p.getBusCount (false);
if (AudioProcessor::Bus* bus = p.getBus (true, 0))
if (! bus->setCurrentLayout (mainInput))
if (const AudioProcessor::Bus* bus = p.getBus (true, 0))
if (! bus->isLayoutSupported (mainInput, &currentLayout))
return false; return false;
if (AudioProcessor::Bus* bus = p.getBus (false, 0))
if (! bus->setCurrentLayout (mainOutput))
if (const AudioProcessor::Bus* bus = p.getBus (false, 0))
if (! bus->isLayoutSupported (mainOutput, &currentLayout))
return false; return false;
// did this change the input again // did this change the input again
if (numInputBuses > 0 && p.getChannelLayoutOfBus (true, 0) != mainInput)
if (numInputBuses > 0 && currentLayout.inputBuses.getReference (0) != mainInput)
return false; return false;
#ifdef JucePlugin_PreferredChannelConfigurations #ifdef JucePlugin_PreferredChannelConfigurations
short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
if (! AudioProcessor::containsLayout (p.getBusesLayout(), configs))
if (! AudioProcessor::containsLayout (currentLayout, configs))
return false; return false;
#endif #endif
bool foundValid = false; bool foundValid = false;
{ {
AudioProcessor::BusesLayout onlyMains = p.getBusesLayout();
AudioProcessor::BusesLayout onlyMains = currentLayout;
for (int i = 1; i < numInputBuses; ++i) for (int i = 1; i < numInputBuses; ++i)
onlyMains.inputBuses.getReference (i) = AudioChannelSet::disabled(); onlyMains.inputBuses.getReference (i) = AudioChannelSet::disabled();
@@ -1056,43 +1084,43 @@ namespace AAXClasses
if (numInputBuses > 1) if (numInputBuses > 1)
{ {
// can the first bus be a sidechain or disabled, if not then we can't use this layout combination // can the first bus be a sidechain or disabled, if not then we can't use this layout combination
if (AudioProcessor::Bus* bus = p.getBus (true, 1))
if (! bus->setCurrentLayout (AudioChannelSet::mono()) && ! bus->setCurrentLayout (AudioChannelSet::disabled()))
if (const AudioProcessor::Bus* bus = p.getBus (true, 1))
if (! bus->isLayoutSupported (AudioChannelSet::mono(), &currentLayout) && ! bus->isLayoutSupported (AudioChannelSet::disabled(), &currentLayout))
return foundValid; return foundValid;
// can all the other inputs be disabled, if not then we can't use this layout combination // can all the other inputs be disabled, if not then we can't use this layout combination
for (int i = 2; i < numInputBuses; ++i) for (int i = 2; i < numInputBuses; ++i)
if (AudioProcessor::Bus* bus = p.getBus (true, i))
if (! bus->setCurrentLayout (AudioChannelSet::disabled()))
if (const AudioProcessor::Bus* bus = p.getBus (true, i))
if (! bus->isLayoutSupported (AudioChannelSet::disabled(), &currentLayout))
return foundValid; return foundValid;
if (AudioProcessor::Bus* bus = p.getBus (true, 0))
if (! bus->setCurrentLayout (mainInput))
if (const AudioProcessor::Bus* bus = p.getBus (true, 0))
if (! bus->isLayoutSupported (mainInput, &currentLayout))
return foundValid; return foundValid;
if (AudioProcessor::Bus* bus = p.getBus (false, 0))
if (! bus->setCurrentLayout (mainOutput))
if (const AudioProcessor::Bus* bus = p.getBus (false, 0))
if (! bus->isLayoutSupported (mainOutput, &currentLayout))
return foundValid; return foundValid;
// recheck if the format is correct // recheck if the format is correct
if ((numInputBuses > 0 && p.getChannelLayoutOfBus (true, 0) != mainInput)
|| (numOutputBuses > 0 && p.getChannelLayoutOfBus (false, 0) != mainOutput))
if ((numInputBuses > 0 && currentLayout.inputBuses .getReference (0) != mainInput)
|| (numOutputBuses > 0 && currentLayout.outputBuses.getReference (0) != mainOutput))
return foundValid; return foundValid;
const AudioChannelSet& sidechainBus = p.getChannelLayoutOfBus (true, 1);
const AudioChannelSet& sidechainBus = currentLayout.inputBuses.getReference (1);
if (sidechainBus != AudioChannelSet::mono() && sidechainBus != AudioChannelSet::disabled()) if (sidechainBus != AudioChannelSet::mono() && sidechainBus != AudioChannelSet::disabled())
return foundValid; return foundValid;
for (int i = 2; i < numInputBuses; ++i) for (int i = 2; i < numInputBuses; ++i)
if (p.getChannelLayoutOfBus (true, i) != AudioChannelSet::disabled())
if (currentLayout.outputBuses.getReference (i) != AudioChannelSet::disabled())
return foundValid; return foundValid;
} }
const bool hasSidechain = (numInputBuses > 1 && p.getChannelLayoutOfBus (true, 1) == AudioChannelSet::mono());
const bool hasSidechain = (numInputBuses > 1 && currentLayout.inputBuses.getReference (1) == AudioChannelSet::mono());
if (hasSidechain) if (hasSidechain)
{ {
AudioProcessor::BusesLayout onlyMainsAndSidechain = p.getBusesLayout();
AudioProcessor::BusesLayout onlyMainsAndSidechain = currentLayout;
for (int i = 1; i < numOutputBuses; ++i) for (int i = 1; i < numOutputBuses; ++i)
onlyMainsAndSidechain.outputBuses.getReference (i) = AudioChannelSet::disabled(); onlyMainsAndSidechain.outputBuses.getReference (i) = AudioChannelSet::disabled();
@@ -1106,7 +1134,7 @@ namespace AAXClasses
if (numOutputBuses > 1) if (numOutputBuses > 1)
{ {
AudioProcessor::BusesLayout copy = p.getBusesLayout();
AudioProcessor::BusesLayout copy = currentLayout;
int maxAuxBuses = jmin (16, numOutputBuses); int maxAuxBuses = jmin (16, numOutputBuses);
for (int i = 1; i < maxAuxBuses; ++i) for (int i = 1; i < maxAuxBuses; ++i)
@@ -1123,38 +1151,38 @@ namespace AAXClasses
else else
{ {
for (int i = 1; i < maxAuxBuses; ++i) for (int i = 1; i < maxAuxBuses; ++i)
if (p.getChannelLayoutOfBus (false, i).isDisabled())
if (currentLayout.outputBuses.getReference (i).isDisabled())
return foundValid; return foundValid;
for (int i = maxAuxBuses; i < numOutputBuses; ++i) for (int i = maxAuxBuses; i < numOutputBuses; ++i)
if (AudioProcessor::Bus* bus = p.getBus (false, i))
if (! bus->setCurrentLayout (AudioChannelSet::disabled()))
if (const AudioProcessor::Bus* bus = p.getBus (false, i))
if (! bus->isLayoutSupported (AudioChannelSet::disabled(), &currentLayout))
return foundValid; return foundValid;
if (AudioProcessor::Bus* bus = p.getBus (true, 0))
if (! bus->setCurrentLayout (mainInput))
if (const AudioProcessor::Bus* bus = p.getBus (true, 0))
if (! bus->isLayoutSupported (mainInput, &currentLayout))
return foundValid; return foundValid;
if (AudioProcessor::Bus* bus = p.getBus (false, 0))
if (! bus->setCurrentLayout (mainOutput))
if (const AudioProcessor::Bus* bus = p.getBus (false, 0))
if (! bus->isLayoutSupported (mainOutput, &currentLayout))
return foundValid; return foundValid;
if ((numInputBuses > 0 && p.getChannelLayoutOfBus (true, 0) != mainInput)
|| (numOutputBuses > 0 && p.getChannelLayoutOfBus (false, 0) != mainOutput))
if ((numInputBuses > 0 && currentLayout.inputBuses .getReference (0) != mainInput)
|| (numOutputBuses > 0 && currentLayout.outputBuses.getReference (0) != mainOutput))
return foundValid; return foundValid;
if (numInputBuses > 1 )
if (numInputBuses > 1)
{ {
const AudioChannelSet& sidechainBus = p.getChannelLayoutOfBus (true, 1);
const AudioChannelSet& sidechainBus = currentLayout.inputBuses.getReference (1);
if (sidechainBus != AudioChannelSet::mono() && sidechainBus != AudioChannelSet::disabled()) if (sidechainBus != AudioChannelSet::mono() && sidechainBus != AudioChannelSet::disabled())
return foundValid; return foundValid;
} }
for (int i = maxAuxBuses; i < numOutputBuses; ++i) for (int i = maxAuxBuses; i < numOutputBuses; ++i)
if (! p.getChannelLayoutOfBus (false, i).isDisabled())
if (! currentLayout.outputBuses.getReference (i).isDisabled())
return foundValid; return foundValid;
fullLayout = p.getBusesLayout();
fullLayout = currentLayout;
foundValid = true; foundValid = true;
} }
} }
@@ -1383,6 +1411,23 @@ namespace AAXClasses
return AAX_ERROR_UNIMPLEMENTED; return AAX_ERROR_UNIMPLEMENTED;
} }
hasSidechain = (newLayout.getNumChannels (true, 1) == 1);
if (hasSidechain)
{
sidechainDesired.set (1);
AudioProcessor::BusesLayout disabledSidechainLayout (newLayout);
disabledSidechainLayout.inputBuses.getReference (1) = AudioChannelSet::disabled();
canDisableSidechain = audioProcessor.checkBusesLayoutSupported (disabledSidechainLayout);
if (canDisableSidechain)
{
sidechainDesired.set (0);
newLayout = disabledSidechainLayout;
}
}
const bool layoutChanged = (oldLayout != newLayout); const bool layoutChanged = (oldLayout != newLayout);
if (layoutChanged) if (layoutChanged)
@@ -1412,10 +1457,8 @@ namespace AAXClasses
audioProcessor.setRateAndBufferSizeDetails (sampleRate, lastBufferSize); audioProcessor.setRateAndBufferSizeDetails (sampleRate, lastBufferSize);
audioProcessor.prepareToPlay (sampleRate, lastBufferSize); audioProcessor.prepareToPlay (sampleRate, lastBufferSize);
maxBufferSize = lastBufferSize; maxBufferSize = lastBufferSize;
hasSidechain = audioProcessor.getChannelLayoutOfBus (true, 1) == AudioChannelSet::mono();
if (hasSidechain)
sideChainBuffer.calloc (static_cast<size_t> (maxBufferSize));
sideChainBuffer.calloc (static_cast<size_t> (maxBufferSize));
} }
check (Controller()->SetSignalLatency (audioProcessor.getLatencySamples())); check (Controller()->SetSignalLatency (audioProcessor.getLatencySamples()));
@@ -1477,6 +1520,33 @@ namespace AAXClasses
meterTapBuffers); meterTapBuffers);
} }
} }
//==============================================================================
void handleAsyncUpdate() override
{
if (processingSidechainChange.get() == 0)
return;
AudioProcessor& audioProcessor = getPluginInstance();
const bool sidechainActual = (audioProcessor.getChannelCountOfBus (true, 1) > 0);
if (hasSidechain && canDisableSidechain && (sidechainDesired.get() != 0) != sidechainActual)
{
if (isPrepared)
{
isPrepared = false;
audioProcessor.releaseResources();
}
if (AudioProcessor::Bus* bus = audioProcessor.getBus (true, 1))
bus->setCurrentLayout (sidechainDesired.get() != 0 ? AudioChannelSet::mono() : AudioChannelSet::disabled());
audioProcessor.prepareToPlay (audioProcessor.getSampleRate(), audioProcessor.getBlockSize());
isPrepared = true;
}
processingSidechainChange.set (0);
}
//============================================================================== //==============================================================================
inline int getParamIndexFromID (AAX_CParamID paramID) const noexcept inline int getParamIndexFromID (AAX_CParamID paramID) const noexcept
@@ -1492,7 +1562,7 @@ namespace AAXClasses
} }
//============================================================================== //==============================================================================
static AudioProcessor::BusesLayout getDefaultLayout (AudioProcessor& p, bool enableAll)
static AudioProcessor::BusesLayout getDefaultLayout (const AudioProcessor& p, bool enableAll)
{ {
AudioProcessor::BusesLayout defaultLayout; AudioProcessor::BusesLayout defaultLayout;
@@ -1503,7 +1573,7 @@ namespace AAXClasses
Array<AudioChannelSet>& layouts = (isInput ? defaultLayout.inputBuses : defaultLayout.outputBuses); Array<AudioChannelSet>& layouts = (isInput ? defaultLayout.inputBuses : defaultLayout.outputBuses);
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
if (AudioProcessor::Bus* bus = p.getBus (isInput, i))
if (const AudioProcessor::Bus* bus = p.getBus (isInput, i))
layouts.add (enableAll || bus->isEnabledByDefault() ? bus->getDefaultLayout() : AudioChannelSet()); layouts.add (enableAll || bus->isEnabledByDefault() ? bus->getDefaultLayout() : AudioChannelSet());
} }
@@ -1535,7 +1605,10 @@ namespace AAXClasses
int32_t juceChunkIndex; int32_t juceChunkIndex;
AAX_CSampleRate sampleRate; AAX_CSampleRate sampleRate;
int lastBufferSize, maxBufferSize; int lastBufferSize, maxBufferSize;
bool hasSidechain;
bool hasSidechain, canDisableSidechain;
Atomic<int> processingSidechainChange, sidechainDesired;
HeapBlock<float> sideChainBuffer; HeapBlock<float> sideChainBuffer;
Array<int> inputLayoutMap, outputLayoutMap; Array<int> inputLayoutMap, outputLayoutMap;
@@ -1694,12 +1767,15 @@ namespace AAXClasses
check (desc.AddPrivateData (JUCEAlgorithmIDs::pluginInstance, sizeof (PluginInstanceInfo))); check (desc.AddPrivateData (JUCEAlgorithmIDs::pluginInstance, sizeof (PluginInstanceInfo)));
check (desc.AddPrivateData (JUCEAlgorithmIDs::preparedFlag, sizeof (int32_t))); check (desc.AddPrivateData (JUCEAlgorithmIDs::preparedFlag, sizeof (int32_t)));
HeapBlock<AAX_CTypeID> meterIDs (static_cast<size_t> (numMeters));
if (numMeters > 0)
{
HeapBlock<AAX_CTypeID> meterIDs (static_cast<size_t> (numMeters));
for (int i = 0; i < numMeters; ++i)
meterIDs[i] = 'Metr' + static_cast<AAX_CTypeID> (i);
for (int i = 0; i < numMeters; ++i)
meterIDs[i] = 'Metr' + static_cast<AAX_CTypeID> (i);
check (desc.AddMeters (JUCEAlgorithmIDs::meterTapBuffers, meterIDs.getData(), static_cast<uint32_t> (numMeters)));
check (desc.AddMeters (JUCEAlgorithmIDs::meterTapBuffers, meterIDs.getData(), static_cast<uint32_t> (numMeters)));
}
// Create a property map // Create a property map
AAX_IPropertyMap* const properties = desc.NewPropertyMap(); AAX_IPropertyMap* const properties = desc.NewPropertyMap();


Loading…
Cancel
Save