diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index 65354cc3bb..55bd797e55 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -878,6 +878,20 @@ public: desc.isInstrument = (componentDesc.componentType == kAudioUnitType_MusicDevice); } + void getExtensions (ExtensionsVisitor& visitor) const override + { + struct Extensions : public ExtensionsVisitor::AudioUnitClient + { + explicit Extensions (const AudioUnitPluginInstance* instanceIn) : instance (instanceIn) {} + + void* getAudioUnitHandle() const noexcept override { return instance->audioUnit; } + + const AudioUnitPluginInstance* instance = nullptr; + }; + + visitor.visitAudioUnitClient (Extensions { this }); + } + void* getPlatformSpecificData() override { return audioUnit; } const String getName() const override { return pluginName; } diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index da8e5a51b0..4a41729a44 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -2256,6 +2256,27 @@ public: return true; } + void getExtensions (ExtensionsVisitor& visitor) const override + { + struct Extensions : public ExtensionsVisitor::VST3Client + { + explicit Extensions (const VST3PluginInstance* instanceIn) : instance (instanceIn) {} + + void* getIComponentPtr() const noexcept override { return instance->holder->component; } + + MemoryBlock getPreset() const override { return instance->getStateForPresetFile(); } + + bool setPreset (const MemoryBlock& rawData) const override + { + return instance->setStateFromPresetFile (rawData); + } + + const VST3PluginInstance* instance = nullptr; + }; + + visitor.visitVST3Client (Extensions { this }); + } + void* getPlatformSpecificData() override { return holder->component; } void updateMidiMappings() @@ -2857,7 +2878,25 @@ public: } } - bool setStateFromPresetFile (const MemoryBlock& rawData) + MemoryBlock getStateForPresetFile() const + { + VSTComSmartPtr memoryStream = new Steinberg::MemoryStream(); + + if (memoryStream == nullptr || holder->component == nullptr) + return {}; + + const auto saved = Steinberg::Vst::PresetFile::savePreset (memoryStream, + holder->cidOfComponent, + holder->component, + editController); + + if (saved) + return { memoryStream->getData(), static_cast (memoryStream->getSize()) }; + + return {}; + } + + bool setStateFromPresetFile (const MemoryBlock& rawData) const { MemoryBlock rawDataCopy (rawData); VSTComSmartPtr memoryStream = new Steinberg::MemoryStream (rawDataCopy.getData(), (int) rawDataCopy.getSize()); @@ -3539,8 +3578,8 @@ tresult VST3HostContext::notifyProgramListChange (Vst::ProgramListID, Steinberg: //============================================================================== //============================================================================== -VST3PluginFormat::VST3PluginFormat() {} -VST3PluginFormat::~VST3PluginFormat() {} +VST3PluginFormat::VST3PluginFormat() = default; +VST3PluginFormat::~VST3PluginFormat() = default; bool VST3PluginFormat::setStateFromVSTPresetFile (AudioPluginInstance* api, const MemoryBlock& rawData) { diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h index 66d5123bfe..88ebeba29b 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h @@ -43,11 +43,16 @@ public: ~VST3PluginFormat() override; //============================================================================== - /** Attempts to reload a VST3 plugin's state from some preset file data. + /** Instead of using this function, use AudioPluginInstance::getExtensions() + to visit the ExtensionsVisitor::VST3 struct for the instance, if it exists. + Then, call ExtensionsVisitor::VST3::setPreset() to set the state using the + contents of a vstpreset file. + + Attempts to reload a VST3 plugin's state from some preset file data. @see VSTPluginFormat::loadFromFXBFile */ - static bool setStateFromVSTPresetFile (AudioPluginInstance*, const MemoryBlock&); + JUCE_DEPRECATED (static bool setStateFromVSTPresetFile (AudioPluginInstance*, const MemoryBlock&)); //============================================================================== static String getFormatName() { return "VST3"; } diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index 6235345b23..3d2849e3c7 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -1250,6 +1250,20 @@ struct VSTPluginInstance : public AudioPluginInstance, setLatencySamples (vstEffect->initialDelay); } + void getExtensions (ExtensionsVisitor& visitor) const override + { + struct Extensions : public ExtensionsVisitor::VSTClient + { + explicit Extensions (const VSTPluginInstance* instanceIn) : instance (instanceIn) {} + + void* getAEffectPtr() const noexcept override { return instance->vstEffect; } + + const VSTPluginInstance* instance = nullptr; + }; + + visitor.visitVSTClient (Extensions { this }); + } + void* getPlatformSpecificData() override { return vstEffect; } const String getName() const override diff --git a/modules/juce_audio_processors/juce_audio_processors.h b/modules/juce_audio_processors/juce_audio_processors.h index e543a92fdb..97cd93bf76 100644 --- a/modules/juce_audio_processors/juce_audio_processors.h +++ b/modules/juce_audio_processors/juce_audio_processors.h @@ -115,6 +115,7 @@ #endif //============================================================================== +#include "utilities/juce_ExtensionsVisitor.h" #include "processors/juce_AudioProcessorEditor.h" #include "processors/juce_AudioProcessorListener.h" #include "processors/juce_AudioProcessorParameter.h" diff --git a/modules/juce_audio_processors/processors/juce_AudioPluginInstance.cpp b/modules/juce_audio_processors/processors/juce_AudioPluginInstance.cpp index 3164ec9c55..6153487eff 100644 --- a/modules/juce_audio_processors/processors/juce_AudioPluginInstance.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioPluginInstance.cpp @@ -35,6 +35,8 @@ PluginDescription AudioPluginInstance::getPluginDescription() const void* AudioPluginInstance::getPlatformSpecificData() { return nullptr; } +void AudioPluginInstance::getExtensions (ExtensionsVisitor& visitor) const { visitor.visitUnknown ({}); } + String AudioPluginInstance::getParameterID (int parameterIndex) { assertOnceOnDeprecatedMethodUse(); diff --git a/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h b/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h index 79d76bd86e..8a5a559990 100644 --- a/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h +++ b/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h @@ -65,11 +65,24 @@ public: */ PluginDescription getPluginDescription() const; - /** Returns a pointer to some kind of platform-specific data about the plugin. + /** Allows retrieval of information related to the inner workings of a particular plugin format, + such as the AEffect* of a VST, or the handle of an AudioUnit. + + To use this, create a new class derived from ExtensionsVisitor, and override + each of the visit member functions. If this AudioPluginInstance wraps a VST3 plugin + the visitVST3() member will be called, while if the AudioPluginInstance wraps an + unknown format the visitUnknown() member will be called. The argument of the visit function + can be queried to extract information related to the AudioPluginInstance's implementation. + */ + virtual void getExtensions (ExtensionsVisitor&) const; + + /** Use the new typesafe visitor-based interface rather than this function. + + Returns a pointer to some kind of platform-specific data about the plugin. E.g. For a VST, this value can be cast to an AEffect*. For an AudioUnit, it can be cast to an AudioUnit handle. */ - virtual void* getPlatformSpecificData(); + JUCE_DEPRECATED (virtual void* getPlatformSpecificData()); // Rather than using these methods you should call the corresponding methods // on the AudioProcessorParameter objects returned from getParameters(). diff --git a/modules/juce_audio_processors/utilities/juce_ExtensionsVisitor.h b/modules/juce_audio_processors/utilities/juce_ExtensionsVisitor.h new file mode 100644 index 0000000000..8e5c7b25b6 --- /dev/null +++ b/modules/juce_audio_processors/utilities/juce_ExtensionsVisitor.h @@ -0,0 +1,85 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2020 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 6 End-User License + Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). + + End User License Agreement: www.juce.com/juce-6-licence + Privacy Policy: www.juce.com/juce-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +/** Create a derived implementation of this class and pass it to + AudioPluginInstance::getExtensions() to retrieve format-specific + information about a plugin instance. + + Note that the references passed to the visit member functions are only + guaranteed to live for the duration of the function call, so don't + store pointers to these objects! If you need to store and reuse + format-specific information, it is recommended to copy the result + of the function calls that you care about. For example, you should + store the result of VST::getAEffectPtr() rather than storing a pointer + to the VST instance. +*/ +struct ExtensionsVisitor +{ + struct Unknown {}; + + /** Can be used to retrieve information about a VST3 that is wrapped by an AudioProcessor. */ + struct VST3Client + { + virtual ~VST3Client() = default; + virtual void* getIComponentPtr() const noexcept = 0; + + virtual MemoryBlock getPreset() const = 0; + virtual bool setPreset (const MemoryBlock&) const = 0; + }; + + /** Can be used to retrieve information about an AudioUnit that is wrapped by an AudioProcessor. */ + struct AudioUnitClient + { + virtual ~AudioUnitClient() = default; + virtual void* getAudioUnitHandle() const noexcept = 0; + }; + + /** Can be used to retrieve information about a VST that is wrapped by an AudioProcessor. */ + struct VSTClient + { + virtual ~VSTClient() = default; + virtual void* getAEffectPtr() const noexcept = 0; + }; + + virtual ~ExtensionsVisitor() = default; + + /** Will be called if there is no platform specific information available. */ + virtual void visitUnknown (const Unknown&) {} + + /** Called with VST3-specific information. */ + virtual void visitVST3Client (const VST3Client&) {} + + /** Called with VST-specific information. */ + virtual void visitVSTClient (const VSTClient&) {} + + /** Called with AU-specific information. */ + virtual void visitAudioUnitClient (const AudioUnitClient&) {} +}; + +} // namespace juce