From 9b81643aa98871e4eac0e4e56781abb822a96ba4 Mon Sep 17 00:00:00 2001 From: hogliux Date: Mon, 4 Jun 2018 15:13:28 +0100 Subject: [PATCH] Plug-In wrappers and hosting code now support infinite tail times --- BREAKING-CHANGES.txt | 19 ++++++++++++++++ .../VST/juce_VST_Wrapper.cpp | 22 +++++++++++++++---- .../VST3/juce_VST3_Wrapper.cpp | 3 +++ .../format_types/juce_VST3PluginFormat.cpp | 7 ++++++ .../format_types/juce_VSTInterface.h | 11 +++++----- .../format_types/juce_VSTPluginFormat.cpp | 17 +++++++++++--- 6 files changed, 67 insertions(+), 12 deletions(-) diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index 937d849969..1b5a8e56ad 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -4,6 +4,25 @@ JUCE breaking changes Develop ======= +Change +------ +AudioProcessor::getTailLengthSeconds can now return infinity for VST/VST3/AU/AUv3 + +Possible Issues +--------------- +If you are using the result of getTailLengthSeconds to allocate a buffer in your host, +then your host will now likely crash when loading a plug-in with an infinite tail time. + +Workaround +---------- +Re-write your code to not use the result of getTailLengthSeconds directly to allocate +a buffer. + +Rationale +--------- + +Before this change there was no way for a JUCE plug-in to report an infinite tail time. + Version 5.3.2 ============= diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp index 216265ea4d..1a22827283 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp @@ -317,12 +317,15 @@ public: if (processor->supportsDoublePrecisionProcessing()) vstEffect.flags |= vstEffectFlagInplaceDoubleAudio; + vstEffect.flags |= vstEffectFlagDataInChunks; + #if JucePlugin_IsSynth vstEffect.flags |= vstEffectFlagIsSynth; + #else + if (processor->getTailLengthSeconds() == 0.0) + vstEffect.flags |= vstEffectFlagSilenceInProducesSilenceOut; #endif - vstEffect.flags |= vstEffectFlagDataInChunks; - activePlugins.add (this); } @@ -588,7 +591,7 @@ public: if (getHostType().isAbletonLive() && hostCallback != nullptr - && processor->getTailLengthSeconds() == std::numeric_limits::max()) + && processor->getTailLengthSeconds() == std::numeric_limits::infinity()) { AbletonLiveHostSpecific hostCmd; @@ -2046,7 +2049,18 @@ private: pointer_sized_int handleGetTailSize (VstOpCodeArguments) { if (processor != nullptr) - return (pointer_sized_int) (processor->getTailLengthSeconds() * sampleRate); + { + int32 result; + + auto tailSeconds = processor->getTailLengthSeconds(); + + if (tailSeconds == std::numeric_limits::infinity()) + result = std::numeric_limits::max(); + else + result = static_cast (tailSeconds * sampleRate); + + return result; // Vst2 expects an int32 upcasted to a intptr_t here + } return 0; } 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 80dc9a4fa0..89b2f21ea0 100644 --- a/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp @@ -2033,6 +2033,9 @@ public: if (tailLengthSeconds <= 0.0 || processSetup.sampleRate <= 0.0) return Vst::kNoTail; + if (tailLengthSeconds == std::numeric_limits::infinity()) + return Vst::kInfiniteTail; + return (Steinberg::uint32) roundToIntAccurate (tailLengthSeconds * processSetup.sampleRate); } diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 35db7ab353..6a537be411 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -2296,7 +2296,14 @@ struct VST3PluginInstance : public AudioPluginInstance auto sampleRate = getSampleRate(); if (sampleRate > 0.0) + { + auto tailSamples = processor->getTailSamples(); + + if (tailSamples == Vst::kInfiniteTail) + return std::numeric_limits::infinity(); + return jlimit (0, 0x7fffffff, (int) processor->getTailSamples()) / sampleRate; + } } return 0.0; diff --git a/modules/juce_audio_processors/format_types/juce_VSTInterface.h b/modules/juce_audio_processors/format_types/juce_VSTInterface.h index a2f09aae93..a6c63e24f9 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTInterface.h +++ b/modules/juce_audio_processors/format_types/juce_VSTInterface.h @@ -83,11 +83,12 @@ typedef pointer_sized_int (VSTINTERFACECALL* VstHostCallback) (VstEffectInterfac enum VstEffectInterfaceFlags { - vstEffectFlagHasEditor = 1, - vstEffectFlagInplaceAudio = 16, - vstEffectFlagDataInChunks = 32, - vstEffectFlagIsSynth = 256, - vstEffectFlagInplaceDoubleAudio = 4096 + vstEffectFlagHasEditor = 1, + vstEffectFlagInplaceAudio = 16, + vstEffectFlagDataInChunks = 32, + vstEffectFlagIsSynth = 256, + vstEffectFlagSilenceInProducesSilenceOut = 512, + vstEffectFlagInplaceDoubleAudio = 4096 }; //============================================================================== diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index 06dfcb0261..293dcd24a8 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -1283,12 +1283,23 @@ struct VSTPluginInstance : public AudioPluginInstance, if (vstEffect == nullptr) return 0.0; + if ((vstEffect->flags & vstEffectFlagSilenceInProducesSilenceOut) != 0) + return 0.0; + + auto tailSize = dispatch (plugInOpcodeGetTailSize, 0, 0, 0, 0); auto sampleRate = getSampleRate(); - if (sampleRate <= 0) - return 0.0; + // remain backward compatible with old JUCE plug-ins: anything larger + // than INT32_MAX is an invalid tail time but old JUCE 64-bit plug-ins + // would return INT64_MAX for infinite tail time. So treat anything + // equal or greater than INT32_MAX as infinite tail time. + if (tailSize >= std::numeric_limits::max()) + return std::numeric_limits::infinity(); + + if (tailSize >= 0 && sampleRate > 0) + return static_cast (tailSize) / sampleRate; - return dispatch (plugInOpcodeGetTailSize, 0, 0, 0, 0) / sampleRate; + return 0.0; } bool acceptsMidi() const override { return wantsMidiMessages; }