diff --git a/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp b/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp index fa37ef4336..cdddcee011 100644 --- a/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp @@ -983,6 +983,10 @@ namespace template struct AudioBusPointerHelper {}; template <> struct AudioBusPointerHelper { static inline float** impl (Vst::AudioBusBuffers& data) noexcept { return data.channelBuffers32; } }; template <> struct AudioBusPointerHelper { static inline double** impl (Vst::AudioBusBuffers& data) noexcept { return data.channelBuffers64; } }; + + template struct ChooseBufferHelper {}; + template <> struct ChooseBufferHelper { static inline AudioBuffer& impl (AudioBuffer& f, AudioBuffer& ) noexcept { return f; } }; + template <> struct ChooseBufferHelper { static inline AudioBuffer& impl (AudioBuffer& , AudioBuffer& d) noexcept { return d; } }; } @@ -1142,6 +1146,9 @@ public: if (! state) { getPluginInstance().releaseResources(); + + deallocateChannelListAndBuffers (channelListFloat, emptyBufferFloat); + deallocateChannelListAndBuffers (channelListDouble, emptyBufferDouble); } else { @@ -1156,8 +1163,8 @@ public: ? (int) processSetup.maxSamplesPerBlock : bufferSize; - allocateChannelLists (channelListFloat); - allocateChannelLists (channelListDouble); + allocateChannelListAndBuffers (channelListFloat, emptyBufferFloat); + allocateChannelListAndBuffers (channelListDouble, emptyBufferDouble); preparePlugin (sampleRate, bufferSize); } @@ -1947,6 +1954,9 @@ private: Array channelListFloat; Array channelListDouble; + AudioBuffer emptyBufferFloat; + AudioBuffer emptyBufferDouble; + bool isMidiInputBusEnabled, isMidiOutputBusEnabled; ScopedJuceInitialiser_GUI libraryInitialiser; @@ -1965,52 +1975,110 @@ private: void processAudio (Vst::ProcessData& data, Array& channelList) { int totalInputChans = 0; + bool tmpBufferNeedsClearing = false; const int plugInInputChannels = pluginInstance->getTotalNumInputChannels(); const int plugInOutputChannels = pluginInstance->getTotalNumOutputChannels(); - if (data.inputs != nullptr) + // Wavelab workaround: wave-lab lies on the number of inputs/outputs so re-count here + int vstInputs; + for (vstInputs = 0; vstInputs < data.numInputs; ++vstInputs) + if (getPointerForAudioBus (data.inputs[vstInputs]) == nullptr) + break; + + int vstOutputs; + for (vstOutputs = 0; vstOutputs < data.numOutputs; ++vstOutputs) + if (getPointerForAudioBus (data.outputs[vstOutputs]) == nullptr) + break; + { - for (int bus = 0; bus < data.numInputs && totalInputChans < plugInInputChannels; ++bus) + const int n = jmax (vstInputs, getNumAudioBuses (true)); + + for (int bus = 0; bus < n && totalInputChans < plugInInputChannels; ++bus) { - if (FloatType** const busChannels = getPointerForAudioBus (data.inputs[bus])) + if (bus < vstInputs) { - const int numChans = jmin ((int) data.inputs[bus].numChannels, plugInInputChannels - totalInputChans); + if (FloatType** const busChannels = getPointerForAudioBus (data.inputs[bus])) + { + const int numChans = jmin ((int) data.inputs[bus].numChannels, plugInInputChannels - totalInputChans); + + for (int i = 0; i < numChans; ++i) + if (busChannels[i] != nullptr) + channelList.set (totalInputChans++, busChannels[i]); + } + } + else + { + const int numChans = jmin (pluginInstance->getChannelCountOfBus (true, bus), plugInInputChannels - totalInputChans); for (int i = 0; i < numChans; ++i) - if (busChannels[i] != nullptr) - channelList.set (totalInputChans++, busChannels[i]); + { + if (FloatType* tmpBuffer = getTmpBufferForChannel (totalInputChans, data.numSamples)) + { + tmpBufferNeedsClearing = true; + channelList.set (totalInputChans++, tmpBuffer); + } + else + return; + } } } } int totalOutputChans = 0; - if (data.outputs != nullptr) { - for (int bus = 0; bus < data.numOutputs && totalOutputChans < plugInOutputChannels; ++bus) + const int n = jmax (vstOutputs, getNumAudioBuses (false)); + + for (int bus = 0; bus < n && totalOutputChans < plugInOutputChannels; ++bus) { - if (FloatType** const busChannels = getPointerForAudioBus (data.outputs[bus])) + if (bus < vstOutputs) { - const int numChans = jmin ((int) data.outputs[bus].numChannels, plugInOutputChannels - totalOutputChans); + if (FloatType** const busChannels = getPointerForAudioBus (data.outputs[bus])) + { + const int numChans = jmin ((int) data.outputs[bus].numChannels, plugInOutputChannels - totalOutputChans); + + for (int i = 0; i < numChans; ++i) + { + if (busChannels[i] != nullptr) + { + if (totalOutputChans >= totalInputChans) + { + FloatVectorOperations::clear (busChannels[i], data.numSamples); + channelList.set (totalOutputChans, busChannels[i]); + } + + ++totalOutputChans; + } + } + } + } + else + { + const int numChans = jmin (pluginInstance->getChannelCountOfBus (false, bus), plugInOutputChannels - totalOutputChans); for (int i = 0; i < numChans; ++i) { - if (busChannels[i] != nullptr) + if (FloatType* tmpBuffer = getTmpBufferForChannel (totalOutputChans, data.numSamples)) { if (totalOutputChans >= totalInputChans) { - FloatVectorOperations::clear (busChannels[i], data.numSamples); - channelList.set (totalOutputChans, busChannels[i]); + tmpBufferNeedsClearing = true; + channelList.set (totalOutputChans, tmpBuffer); } ++totalOutputChans; } + else + return; } } } } + if (tmpBufferNeedsClearing) + ChooseBufferHelper::impl (emptyBufferFloat, emptyBufferDouble).clear(); + AudioBuffer buffer; if (int totalChans = jmax (totalOutputChans, totalInputChans)) @@ -2089,10 +2157,22 @@ private: //============================================================================== template - void allocateChannelLists (Array& channelList) + void allocateChannelListAndBuffers (Array& channelList, AudioBuffer& buffer) { channelList.clearQuick(); channelList.insertMultiple (0, nullptr, 128); + + const AudioProcessor& p = getPluginInstance(); + buffer.setSize (jmax (p.getTotalNumInputChannels(), p.getTotalNumOutputChannels()), p.getBlockSize() * 4); + buffer.clear(); + } + + template + void deallocateChannelListAndBuffers (Array& channelList, AudioBuffer& buffer) + { + channelList.clearQuick(); + channelList.resize (0); + buffer.setSize (0, 0); } template @@ -2101,6 +2181,19 @@ private: return AudioBusPointerHelper::impl (data); } + template + FloatType* getTmpBufferForChannel (int channel, int numSamples) noexcept + { + AudioBuffer& buffer = ChooseBufferHelper::impl (emptyBufferFloat, emptyBufferDouble); + + // we can't do anything if the host requests to render many more samples than the + // block size, we need to bail out + if (numSamples > buffer.getNumSamples() || channel >= buffer.getNumChannels()) + return nullptr; + + return buffer.getWritePointer (channel); + } + void preparePlugin (double sampleRate, int bufferSize) { AudioProcessor& p = getPluginInstance();