|
|
@@ -2186,18 +2186,6 @@ private: |
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3EditController)
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3EditController)
|
|
|
};
|
|
|
};
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
|
{
|
|
|
|
|
|
template <typename FloatType> struct AudioBusPointerHelper {};
|
|
|
|
|
|
template <> struct AudioBusPointerHelper<float> { static float** impl (Vst::AudioBusBuffers& data) noexcept { return data.channelBuffers32; } };
|
|
|
|
|
|
template <> struct AudioBusPointerHelper<double> { static double** impl (Vst::AudioBusBuffers& data) noexcept { return data.channelBuffers64; } };
|
|
|
|
|
|
|
|
|
|
|
|
template <typename FloatType> struct ChooseBufferHelper {};
|
|
|
|
|
|
template <> struct ChooseBufferHelper<float> { static AudioBuffer<float>& impl (AudioBuffer<float>& f, AudioBuffer<double>& ) noexcept { return f; } };
|
|
|
|
|
|
template <> struct ChooseBufferHelper<double> { static AudioBuffer<double>& impl (AudioBuffer<float>& , AudioBuffer<double>& d) noexcept { return d; } };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
//==============================================================================
|
|
|
class JuceVST3Component : public Vst::IComponent,
|
|
|
class JuceVST3Component : public Vst::IComponent,
|
|
|
public Vst::IAudioProcessor,
|
|
|
public Vst::IAudioProcessor,
|
|
|
@@ -2343,9 +2331,6 @@ public: |
|
|
if (! state)
|
|
|
if (! state)
|
|
|
{
|
|
|
{
|
|
|
getPluginInstance().releaseResources();
|
|
|
getPluginInstance().releaseResources();
|
|
|
|
|
|
|
|
|
deallocateChannelListAndBuffers (channelListFloat, emptyBufferFloat);
|
|
|
|
|
|
deallocateChannelListAndBuffers (channelListDouble, emptyBufferDouble);
|
|
|
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
else
|
|
|
{
|
|
|
{
|
|
|
@@ -2360,9 +2345,6 @@ public: |
|
|
? (int) processSetup.maxSamplesPerBlock
|
|
|
? (int) processSetup.maxSamplesPerBlock
|
|
|
: bufferSize;
|
|
|
: bufferSize;
|
|
|
|
|
|
|
|
|
allocateChannelListAndBuffers (channelListFloat, emptyBufferFloat);
|
|
|
|
|
|
allocateChannelListAndBuffers (channelListDouble, emptyBufferDouble);
|
|
|
|
|
|
|
|
|
|
|
|
preparePlugin (sampleRate, bufferSize);
|
|
|
preparePlugin (sampleRate, bufferSize);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2823,6 +2805,7 @@ public: |
|
|
info.mediaType = Vst::kAudio;
|
|
|
info.mediaType = Vst::kAudio;
|
|
|
info.direction = dir;
|
|
|
info.direction = dir;
|
|
|
info.channelCount = bus->getLastEnabledLayout().size();
|
|
|
info.channelCount = bus->getLastEnabledLayout().size();
|
|
|
|
|
|
jassert (info.channelCount == Steinberg::Vst::SpeakerArr::getChannelCount (getVst3SpeakerArrangement (bus->getLastEnabledLayout())));
|
|
|
toString128 (info.name, bus->getName());
|
|
|
toString128 (info.name, bus->getName());
|
|
|
|
|
|
|
|
|
info.busType = [&]
|
|
|
info.busType = [&]
|
|
|
@@ -2904,7 +2887,10 @@ public: |
|
|
return kResultFalse;
|
|
|
return kResultFalse;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
tresult PLUGIN_API activateBus (Vst::MediaType type, Vst::BusDirection dir, Steinberg::int32 index, TBool state) override
|
|
|
|
|
|
|
|
|
tresult PLUGIN_API activateBus (Vst::MediaType type,
|
|
|
|
|
|
Vst::BusDirection dir,
|
|
|
|
|
|
Steinberg::int32 index,
|
|
|
|
|
|
TBool state) override
|
|
|
{
|
|
|
{
|
|
|
// The host is misbehaving! The plugin must be deactivated before setting new arrangements.
|
|
|
// The host is misbehaving! The plugin must be deactivated before setting new arrangements.
|
|
|
jassert (! active);
|
|
|
jassert (! active);
|
|
|
@@ -2935,6 +2921,13 @@ public: |
|
|
if (index < 0 || index >= getNumAudioBuses (dir == Vst::kInput))
|
|
|
if (index < 0 || index >= getNumAudioBuses (dir == Vst::kInput))
|
|
|
return kResultFalse;
|
|
|
return kResultFalse;
|
|
|
|
|
|
|
|
|
|
|
|
// Some hosts (old cakewalk, bitwig studio) might call this function without
|
|
|
|
|
|
// deactivating the plugin, so we update the channel mapping here.
|
|
|
|
|
|
if (dir == Vst::BusDirections::kInput)
|
|
|
|
|
|
bufferMapper.setInputBusActive ((size_t) index, state != 0);
|
|
|
|
|
|
else
|
|
|
|
|
|
bufferMapper.setOutputBusActive ((size_t) index, state != 0);
|
|
|
|
|
|
|
|
|
if (auto* bus = pluginInstance->getBus (dir == Vst::kInput, index))
|
|
|
if (auto* bus = pluginInstance->getBus (dir == Vst::kInput, index))
|
|
|
{
|
|
|
{
|
|
|
#ifdef JucePlugin_PreferredChannelConfigurations
|
|
|
#ifdef JucePlugin_PreferredChannelConfigurations
|
|
|
@@ -3179,8 +3172,8 @@ public: |
|
|
// If all of these are zero, the host is attempting to flush parameters without processing audio.
|
|
|
// If all of these are zero, the host is attempting to flush parameters without processing audio.
|
|
|
if (data.numSamples != 0 || data.numInputs != 0 || data.numOutputs != 0)
|
|
|
if (data.numSamples != 0 || data.numInputs != 0 || data.numOutputs != 0)
|
|
|
{
|
|
|
{
|
|
|
if (processSetup.symbolicSampleSize == Vst::kSample32) processAudio<float> (data, channelListFloat);
|
|
|
|
|
|
else if (processSetup.symbolicSampleSize == Vst::kSample64) processAudio<double> (data, channelListDouble);
|
|
|
|
|
|
|
|
|
if (processSetup.symbolicSampleSize == Vst::kSample32) processAudio<float> (data);
|
|
|
|
|
|
else if (processSetup.symbolicSampleSize == Vst::kSample64) processAudio<double> (data);
|
|
|
else jassertfalse;
|
|
|
else jassertfalse;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -3251,131 +3244,11 @@ private: |
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
//==============================================================================
|
|
|
template <typename FloatType>
|
|
|
template <typename FloatType>
|
|
|
void processAudio (Vst::ProcessData& data, Array<FloatType*>& channelList)
|
|
|
|
|
|
|
|
|
void processAudio (Vst::ProcessData& data)
|
|
|
{
|
|
|
{
|
|
|
int totalInputChans = 0, totalOutputChans = 0;
|
|
|
|
|
|
bool tmpBufferNeedsClearing = false;
|
|
|
|
|
|
|
|
|
|
|
|
auto plugInInputChannels = pluginInstance->getTotalNumInputChannels();
|
|
|
|
|
|
auto plugInOutputChannels = pluginInstance->getTotalNumOutputChannels();
|
|
|
|
|
|
|
|
|
|
|
|
// Wavelab workaround: wave-lab lies on the number of inputs/outputs so re-count here
|
|
|
|
|
|
const auto countValidChannels = [] (Vst::AudioBusBuffers* buffers, int32 num)
|
|
|
|
|
|
{
|
|
|
|
|
|
return int (std::distance (buffers, std::find_if (buffers, buffers + num, [] (Vst::AudioBusBuffers& buf)
|
|
|
|
|
|
{
|
|
|
|
|
|
return getPointerForAudioBus<FloatType> (buf) == nullptr && buf.numChannels > 0;
|
|
|
|
|
|
})));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const auto vstInputs = countValidChannels (data.inputs, data.numInputs);
|
|
|
|
|
|
const auto vstOutputs = countValidChannels (data.outputs, data.numOutputs);
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
auto n = jmax (vstOutputs, getNumAudioBuses (false));
|
|
|
|
|
|
|
|
|
|
|
|
for (int bus = 0; bus < n && totalOutputChans < plugInOutputChannels; ++bus)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto* busObject = pluginInstance->getBus (false, bus))
|
|
|
|
|
|
if (! busObject->isEnabled())
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (bus < vstOutputs)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto** const busChannels = getPointerForAudioBus<FloatType> (data.outputs[bus]))
|
|
|
|
|
|
{
|
|
|
|
|
|
auto numChans = jmin ((int) data.outputs[bus].numChannels, plugInOutputChannels - totalOutputChans);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numChans; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto dst = busChannels[i])
|
|
|
|
|
|
{
|
|
|
|
|
|
if (totalOutputChans >= plugInInputChannels)
|
|
|
|
|
|
FloatVectorOperations::clear (dst, (int) data.numSamples);
|
|
|
|
|
|
|
|
|
|
|
|
channelList.set (totalOutputChans++, busChannels[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
const int numChans = jmin (pluginInstance->getChannelCountOfBus (false, bus), plugInOutputChannels - totalOutputChans);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numChans; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto* tmpBuffer = getTmpBufferForChannel<FloatType> (totalOutputChans, data.numSamples))\
|
|
|
|
|
|
{
|
|
|
|
|
|
tmpBufferNeedsClearing = true;
|
|
|
|
|
|
channelList.set (totalOutputChans++, tmpBuffer);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
auto n = jmax (vstInputs, getNumAudioBuses (true));
|
|
|
|
|
|
|
|
|
|
|
|
for (int bus = 0; bus < n && totalInputChans < plugInInputChannels; ++bus)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto* busObject = pluginInstance->getBus (true, bus))
|
|
|
|
|
|
if (! busObject->isEnabled())
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (bus < vstInputs)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto** const busChannels = getPointerForAudioBus<FloatType> (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)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (totalInputChans >= totalOutputChans)
|
|
|
|
|
|
channelList.set (totalInputChans, busChannels[i]);
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
auto* dst = channelList.getReference (totalInputChans);
|
|
|
|
|
|
auto* src = busChannels[i];
|
|
|
|
|
|
|
|
|
|
|
|
if (dst != src)
|
|
|
|
|
|
FloatVectorOperations::copy (dst, src, (int) data.numSamples);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
++totalInputChans;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
auto numChans = jmin (pluginInstance->getChannelCountOfBus (true, bus), plugInInputChannels - totalInputChans);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numChans; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (auto* tmpBuffer = getTmpBufferForChannel<FloatType> (totalInputChans, data.numSamples))
|
|
|
|
|
|
{
|
|
|
|
|
|
tmpBufferNeedsClearing = true;
|
|
|
|
|
|
channelList.set (totalInputChans++, tmpBuffer);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tmpBufferNeedsClearing)
|
|
|
|
|
|
ChooseBufferHelper<FloatType>::impl (emptyBufferFloat, emptyBufferDouble).clear();
|
|
|
|
|
|
|
|
|
|
|
|
AudioBuffer<FloatType> buffer;
|
|
|
|
|
|
|
|
|
|
|
|
if (int totalChans = jmax (totalOutputChans, totalInputChans))
|
|
|
|
|
|
buffer.setDataToReferTo (channelList.getRawDataPointer(), totalChans, (int) data.numSamples);
|
|
|
|
|
|
|
|
|
auto buffer = bufferMapper.getJuceLayoutForVst3Buffer (detail::Tag<FloatType>{}, data);
|
|
|
|
|
|
jassert ((int) buffer.getNumChannels() == jmax (pluginInstance->getTotalNumInputChannels(),
|
|
|
|
|
|
pluginInstance->getTotalNumOutputChannels()));
|
|
|
|
|
|
|
|
|
{
|
|
|
{
|
|
|
const ScopedLock sl (pluginInstance->getCallbackLock());
|
|
|
const ScopedLock sl (pluginInstance->getCallbackLock());
|
|
|
@@ -3392,16 +3265,12 @@ private: |
|
|
}
|
|
|
}
|
|
|
else
|
|
|
else
|
|
|
{
|
|
|
{
|
|
|
if (totalInputChans == pluginInstance->getTotalNumInputChannels()
|
|
|
|
|
|
&& totalOutputChans == pluginInstance->getTotalNumOutputChannels())
|
|
|
|
|
|
{
|
|
|
|
|
|
// processBlockBypassed should only ever be called if the AudioProcessor doesn't
|
|
|
|
|
|
// return a valid parameter from getBypassParameter
|
|
|
|
|
|
if (pluginInstance->getBypassParameter() == nullptr && comPluginInstance->getBypassParameter()->getValue() >= 0.5f)
|
|
|
|
|
|
pluginInstance->processBlockBypassed (buffer, midiBuffer);
|
|
|
|
|
|
else
|
|
|
|
|
|
pluginInstance->processBlock (buffer, midiBuffer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
// processBlockBypassed should only ever be called if the AudioProcessor doesn't
|
|
|
|
|
|
// return a valid parameter from getBypassParameter
|
|
|
|
|
|
if (pluginInstance->getBypassParameter() == nullptr && comPluginInstance->getBypassParameter()->getValue() >= 0.5f)
|
|
|
|
|
|
pluginInstance->processBlockBypassed (buffer, midiBuffer);
|
|
|
|
|
|
else
|
|
|
|
|
|
pluginInstance->processBlock (buffer, midiBuffer);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
#if JUCE_DEBUG && (! JucePlugin_ProducesMidiOutput)
|
|
|
#if JUCE_DEBUG && (! JucePlugin_ProducesMidiOutput)
|
|
|
@@ -3425,44 +3294,6 @@ private: |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
//==============================================================================
|
|
|
template <typename FloatType>
|
|
|
|
|
|
void allocateChannelListAndBuffers (Array<FloatType*>& channelList, AudioBuffer<FloatType>& buffer)
|
|
|
|
|
|
{
|
|
|
|
|
|
channelList.clearQuick();
|
|
|
|
|
|
channelList.insertMultiple (0, nullptr, 128);
|
|
|
|
|
|
|
|
|
|
|
|
auto& p = getPluginInstance();
|
|
|
|
|
|
buffer.setSize (jmax (p.getTotalNumInputChannels(), p.getTotalNumOutputChannels()), p.getBlockSize() * 4);
|
|
|
|
|
|
buffer.clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename FloatType>
|
|
|
|
|
|
void deallocateChannelListAndBuffers (Array<FloatType*>& channelList, AudioBuffer<FloatType>& buffer)
|
|
|
|
|
|
{
|
|
|
|
|
|
channelList.clearQuick();
|
|
|
|
|
|
channelList.resize (0);
|
|
|
|
|
|
buffer.setSize (0, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename FloatType>
|
|
|
|
|
|
static FloatType** getPointerForAudioBus (Vst::AudioBusBuffers& data) noexcept
|
|
|
|
|
|
{
|
|
|
|
|
|
return AudioBusPointerHelper<FloatType>::impl (data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename FloatType>
|
|
|
|
|
|
FloatType* getTmpBufferForChannel (int channel, int numSamples) noexcept
|
|
|
|
|
|
{
|
|
|
|
|
|
auto& buffer = ChooseBufferHelper<FloatType>::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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Steinberg::uint32 PLUGIN_API getProcessContextRequirements() override
|
|
|
Steinberg::uint32 PLUGIN_API getProcessContextRequirements() override
|
|
|
{
|
|
|
{
|
|
|
return kNeedSystemTime
|
|
|
return kNeedSystemTime
|
|
|
@@ -3487,6 +3318,8 @@ private: |
|
|
|
|
|
|
|
|
midiBuffer.ensureSize (2048);
|
|
|
midiBuffer.ensureSize (2048);
|
|
|
midiBuffer.clear();
|
|
|
midiBuffer.clear();
|
|
|
|
|
|
|
|
|
|
|
|
bufferMapper.prepare (p, bufferSize);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
//==============================================================================
|
|
|
@@ -3542,11 +3375,7 @@ private: |
|
|
Vst::ProcessSetup processSetup;
|
|
|
Vst::ProcessSetup processSetup;
|
|
|
|
|
|
|
|
|
MidiBuffer midiBuffer;
|
|
|
MidiBuffer midiBuffer;
|
|
|
Array<float*> channelListFloat;
|
|
|
|
|
|
Array<double*> channelListDouble;
|
|
|
|
|
|
|
|
|
|
|
|
AudioBuffer<float> emptyBufferFloat;
|
|
|
|
|
|
AudioBuffer<double> emptyBufferDouble;
|
|
|
|
|
|
|
|
|
ClientBufferMapper bufferMapper;
|
|
|
|
|
|
|
|
|
bool active = false;
|
|
|
bool active = false;
|
|
|
|
|
|
|
|
|
|