diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index cf7f2a81437c..0090f3854aa5 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -613,7 +613,9 @@ static int countValidBuses (Steinberg::Vst::AudioBusBuffers* buffers, int32 num) })); } -template +enum class Direction { input, output }; + +template static bool validateLayouts (Iterator first, Iterator last, const std::vector& map) { if ((size_t) std::distance (first, last) > map.size()) @@ -623,12 +625,24 @@ static bool validateLayouts (Iterator first, Iterator last, const std::vector{}, *it); - const auto anyChannelIsNull = std::any_of (busPtr, busPtr + it->numChannels, [] (auto* ptr) { return ptr == nullptr; }); + auto& bus = *it; + auto** busPtr = getAudioBusPointer (detail::Tag{}, bus); + const auto expectedChannels = static_cast (mapIterator->size()); + const auto actualChannels = static_cast (bus.numChannels); + const auto limit = jmin (expectedChannels, actualChannels); + const auto anyChannelIsNull = std::any_of (busPtr, busPtr + limit, [] (auto* ptr) { return ptr == nullptr; }); + constexpr auto isInput = direction == Direction::input; + + const auto channelCountIsUsable = isInput ? expectedChannels <= actualChannels + : actualChannels <= expectedChannels; // Null channels are allowed if the bus is inactive - if (mapIterator->isHostActive() && (anyChannelIsNull || (int) mapIterator->size() != it->numChannels)) + if (mapIterator->isHostActive() && (anyChannelIsNull || ! channelCountIsUsable)) return false; + + // If this is hit, the destination bus has fewer channels than the source bus. + // As a result, some channels will 'go missing', and channel layouts may be invalid. + jassert (actualChannels == expectedChannels); } // If the host didn't provide the full complement of buses, it must be because the other @@ -669,7 +683,7 @@ class ClientBufferMapperData // WaveLab workaround: This host may report the wrong number of inputs/outputs so re-count here const auto vstInputs = countValidBuses (data.inputs, data.numInputs); - if (! validateLayouts (data.inputs, data.inputs + vstInputs, inputMap)) + if (! validateLayouts (data.inputs, data.inputs + vstInputs, inputMap)) return getBlankBuffer (usedChannels, (int) data.numSamples); setUpInputChannels (data, (size_t) vstInputs, scratchBuffer, inputMap, channels); @@ -702,7 +716,12 @@ class ClientBufferMapperData if (mapping.isHostActive() && busIndex < vstInputs) { - auto** busPtr = getAudioBusPointer (detail::Tag{}, data.inputs[busIndex]); + auto& bus = data.inputs[busIndex]; + + // Every JUCE channel must have a VST3 channel counterpart + jassert (mapping.size() <= static_cast (bus.numChannels)); + + auto** busPtr = getAudioBusPointer (detail::Tag{}, bus); for (size_t channelIndex = 0; channelIndex < mapping.size(); ++channelIndex) { @@ -921,7 +940,7 @@ class ClientRemappedBuffer // WaveLab workaround: This host may report the wrong number of inputs/outputs so re-count here const auto vstOutputs = (size_t) countValidBuses (data.outputs, data.numOutputs); - if (validateLayouts (data.outputs, data.outputs + vstOutputs, *outputMap)) + if (validateLayouts (data.outputs, data.outputs + vstOutputs, *outputMap)) copyToHostOutputBuses (vstOutputs); else clearHostOutputBuses (vstOutputs); @@ -940,9 +959,12 @@ class ClientRemappedBuffer { auto& bus = data.outputs[i]; + // Every VST3 channel must have a JUCE channel counterpart + jassert (static_cast (bus.numChannels) <= mapping.size()); + if (mapping.isClientActive()) { - for (size_t j = 0; j < mapping.size(); ++j) + for (size_t j = 0; j < static_cast (bus.numChannels); ++j) { auto* hostChannel = getAudioBusPointer (detail::Tag{}, bus)[j]; const auto juceChannel = juceBusOffset + (size_t) mapping.getJuceChannelForVst3Channel ((int) j); @@ -951,7 +973,7 @@ class ClientRemappedBuffer } else { - for (size_t j = 0; j < mapping.size(); ++j) + for (size_t j = 0; j < static_cast (bus.numChannels); ++j) { auto* hostChannel = getAudioBusPointer (detail::Tag{}, bus)[j]; FloatVectorOperations::clear (hostChannel, (size_t) data.numSamples); diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 7865d50bdad1..4426ad13c191 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -94,7 +94,6 @@ static int warnOnFailureIfImplemented (int result) noexcept #define warnOnFailureIfImplemented(x) x #endif -enum class Direction { input, output }; enum class MediaKind { audio, event }; static Vst::MediaType toVstType (MediaKind x) { return x == MediaKind::audio ? Vst::kAudio : Vst::kEvent; }