mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Some VST3 hosting fixes for speaker arrangements and tail length.
This commit is contained in:
parent
de6c80bb98
commit
acebbfd576
2 changed files with 114 additions and 50 deletions
|
|
@ -85,6 +85,18 @@ static Steinberg::Vst::TChar* toString (const juce::String& source) noexcept
|
|||
|
||||
|
||||
//==============================================================================
|
||||
static Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg::Vst::IAudioProcessor* processor,
|
||||
bool isInput, int busIndex)
|
||||
{
|
||||
Steinberg::Vst::SpeakerArrangement arrangement = Steinberg::Vst::SpeakerArr::kEmpty;
|
||||
|
||||
if (processor != nullptr)
|
||||
processor->getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
|
||||
(Steinberg::int32) busIndex, arrangement);
|
||||
|
||||
return arrangement;
|
||||
}
|
||||
|
||||
/** For the sake of simplicity, there can only be 1 arrangement type per channel count.
|
||||
i.e.: 4 channels == k31Cine OR k40Cine
|
||||
*/
|
||||
|
|
@ -341,7 +353,7 @@ namespace VST3BufferExchange
|
|||
Bus& bus,
|
||||
AudioSampleBuffer& buffer,
|
||||
int numChannels, int channelStartOffset,
|
||||
int sampleOffset = 0) noexcept
|
||||
int sampleOffset = 0)
|
||||
{
|
||||
const int channelEnd = numChannels + channelStartOffset;
|
||||
jassert (channelEnd >= 0 && channelEnd <= buffer.getNumChannels());
|
||||
|
|
@ -356,37 +368,52 @@ namespace VST3BufferExchange
|
|||
vstBuffers.silenceFlags = 0;
|
||||
}
|
||||
|
||||
static void mapArrangementToBusses (int& channelIndexOffset, int index,
|
||||
Array<Steinberg::Vst::AudioBusBuffers>& result,
|
||||
BusMap& busMapToUse, Steinberg::Vst::SpeakerArrangement arrangement,
|
||||
AudioSampleBuffer& source)
|
||||
{
|
||||
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
|
||||
|
||||
if (index >= result.size())
|
||||
result.add (Steinberg::Vst::AudioBusBuffers());
|
||||
|
||||
if (index >= busMapToUse.size())
|
||||
busMapToUse.add (Bus());
|
||||
|
||||
if (numChansForBus > 0)
|
||||
{
|
||||
associateBufferTo (result.getReference (index),
|
||||
busMapToUse.getReference (index),
|
||||
source, numChansForBus, channelIndexOffset);
|
||||
}
|
||||
|
||||
channelIndexOffset += numChansForBus;
|
||||
}
|
||||
|
||||
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result, BusMap& busMapToUse,
|
||||
const Array<Steinberg::Vst::SpeakerArrangement>& arrangements,
|
||||
AudioSampleBuffer& source)
|
||||
{
|
||||
int channelIndexOffset = 0;
|
||||
|
||||
for (int i = 0; i < arrangements.size(); ++i)
|
||||
mapArrangementToBusses (channelIndexOffset, i, result, busMapToUse,
|
||||
arrangements.getUnchecked (i), source);
|
||||
}
|
||||
|
||||
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result,
|
||||
Steinberg::Vst::IAudioProcessor& processor,
|
||||
BusMap& busMapToUse,
|
||||
bool isInput, int numBusses,
|
||||
BusMap& busMapToUse, bool isInput, int numBusses,
|
||||
AudioSampleBuffer& source)
|
||||
{
|
||||
int channelIndexOffset = 0;
|
||||
|
||||
for (int i = 0; i < numBusses; ++i)
|
||||
{
|
||||
Steinberg::Vst::SpeakerArrangement arrangement = 0;
|
||||
processor.getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
|
||||
(Steinberg::int32) i, arrangement);
|
||||
|
||||
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
|
||||
|
||||
if (i >= result.size())
|
||||
result.add (Steinberg::Vst::AudioBusBuffers());
|
||||
|
||||
if (i >= busMapToUse.size())
|
||||
busMapToUse.add (Bus());
|
||||
|
||||
if (numChansForBus > 0)
|
||||
{
|
||||
associateBufferTo (result.getReference (i),
|
||||
busMapToUse.getReference (i),
|
||||
source, numChansForBus, channelIndexOffset);
|
||||
}
|
||||
|
||||
channelIndexOffset += numChansForBus;
|
||||
}
|
||||
mapArrangementToBusses (channelIndexOffset, i,
|
||||
result, busMapToUse,
|
||||
getArrangementForBus (&processor, isInput, i),
|
||||
source);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1632,7 +1632,8 @@ public:
|
|||
midiInputs (new MidiEventList()),
|
||||
midiOutputs (new MidiEventList()),
|
||||
isComponentInitialised (false),
|
||||
isControllerInitialised (false)
|
||||
isControllerInitialised (false),
|
||||
isActive (false)
|
||||
{
|
||||
host = new VST3HostContext (this);
|
||||
}
|
||||
|
|
@ -1719,8 +1720,27 @@ public:
|
|||
return module != nullptr ? module->name : String::empty;
|
||||
}
|
||||
|
||||
void repopulateArrangements()
|
||||
{
|
||||
inputArrangements.clearQuick();
|
||||
outputArrangements.clearQuick();
|
||||
|
||||
// NB: Some plugins need a valid arrangement despite specifying 0 for their I/O busses
|
||||
for (int i = 0; i < jmax (1, numInputAudioBusses); ++i)
|
||||
inputArrangements.add (getArrangementForBus (processor, true, i));
|
||||
|
||||
for (int i = 0; i < jmax (1, numOutputAudioBusses); ++i)
|
||||
outputArrangements.add (getArrangementForBus (processor, false, i));
|
||||
}
|
||||
|
||||
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override
|
||||
{
|
||||
// Avoid redundantly calling things like setActive, which can be a heavy-duty call for some plugins:
|
||||
if (isActive
|
||||
&& getSampleRate() == sampleRate
|
||||
&& getBlockSize() == estimatedSamplesPerBlock)
|
||||
return;
|
||||
|
||||
using namespace Vst;
|
||||
|
||||
ProcessSetup setup;
|
||||
|
|
@ -1736,21 +1756,25 @@ public:
|
|||
|
||||
editController->setComponentHandler (host);
|
||||
|
||||
Array<SpeakerArrangement> inArrangements, outArrangements;
|
||||
if (inputArrangements.size() <= 0 || outputArrangements.size() <= 0)
|
||||
repopulateArrangements();
|
||||
|
||||
// NB: Some plugins need a valid arrangement despite specifying 0 for their I/O busses
|
||||
for (int i = 0; i < jmax (1, numInputAudioBusses); ++i)
|
||||
inArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (true, true, i).channelCount)));
|
||||
|
||||
for (int i = 0; i < jmax (1, numOutputAudioBusses); ++i)
|
||||
outArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (false, true, i).channelCount)));
|
||||
|
||||
warnOnFailure (processor->setBusArrangements (inArrangements.getRawDataPointer(), numInputAudioBusses,
|
||||
outArrangements.getRawDataPointer(), numOutputAudioBusses));
|
||||
warnOnFailure (processor->setBusArrangements (inputArrangements.getRawDataPointer(), numInputAudioBusses,
|
||||
outputArrangements.getRawDataPointer(), numOutputAudioBusses));
|
||||
|
||||
// Update the num. busses in case the configuration has been modified by the plugin. (May affect number of channels!):
|
||||
numInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true);
|
||||
numOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true);
|
||||
const int newNumInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true);
|
||||
const int newNumOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true);
|
||||
|
||||
// Repopulate arrangements if the number of busses have changed:
|
||||
if (numInputAudioBusses != newNumInputAudioBusses
|
||||
|| numOutputAudioBusses != newNumOutputAudioBusses)
|
||||
{
|
||||
numInputAudioBusses = newNumInputAudioBusses;
|
||||
numOutputAudioBusses = newNumOutputAudioBusses;
|
||||
|
||||
repopulateArrangements();
|
||||
}
|
||||
|
||||
// Needed for having the same sample rate in processBlock(); some plugins need this!
|
||||
setPlayConfigDetails (getNumSingleDirectionChannelsFor (component, true, true),
|
||||
|
|
@ -1763,19 +1787,26 @@ public:
|
|||
|
||||
warnOnFailure (component->setActive (true));
|
||||
warnOnFailure (processor->setProcessing (true));
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
void releaseResources() override
|
||||
{
|
||||
if (! isActive)
|
||||
return; // Avoids redundantly calling things like setActive
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
isActive = false;
|
||||
|
||||
setStateForAllBusses (false);
|
||||
|
||||
if (processor != nullptr)
|
||||
processor->setProcessing (false);
|
||||
warnOnFailure (processor->setProcessing (false));
|
||||
|
||||
if (component != nullptr)
|
||||
component->setActive (false);
|
||||
warnOnFailure (component->setActive (false));
|
||||
}
|
||||
JUCE_CATCH_ALL_ASSERT
|
||||
}
|
||||
|
|
@ -1784,7 +1815,8 @@ public:
|
|||
{
|
||||
using namespace Vst;
|
||||
|
||||
if (processor != nullptr
|
||||
if (isActive
|
||||
&& processor != nullptr
|
||||
&& processor->canProcessSampleSize (kSample32) == kResultTrue)
|
||||
{
|
||||
const int numSamples = buffer.getNumSamples();
|
||||
|
|
@ -1856,15 +1888,22 @@ public:
|
|||
//==============================================================================
|
||||
bool silenceInProducesSilenceOut() const override
|
||||
{
|
||||
return processor == nullptr;
|
||||
if (processor != nullptr)
|
||||
return processor->getTailSamples() == Vst::kNoTail;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** May return a negative value as a means of informing us that the plugin has "infinite tail," or 0 for "no tail." */
|
||||
double getTailLengthSeconds() const override
|
||||
{
|
||||
if (processor != nullptr)
|
||||
return (double) jmin ((int) jmax ((Steinberg::uint32) 0, processor->getTailSamples()), 0x7fffffff)
|
||||
* getSampleRate();
|
||||
{
|
||||
const double sampleRate = getSampleRate();
|
||||
|
||||
if (sampleRate > 0.0)
|
||||
return jlimit (0, 0x7fffffff, (int) processor->getTailSamples()) / sampleRate;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
|
@ -2039,6 +2078,7 @@ private:
|
|||
as very poorly specified by the Steinberg SDK
|
||||
*/
|
||||
int numInputAudioBusses, numOutputAudioBusses;
|
||||
Array<Vst::SpeakerArrangement> inputArrangements, outputArrangements; // Caching to improve performance and to avoid possible non-thread-safe calls to getBusArrangements().
|
||||
VST3BufferExchange::BusMap inputBusMap, outputBusMap;
|
||||
Array<Vst::AudioBusBuffers> inputBusses, outputBusses;
|
||||
|
||||
|
|
@ -2105,7 +2145,7 @@ private:
|
|||
ComSmartPtr<ParameterChangeList> inputParameterChanges, outputParameterChanges;
|
||||
ComSmartPtr<MidiEventList> midiInputs, midiOutputs;
|
||||
Vst::ProcessContext timingInfo; //< Only use this in processBlock()!
|
||||
bool isComponentInitialised, isControllerInitialised;
|
||||
bool isComponentInitialised, isControllerInitialised, isActive;
|
||||
|
||||
//==============================================================================
|
||||
bool fetchComponentAndController (IPluginFactory* factory, const Steinberg::int32 numClasses)
|
||||
|
|
@ -2310,11 +2350,8 @@ private:
|
|||
{
|
||||
using namespace VST3BufferExchange;
|
||||
|
||||
mapBufferToBusses (inputBusses, *processor, inputBusMap,
|
||||
true, numInputAudioBusses, buffer);
|
||||
|
||||
mapBufferToBusses (outputBusses, *processor, outputBusMap,
|
||||
false, numOutputAudioBusses, buffer);
|
||||
mapBufferToBusses (inputBusses, inputBusMap, inputArrangements, buffer);
|
||||
mapBufferToBusses (outputBusses, outputBusMap, outputArrangements, buffer);
|
||||
|
||||
destination.inputs = inputBusses.getRawDataPointer();
|
||||
destination.outputs = outputBusses.getRawDataPointer();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue