diff --git a/source/modules/juce_audio_processors/Makefile b/source/modules/juce_audio_processors/Makefile deleted file mode 100644 index c246b23ec..000000000 --- a/source/modules/juce_audio_processors/Makefile +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/make -f -# Makefile for juce_audio_processors # -# ---------------------------------- # -# Created by falkTX -# - -CWD=../.. -MODULENAME=juce_audio_processors -include ../Makefile.mk - -# ---------------------------------------------------------------------------------------------------------------------------- - -BUILD_CXX_FLAGS += $(JUCE_AUDIO_PROCESSORS_FLAGS) -I$(CWD)/includes/ladspa -I$(CWD)/includes/vst2 -I$(CWD)/includes/vst3 -I.. - -ifeq ($(CARLA_VESTIGE_HEADER),true) -BUILD_CXX_FLAGS += -DVESTIGE_HEADER -else -# needed by vst3 -BUILD_CXX_FLAGS += -w -ifeq ($(DEBUG),true) -BUILD_CXX_FLAGS += -DDEVELOPMENT -D_DEBUG -else -BUILD_CXX_FLAGS += -DRELEASE -endif -# needed by vst3 on mingw -ifeq ($(WIN32),true) -BUILD_CXX_FLAGS += -D_NATIVE_WCHAR_T_DEFINED -D__wchar_t=wchar_t -fpermissive -endif -endif - -# ---------------------------------------------------------------------------------------------------------------------------- - -ifeq ($(MACOS),true) -OBJS = $(OBJDIR)/$(MODULENAME).mm.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).mm.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).mm.posix64.o -else -OBJS = $(OBJDIR)/$(MODULENAME).cpp.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).cpp.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).cpp.posix64.o -endif -OBJS_win32 = $(OBJDIR)/$(MODULENAME).cpp.win32.o -OBJS_win64 = $(OBJDIR)/$(MODULENAME).cpp.win64.o - -# ---------------------------------------------------------------------------------------------------------------------------- - -all: $(MODULEDIR)/$(MODULENAME).a -posix32: $(MODULEDIR)/$(MODULENAME).posix32.a -posix64: $(MODULEDIR)/$(MODULENAME).posix64.a -win32: $(MODULEDIR)/$(MODULENAME).win32.a -win64: $(MODULEDIR)/$(MODULENAME).win64.a - -# ---------------------------------------------------------------------------------------------------------------------------- - -clean: - rm -f $(OBJDIR)/*.o $(MODULEDIR)/$(MODULENAME)*.a - -debug: - $(MAKE) DEBUG=true - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(MODULEDIR)/$(MODULENAME).a: $(OBJS) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix32.a: $(OBJS_posix32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix64.a: $(OBJS_posix64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win32.a: $(OBJS_win32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win64.a: $(OBJS_win64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).cpp.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).mm.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -ObjC++ -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - --include $(OBJS:%.o=%.d) --include $(OBJS_posix32:%.o=%.d) --include $(OBJS_posix64:%.o=%.d) --include $(OBJS_win32:%.o=%.d) --include $(OBJS_win64:%.o=%.d) - -# ---------------------------------------------------------------------------------------------------------------------------- diff --git a/source/modules/juce_audio_processors/format/juce_AudioPluginFormat.cpp b/source/modules/juce_audio_processors/format/juce_AudioPluginFormat.cpp deleted file mode 100644 index 8b33d4d04..000000000 --- a/source/modules/juce_audio_processors/format/juce_AudioPluginFormat.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -namespace AudioPluginFormatHelpers -{ - struct CallbackInvoker - { - struct InvokeOnMessageThread : public CallbackMessage - { - InvokeOnMessageThread (AudioPluginInstance* inInstance, const String& inError, - AudioPluginFormat::InstantiationCompletionCallback* inCompletion, - CallbackInvoker* invoker) - : instance (inInstance), error (inError), compCallback (inCompletion), owner (invoker) - {} - - void messageCallback() override { compCallback->completionCallback (instance, error); } - - //============================================================================== - AudioPluginInstance* instance; - String error; - ScopedPointer compCallback; - ScopedPointer owner; - }; - - //============================================================================== - CallbackInvoker (AudioPluginFormat::InstantiationCompletionCallback* cc) : completion (cc) - {} - - void completionCallback (AudioPluginInstance* instance, const String& error) - { - (new InvokeOnMessageThread (instance, error, completion, this))->post(); - } - - static void staticCompletionCallback (void* userData, AudioPluginInstance* instance, const String& error) - { - reinterpret_cast (userData)->completionCallback (instance, error); - } - - //============================================================================== - AudioPluginFormat::InstantiationCompletionCallback* completion; - }; -} - -AudioPluginFormat::AudioPluginFormat() noexcept {} -AudioPluginFormat::~AudioPluginFormat() {} - -AudioPluginInstance* AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc, - double initialSampleRate, - int initialBufferSize) -{ - String errorMessage; - return createInstanceFromDescription (desc, initialSampleRate, initialBufferSize, errorMessage); -} - -//============================================================================== -struct EventSignaler : public AudioPluginFormat::InstantiationCompletionCallback -{ - EventSignaler (WaitableEvent& inEvent, AudioPluginInstance*& inInstance, String& inErrorMessage) - : event (inEvent), outInstance (inInstance), outErrorMessage (inErrorMessage) - {} - - void completionCallback (AudioPluginInstance* newInstance, const String& result) override - { - outInstance = newInstance; - outErrorMessage = result; - event.signal(); - } - - static void staticCompletionCallback (void* userData, AudioPluginInstance* pluginInstance, const String& error) - { - reinterpret_cast (userData)->completionCallback (pluginInstance, error); - } - - WaitableEvent& event; - AudioPluginInstance*& outInstance; - String& outErrorMessage; - - JUCE_DECLARE_NON_COPYABLE (EventSignaler) -}; - -AudioPluginInstance* AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc, - double initialSampleRate, - int initialBufferSize, - String& errorMessage) -{ - if (MessageManager::getInstance()->isThisTheMessageThread() - && requiresUnblockedMessageThreadDuringCreation(desc)) - { - errorMessage = NEEDS_TRANS ("This plug-in cannot be instantiated synchronously"); - return nullptr; - } - - WaitableEvent waitForCreation; - AudioPluginInstance* instance = nullptr; - - ScopedPointer eventSignaler (new EventSignaler (waitForCreation, instance, errorMessage)); - - if (! MessageManager::getInstance()->isThisTheMessageThread()) - createPluginInstanceAsync (desc, initialSampleRate, initialBufferSize, eventSignaler.release()); - else - createPluginInstance (desc, initialSampleRate, initialBufferSize, - eventSignaler, EventSignaler::staticCompletionCallback); - - - waitForCreation.wait(); - - return instance; -} - -void AudioPluginFormat::createPluginInstanceAsync (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - AudioPluginFormat::InstantiationCompletionCallback* callback) -{ - if (MessageManager::getInstance()->isThisTheMessageThread()) - { - createPluginInstanceOnMessageThread (description, initialSampleRate, initialBufferSize, callback); - return; - } - - //============================================================================== - struct InvokeOnMessageThread : public CallbackMessage - { - InvokeOnMessageThread (AudioPluginFormat* myself, - const PluginDescription& descriptionParam, - double initialSampleRateParam, - int initialBufferSizeParam, - AudioPluginFormat::InstantiationCompletionCallback* callbackParam) - : owner (myself), descr (descriptionParam), sampleRate (initialSampleRateParam), - bufferSize (initialBufferSizeParam), call (callbackParam) - {} - - void messageCallback() override - { - owner->createPluginInstanceOnMessageThread (descr, sampleRate, bufferSize, call); - } - - AudioPluginFormat* owner; - PluginDescription descr; - double sampleRate; - int bufferSize; - AudioPluginFormat::InstantiationCompletionCallback* call; - }; - - (new InvokeOnMessageThread (this, description, initialSampleRate, initialBufferSize, callback))->post(); -} - -void AudioPluginFormat::createPluginInstanceAsync (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - std::function f) -{ - struct CallbackInvoker : public AudioPluginFormat::InstantiationCompletionCallback - { - CallbackInvoker (std::function inCompletion) - : completion (inCompletion) - {} - - void completionCallback (AudioPluginInstance* instance, const String& error) override - { - completion (instance, error); - } - - std::function completion; - }; - - createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, new CallbackInvoker (f)); -} - -void AudioPluginFormat::createPluginInstanceOnMessageThread (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - AudioPluginFormat::InstantiationCompletionCallback* callback) -{ - jassert (callback != nullptr); - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - - //============================================================================== - - - //============================================================================== - AudioPluginFormatHelpers::CallbackInvoker* completion = new AudioPluginFormatHelpers::CallbackInvoker (callback); - - createPluginInstance (description, initialSampleRate, initialBufferSize, completion, - AudioPluginFormatHelpers::CallbackInvoker::staticCompletionCallback); -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/format/juce_AudioPluginFormat.h b/source/modules/juce_audio_processors/format/juce_AudioPluginFormat.h deleted file mode 100644 index 6eb08eb32..000000000 --- a/source/modules/juce_audio_processors/format/juce_AudioPluginFormat.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc. - - @see AudioPluginFormatManager -*/ -class JUCE_API AudioPluginFormat -{ -public: - //============================================================================== - struct JUCE_API InstantiationCompletionCallback - { - virtual ~InstantiationCompletionCallback() {} - virtual void completionCallback (AudioPluginInstance* instance, const String& error) = 0; - - JUCE_LEAK_DETECTOR (InstantiationCompletionCallback) - }; - - //============================================================================== - /** Destructor. */ - virtual ~AudioPluginFormat(); - - //============================================================================== - /** Returns the format name. - E.g. "VST", "AudioUnit", etc. - */ - virtual String getName() const = 0; - - /** This tries to create descriptions for all the plugin types available in - a binary module file. - - The file will be some kind of DLL or bundle. - - Normally there will only be one type returned, but some plugins - (e.g. VST shells) can use a single DLL to create a set of different plugin - subtypes, so in that case, each subtype is returned as a separate object. - */ - virtual void findAllTypesForFile (OwnedArray& results, - const String& fileOrIdentifier) = 0; - - /** Tries to recreate a type from a previously generated PluginDescription. - @see AudioPluginFormatManager::createInstance - */ - AudioPluginInstance* createInstanceFromDescription (const PluginDescription&, - double initialSampleRate, - int initialBufferSize); - - /** Same as above but with the possibility of returning an error message. - - @see AudioPluginFormatManager::createInstance - */ - AudioPluginInstance* createInstanceFromDescription (const PluginDescription&, - double initialSampleRate, - int initialBufferSize, - String& errorMessage); - - /** Tries to recreate a type from a previously generated PluginDescription. - - @see AudioPluginFormatManager::createInstanceAsync - */ - void createPluginInstanceAsync (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - InstantiationCompletionCallback* completionCallback); - - void createPluginInstanceAsync (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - std::function completionCallback); - - /** Should do a quick check to see if this file or directory might be a plugin of - this format. - - This is for searching for potential files, so it shouldn't actually try to - load the plugin or do anything time-consuming. - */ - virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0; - - /** Returns a readable version of the name of the plugin that this identifier refers to. */ - virtual String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0; - - /** Returns true if this plugin's version or date has changed and it should be re-checked. */ - virtual bool pluginNeedsRescanning (const PluginDescription&) = 0; - - /** Checks whether this plugin could possibly be loaded. - It doesn't actually need to load it, just to check whether the file or component - still exists. - */ - virtual bool doesPluginStillExist (const PluginDescription&) = 0; - - /** Returns true if this format needs to run a scan to find its list of plugins. */ - virtual bool canScanForPlugins() const = 0; - - /** Searches a suggested set of directories for any plugins in this format. - The path might be ignored, e.g. by AUs, which are found by the OS rather - than manually. - - @param directoriesToSearch This specifies which directories shall be - searched for plug-ins. - @param recursive Should the search recursively traverse folders. - @param allowPluginsWhichRequireAsynchronousInstantiation - If this is false then plug-ins which require - asynchronous creation will be excluded. - */ - virtual StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, - bool recursive, - bool allowPluginsWhichRequireAsynchronousInstantiation = false) = 0; - - /** Returns the typical places to look for this kind of plugin. - - Note that if this returns no paths, it means that the format doesn't search in - files or folders, e.g. AudioUnits. - */ - virtual FileSearchPath getDefaultLocationsToSearch() = 0; - -protected: - //============================================================================== - friend class AudioPluginFormatManager; - - AudioPluginFormat() noexcept; - - /** Implementors must override this function. This is guaranteed to be called on - the message thread. You may call the callback on any thread. - */ - virtual void createPluginInstance (const PluginDescription&, double initialSampleRate, - int initialBufferSize, void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) = 0; - - virtual bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept = 0; - -private: - /** @internal */ - void createPluginInstanceOnMessageThread (const PluginDescription&, double rate, int size, - AudioPluginFormat::InstantiationCompletionCallback*); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormat) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.cpp b/source/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.cpp deleted file mode 100644 index ceedf1705..000000000 --- a/source/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -namespace PluginFormatManagerHelpers -{ - struct ErrorCallbackOnMessageThread : public CallbackMessage - { - ErrorCallbackOnMessageThread (const String& inError, - AudioPluginFormat::InstantiationCompletionCallback* inCallback) - : error (inError), callback (inCallback) - { - } - - void messageCallback() override { callback->completionCallback (nullptr, error); } - - String error; - ScopedPointer callback; - }; - - struct ErrorLambdaOnMessageThread : public CallbackMessage - { - ErrorLambdaOnMessageThread (const String& inError, - std::function f) - : error (inError), lambda (f) - { - } - - void messageCallback() override { lambda (nullptr, error); } - - String error; - std::function lambda; - }; -} - -AudioPluginFormatManager::AudioPluginFormatManager() {} -AudioPluginFormatManager::~AudioPluginFormatManager() {} - -//============================================================================== -void AudioPluginFormatManager::addDefaultFormats() -{ - #if JUCE_DEBUG - // you should only call this method once! - for (int i = formats.size(); --i >= 0;) - { - #if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_IOS) - jassert (dynamic_cast (formats[i]) == nullptr); - #endif - - #if JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS) - jassert (dynamic_cast (formats[i]) == nullptr); - #endif - - #if JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS) - jassert (dynamic_cast (formats[i]) == nullptr); - #endif - - #if JUCE_PLUGINHOST_LADSPA && JUCE_LINUX - jassert (dynamic_cast (formats[i]) == nullptr); - #endif - } - #endif - - #if JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS) - formats.add (new AudioUnitPluginFormat()); - #endif - - #if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_IOS) - formats.add (new VSTPluginFormat()); - #endif - - #if JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS) - formats.add (new VST3PluginFormat()); - #endif - - #if JUCE_PLUGINHOST_LADSPA && JUCE_LINUX - formats.add (new LADSPAPluginFormat()); - #endif -} - -int AudioPluginFormatManager::getNumFormats() -{ - return formats.size(); -} - -AudioPluginFormat* AudioPluginFormatManager::getFormat (const int index) -{ - return formats [index]; -} - -void AudioPluginFormatManager::addFormat (AudioPluginFormat* const format) -{ - formats.add (format); -} - -AudioPluginInstance* AudioPluginFormatManager::createPluginInstance (const PluginDescription& description, double rate, - int blockSize, String& errorMessage) const -{ - if (AudioPluginFormat* format = findFormatForDescription (description, errorMessage)) - return format->createInstanceFromDescription (description, rate, blockSize, errorMessage); - - return nullptr; -} - -void AudioPluginFormatManager::createPluginInstanceAsync (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - AudioPluginFormat::InstantiationCompletionCallback* callback) -{ - String error; - - if (AudioPluginFormat* format = findFormatForDescription (description, error)) - return format->createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, callback); - - (new PluginFormatManagerHelpers::ErrorCallbackOnMessageThread (error, callback))->post(); -} - -void AudioPluginFormatManager::createPluginInstanceAsync (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - std::function f) -{ - String error; - - if (AudioPluginFormat* format = findFormatForDescription (description, error)) - return format->createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, f); - - (new PluginFormatManagerHelpers::ErrorLambdaOnMessageThread (error, f))->post(); -} - -AudioPluginFormat* AudioPluginFormatManager::findFormatForDescription (const PluginDescription& description, String& errorMessage) const -{ - errorMessage = String(); - - for (int i = 0; i < formats.size(); ++i) - { - AudioPluginFormat* format; - - if ((format = formats.getUnchecked (i))->getName() == description.pluginFormatName - && format->fileMightContainThisPluginType (description.fileOrIdentifier)) - return format; - } - - errorMessage = NEEDS_TRANS ("No compatible plug-in format exists for this plug-in"); - - return nullptr; -} - -bool AudioPluginFormatManager::doesPluginStillExist (const PluginDescription& description) const -{ - for (int i = 0; i < formats.size(); ++i) - if (formats.getUnchecked(i)->getName() == description.pluginFormatName) - return formats.getUnchecked(i)->doesPluginStillExist (description); - - return false; -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h b/source/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h deleted file mode 100644 index 495c22291..000000000 --- a/source/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - This maintains a list of known AudioPluginFormats. - - @see AudioPluginFormat -*/ -class JUCE_API AudioPluginFormatManager -{ -public: - //============================================================================== - AudioPluginFormatManager(); - - /** Destructor. */ - ~AudioPluginFormatManager(); - - //============================================================================== - /** Adds any formats that it knows about, e.g. VST. - */ - void addDefaultFormats(); - - //============================================================================== - /** Returns the number of types of format that are available. - - Use getFormat() to get one of them. - */ - int getNumFormats(); - - /** Returns one of the available formats. - - @see getNumFormats - */ - AudioPluginFormat* getFormat (int index); - - //============================================================================== - /** Adds a format to the list. - - The object passed in will be owned and deleted by the manager. - */ - void addFormat (AudioPluginFormat* format); - - - //============================================================================== - /** Tries to load the type for this description, by trying all the formats - that this manager knows about. - - The caller is responsible for deleting the object that is returned. - - If it can't load the plugin, it returns nullptr and leaves a message in the - errorMessage string. - - If you intend to instantiate a AudioUnit v3 plug-in then you must either - use the non-blocking asynchrous version below - or call this method from a - thread other than the message thread and without blocking the message - thread. - */ - AudioPluginInstance* createPluginInstance (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - String& errorMessage) const; - - /** Tries to asynchronously load the type for this description, by trying - all the formats that this manager knows about. - - The caller must supply a callback object which will be called when - the instantantiation has completed. - - If it can't load the plugin then the callback function will be called - passing a nullptr as the instance argument along with an error message. - - The callback function will be called on the message thread so the caller - must not block the message thread. - - The callback object will be deleted automatically after it has been - invoked. - - The caller is responsible for deleting the instance that is passed to - the callback function. - - If you intend to instantiate a AudioUnit v3 plug-in then you must use - this non-blocking asynchrous version - or call the synchrous method - from an auxiliary thread. - */ - void createPluginInstanceAsync (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - AudioPluginFormat::InstantiationCompletionCallback* callback); - - void createPluginInstanceAsync (const PluginDescription& description, - double initialSampleRate, - int initialBufferSize, - std::function completionCallback); - - /** Checks that the file or component for this plugin actually still exists. - - (This won't try to load the plugin) - */ - bool doesPluginStillExist (const PluginDescription& description) const; - -private: - //============================================================================== - //@internal - AudioPluginFormat* findFormatForDescription (const PluginDescription&, String& errorMessage) const; - - OwnedArray formats; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/format_types/juce_AU_Shared.h b/source/modules/juce_audio_processors/format_types/juce_AU_Shared.h deleted file mode 100644 index 434326ff2..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_AU_Shared.h +++ /dev/null @@ -1,535 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -// This macro can be set if you need to override this internal name for some reason.. -#ifndef JUCE_STATE_DICTIONARY_KEY - #define JUCE_STATE_DICTIONARY_KEY "jucePluginState" -#endif - -namespace juce -{ - -struct AudioUnitHelpers -{ - class ChannelRemapper - { - public: - ChannelRemapper (AudioProcessor& p) : processor (p), inputLayoutMap (nullptr), outputLayoutMap (nullptr) {} - ~ChannelRemapper() {} - - void alloc() - { - const int numInputBuses = AudioUnitHelpers::getBusCount (&processor, true); - const int numOutputBuses = AudioUnitHelpers::getBusCount (&processor, false); - - initializeChannelMapArray (true, numInputBuses); - initializeChannelMapArray (false, numOutputBuses); - - for (int busIdx = 0; busIdx < numInputBuses; ++busIdx) - fillLayoutChannelMaps (true, busIdx); - - for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx) - fillLayoutChannelMaps (false, busIdx); - } - - void release() - { - inputLayoutMap = outputLayoutMap = nullptr; - inputLayoutMapPtrStorage.free(); - outputLayoutMapPtrStorage.free(); - inputLayoutMapStorage.free(); - outputLayoutMapStorage.free(); - } - - inline const int* get (bool input, int bus) const noexcept { return (input ? inputLayoutMap : outputLayoutMap) [bus]; } - - private: - //============================================================================== - AudioProcessor& processor; - HeapBlock inputLayoutMapPtrStorage, outputLayoutMapPtrStorage; - HeapBlock inputLayoutMapStorage, outputLayoutMapStorage; - int** inputLayoutMap; - int** outputLayoutMap; - - //============================================================================== - void initializeChannelMapArray (bool isInput, const int numBuses) - { - HeapBlock& layoutMapPtrStorage = isInput ? inputLayoutMapPtrStorage : outputLayoutMapPtrStorage; - HeapBlock& layoutMapStorage = isInput ? inputLayoutMapStorage : outputLayoutMapStorage; - int**& layoutMap = isInput ? inputLayoutMap : outputLayoutMap; - - const int totalInChannels = processor.getTotalNumInputChannels(); - const int totalOutChannels = processor.getTotalNumOutputChannels(); - - layoutMapPtrStorage.calloc (static_cast (numBuses)); - layoutMapStorage.calloc (static_cast (isInput ? totalInChannels : totalOutChannels)); - - layoutMap = layoutMapPtrStorage. get(); - - int ch = 0; - for (int busIdx = 0; busIdx < numBuses; ++busIdx) - { - layoutMap[busIdx] = layoutMapStorage.get() + ch; - ch += processor.getChannelCountOfBus (isInput, busIdx); - } - } - - void fillLayoutChannelMaps (bool isInput, int busNr) - { - int* layoutMap = (isInput ? inputLayoutMap : outputLayoutMap)[busNr]; - auto channelFormat = processor.getChannelLayoutOfBus (isInput, busNr); - AudioChannelLayout coreAudioLayout; - - zerostruct (coreAudioLayout); - coreAudioLayout.mChannelLayoutTag = CoreAudioLayouts::toCoreAudio (channelFormat); - - const int numChannels = channelFormat.size(); - auto coreAudioChannels = CoreAudioLayouts::getCoreAudioLayoutChannels (coreAudioLayout); - - for (int i = 0; i < numChannels; ++i) - layoutMap[i] = coreAudioChannels.indexOf (channelFormat.getTypeOfChannel (i)); - } - }; - - //============================================================================== - class CoreAudioBufferList - { - public: - CoreAudioBufferList() { reset(); } - - //============================================================================== - void prepare (int inChannels, int outChannels, int maxFrames) - { - const int numChannels = jmax (inChannels, outChannels); - - scratch.setSize (numChannels, maxFrames); - channels.calloc (static_cast (numChannels)); - - reset(); - } - - void release() - { - scratch.setSize (0, 0); - channels.free(); - } - - void reset() noexcept - { - pushIdx = 0; - popIdx = 0; - zeromem (channels.get(), sizeof(float*) * static_cast (scratch.getNumChannels())); - } - - //============================================================================== - float* setBuffer (const int idx, float* ptr = nullptr) noexcept - { - jassert (idx < scratch.getNumChannels()); - return (channels [idx] = uniqueBuffer (idx, ptr)); - } - - //============================================================================== - float* push() noexcept - { - jassert (pushIdx < scratch.getNumChannels()); - return channels [pushIdx++]; - } - - void push (AudioBufferList& bufferList, const int* channelMap) noexcept - { - jassert (pushIdx < scratch.getNumChannels()); - - if (bufferList.mNumberBuffers > 0) - { - const UInt32 n = bufferList.mBuffers [0].mDataByteSize / - (bufferList.mBuffers [0].mNumberChannels * sizeof (float)); - const bool isInterleaved = isAudioBufferInterleaved (bufferList); - const int numChannels = static_cast (isInterleaved ? bufferList.mBuffers [0].mNumberChannels - : bufferList.mNumberBuffers); - - for (int ch = 0; ch < numChannels; ++ch) - { - float* data = push(); - - int mappedChannel = channelMap [ch]; - if (isInterleaved || static_cast (bufferList.mBuffers [mappedChannel].mData) != data) - copyAudioBuffer (bufferList, mappedChannel, n, data); - } - } - } - - //============================================================================== - float* pop() noexcept - { - jassert (popIdx < scratch.getNumChannels()); - return channels[popIdx++]; - } - - void pop (AudioBufferList& buffer, const int* channelMap) noexcept - { - if (buffer.mNumberBuffers > 0) - { - const UInt32 n = buffer.mBuffers [0].mDataByteSize / (buffer.mBuffers [0].mNumberChannels * sizeof (float)); - const bool isInterleaved = isAudioBufferInterleaved (buffer); - const int numChannels = static_cast (isInterleaved ? buffer.mBuffers [0].mNumberChannels : buffer.mNumberBuffers); - - for (int ch = 0; ch < numChannels; ++ch) - { - int mappedChannel = channelMap [ch]; - float* nextBuffer = pop(); - - if (nextBuffer == buffer.mBuffers [mappedChannel].mData && ! isInterleaved) - continue; // no copying necessary - - if (buffer.mBuffers [mappedChannel].mData == nullptr && ! isInterleaved) - buffer.mBuffers [mappedChannel].mData = nextBuffer; - else - copyAudioBuffer (nextBuffer, mappedChannel, n, buffer); - } - } - } - - //============================================================================== - AudioSampleBuffer& getBuffer (UInt32 frames) noexcept - { - jassert (pushIdx == scratch.getNumChannels()); - - #if JUCE_DEBUG - for (int i = 0; i < pushIdx; ++i) - jassert (channels [i] != nullptr); - #endif - - mutableBuffer.setDataToReferTo (channels, pushIdx, static_cast (frames)); - return mutableBuffer; - } - - private: - float* uniqueBuffer (int idx, float* buffer) noexcept - { - if (buffer == nullptr) - return scratch.getWritePointer (idx); - - for (int ch = 0; ch < idx; ++ch) - if (buffer == channels[ch]) - return scratch.getWritePointer (idx); - - return buffer; - } - - //============================================================================== - AudioSampleBuffer scratch; - AudioSampleBuffer mutableBuffer; - - HeapBlock channels; - int pushIdx, popIdx; - }; - - static bool isAudioBufferInterleaved (const AudioBufferList& audioBuffer) noexcept - { - return (audioBuffer.mNumberBuffers == 1 && audioBuffer.mBuffers[0].mNumberChannels > 1); - } - - static void clearAudioBuffer (const AudioBufferList& audioBuffer) noexcept - { - for (unsigned int ch = 0; ch < audioBuffer.mNumberBuffers; ++ch) - zeromem (audioBuffer.mBuffers[ch].mData, audioBuffer.mBuffers[ch].mDataByteSize); - } - - static void copyAudioBuffer (const AudioBufferList& audioBuffer, const int channel, const UInt32 size, float* dst) noexcept - { - if (! isAudioBufferInterleaved (audioBuffer)) - { - jassert (channel < static_cast (audioBuffer.mNumberBuffers)); - jassert (audioBuffer.mBuffers[channel].mDataByteSize == (size * sizeof (float))); - - memcpy (dst, audioBuffer.mBuffers[channel].mData, size * sizeof (float)); - } - else - { - const int numChannels = static_cast (audioBuffer.mBuffers[0].mNumberChannels); - const UInt32 n = static_cast (numChannels) * size; - const float* src = static_cast (audioBuffer.mBuffers[0].mData); - - jassert (channel < numChannels); - jassert (audioBuffer.mBuffers[0].mDataByteSize == (n * sizeof (float))); - - for (const float* inData = src; inData < (src + n); inData += numChannels) - *dst++ = inData[channel]; - } - } - - static void copyAudioBuffer (const float *src, const int channel, const UInt32 size, AudioBufferList& audioBuffer) noexcept - { - if (! isAudioBufferInterleaved (audioBuffer)) - { - jassert (channel < static_cast (audioBuffer.mNumberBuffers)); - jassert (audioBuffer.mBuffers[channel].mDataByteSize == (size * sizeof (float))); - - memcpy (audioBuffer.mBuffers[channel].mData, src, size * sizeof (float)); - } - else - { - const int numChannels = static_cast (audioBuffer.mBuffers[0].mNumberChannels); - const UInt32 n = static_cast (numChannels) * size; - float* dst = static_cast (audioBuffer.mBuffers[0].mData); - - jassert (channel < numChannels); - jassert (audioBuffer.mBuffers[0].mDataByteSize == (n * sizeof (float))); - - for (float* outData = dst; outData < (dst + n); outData += numChannels) - outData[channel] = *src++; - } - } - - template - static bool isLayoutSupported (const AudioProcessor& processor, - bool isInput, int busIdx, - int numChannels, - const short (&channelLayoutList) [numLayouts][2], - bool hasLayoutMap = true) - { - if (const AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx)) - { - if (! bus->isNumberOfChannelsSupported (numChannels)) - return false; - - if (! hasLayoutMap) - return true; - - const int numConfigs = sizeof (channelLayoutList) / sizeof (short[2]); - - for (int i = 0; i < numConfigs; ++i) - { - if (channelLayoutList[i][isInput ? 0 : 1] == numChannels) - return true; - } - } - - return false; - } - - static Array getAUChannelInfo (const AudioProcessor& processor) - { - Array channelInfo; - - auto hasMainInputBus = (AudioUnitHelpers::getBusCount (&processor, true) > 0); - auto hasMainOutputBus = (AudioUnitHelpers::getBusCount (&processor, false) > 0); - - if ((! hasMainInputBus) && (! hasMainOutputBus)) - { - // midi effect plug-in: no audio - AUChannelInfo info; - info.inChannels = 0; - info.outChannels = 0; - - return { &info, 1 }; - } - - auto layout = processor.getBusesLayout(); - auto maxNumChanToCheckFor = 9; - - auto defaultInputs = processor.getChannelCountOfBus (true, 0); - auto defaultOutputs = processor.getChannelCountOfBus (false, 0); - - SortedSet supportedChannels; - - // add the current configuration - if (defaultInputs != 0 || defaultOutputs != 0) - supportedChannels.add ((defaultInputs << 16) | defaultOutputs); - - for (auto inChanNum = hasMainInputBus ? 1 : 0; inChanNum <= (hasMainInputBus ? maxNumChanToCheckFor : 0); ++inChanNum) - { - auto inLayout = layout; - - if (auto* inBus = processor.getBus (true, 0)) - if (! isNumberOfChannelsSupported (inBus, inChanNum, inLayout)) - continue; - - for (auto outChanNum = hasMainOutputBus ? 1 : 0; outChanNum <= (hasMainOutputBus ? maxNumChanToCheckFor : 0); ++outChanNum) - { - auto outLayout = inLayout; - - if (auto* outBus = processor.getBus (false, 0)) - if (! isNumberOfChannelsSupported (outBus, outChanNum, outLayout)) - continue; - - supportedChannels.add (((hasMainInputBus ? outLayout.getMainInputChannels() : 0) << 16) - | (hasMainOutputBus ? outLayout.getMainOutputChannels() : 0)); - } - } - - auto hasInOutMismatch = false; - - for (auto supported : supportedChannels) - { - auto numInputs = (supported >> 16) & 0xffff; - auto numOutputs = (supported >> 0) & 0xffff; - - if (numInputs != numOutputs) - { - hasInOutMismatch = true; - break; - } - } - - auto hasUnsupportedInput = ! hasMainInputBus, hasUnsupportedOutput = ! hasMainOutputBus; - - for (auto inChanNum = hasMainInputBus ? 1 : 0; inChanNum <= (hasMainInputBus ? maxNumChanToCheckFor : 0); ++inChanNum) - { - auto channelConfiguration = (inChanNum << 16) | (hasInOutMismatch ? defaultOutputs : inChanNum); - - if (! supportedChannels.contains (channelConfiguration)) - { - hasUnsupportedInput = true; - break; - } - } - - for (auto outChanNum = hasMainOutputBus ? 1 : 0; outChanNum <= (hasMainOutputBus ? maxNumChanToCheckFor : 0); ++outChanNum) - { - auto channelConfiguration = ((hasInOutMismatch ? defaultInputs : outChanNum) << 16) | outChanNum; - - if (! supportedChannels.contains (channelConfiguration)) - { - hasUnsupportedOutput = true; - break; - } - } - - for (auto supported : supportedChannels) - { - auto numInputs = (supported >> 16) & 0xffff; - auto numOutputs = (supported >> 0) & 0xffff; - - AUChannelInfo info; - - // see here: https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html - info.inChannels = static_cast (hasMainInputBus ? (hasUnsupportedInput ? numInputs : (hasInOutMismatch && (! hasUnsupportedOutput) ? -2 : -1)) : 0); - info.outChannels = static_cast (hasMainOutputBus ? (hasUnsupportedOutput ? numOutputs : (hasInOutMismatch && (! hasUnsupportedInput) ? -2 : -1)) : 0); - - if (info.inChannels == -2 && info.outChannels == -2) - info.inChannels = -1; - - int j; - for (j = 0; j < channelInfo.size(); ++j) - if (info.inChannels == channelInfo.getReference (j).inChannels - && info.outChannels == channelInfo.getReference (j).outChannels) - break; - - if (j >= channelInfo.size()) - channelInfo.add (info); - } - - return channelInfo; - } - - static bool isNumberOfChannelsSupported (const AudioProcessor::Bus* b, int numChannels, AudioProcessor::BusesLayout& inOutCurrentLayout) - { - auto potentialSets = AudioChannelSet::channelSetsWithNumberOfChannels (static_cast (numChannels)); - - for (auto set : potentialSets) - { - auto copy = inOutCurrentLayout; - - if (b->isLayoutSupported (set, ©)) - { - inOutCurrentLayout = copy; - return true; - } - } - - return false; - } - - //============================================================================== - static int getBusCount (const AudioProcessor* juceFilter, bool isInput) - { - int busCount = juceFilter->getBusCount (isInput); - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - const int numConfigs = sizeof (configs) / sizeof (short[2]); - - bool hasOnlyZeroChannels = true; - - for (int i = 0; i < numConfigs && hasOnlyZeroChannels == true; ++i) - if (configs[i][isInput ? 0 : 1] != 0) - hasOnlyZeroChannels = false; - - busCount = jmin (busCount, hasOnlyZeroChannels ? 0 : 1); - #endif - - return busCount; - } - - static bool setBusesLayout (AudioProcessor* juceFilter, const AudioProcessor::BusesLayout& requestedLayouts) - { - #ifdef JucePlugin_PreferredChannelConfigurations - AudioProcessor::BusesLayout copy (requestedLayouts); - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - - const int actualBuses = juceFilter->getBusCount (isInput); - const int auNumBuses = getBusCount (juceFilter, isInput); - Array& buses = (isInput ? copy.inputBuses : copy.outputBuses); - - for (int i = auNumBuses; i < actualBuses; ++i) - buses.add (AudioChannelSet::disabled()); - } - - return juceFilter->setBusesLayout (copy); - #else - return juceFilter->setBusesLayout (requestedLayouts); - #endif - } - - static AudioProcessor::BusesLayout getBusesLayout (const AudioProcessor* juceFilter) - { - #ifdef JucePlugin_PreferredChannelConfigurations - AudioProcessor::BusesLayout layout = juceFilter->getBusesLayout(); - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - - const int actualBuses = juceFilter->getBusCount (isInput); - const int auNumBuses = getBusCount (juceFilter, isInput); - auto& buses = (isInput ? layout.inputBuses : layout.outputBuses); - - for (int i = auNumBuses; i < actualBuses; ++i) - buses.removeLast(); - } - - return layout; - #else - return juceFilter->getBusesLayout(); - #endif - } -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h b/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h deleted file mode 100644 index a4d0e1b16..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -#if (JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS)) || DOXYGEN - -//============================================================================== -/** - Implements a plugin format manager for AudioUnits. -*/ -class JUCE_API AudioUnitPluginFormat : public AudioPluginFormat -{ -public: - //============================================================================== - AudioUnitPluginFormat(); - ~AudioUnitPluginFormat(); - - //============================================================================== - String getName() const override { return "AudioUnit"; } - void findAllTypesForFile (OwnedArray&, const String& fileOrIdentifier) override; - bool fileMightContainThisPluginType (const String& fileOrIdentifier) override; - String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override; - bool pluginNeedsRescanning (const PluginDescription&) override; - StringArray searchPathsForPlugins (const FileSearchPath&, bool recursive, bool) override; - bool doesPluginStillExist (const PluginDescription&) override; - FileSearchPath getDefaultLocationsToSearch() override; - bool canScanForPlugins() const override { return true; } - -private: - //============================================================================== - void createPluginInstance (const PluginDescription&, - double initialSampleRate, - int initialBufferSize, - void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) override; - - bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioUnitPluginFormat) -}; - -#endif - -//============================================================================== -#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 -enum -{ - /** Custom AudioUnit property used to indicate MPE support */ - kAudioUnitProperty_SupportsMPE = 58 -}; -#endif - -} diff --git a/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm deleted file mode 100644 index 65b364950..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ /dev/null @@ -1,2463 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -#if JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS) - -#if JUCE_MAC -#include -#include -#include -#endif - -#include - -#if JUCE_SUPPORT_CARBON - #include -#endif - -#ifndef JUCE_SUPPORTS_AUv3 - #if JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES && __OBJC2__ \ - && ((defined (MAC_OS_X_VERSION_MIN_REQUIRED) && defined (MAC_OS_X_VERSION_10_11) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)) \ - || (defined (__IPHONE_OS_VERSION_MIN_REQUIRED) && defined (__IPHONE_9_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0))) - #define JUCE_SUPPORTS_AUv3 1 - #else - #define JUCE_SUPPORTS_AUv3 0 - #endif -#endif - -#if JUCE_SUPPORTS_AUv3 - #include -#endif - -#include "../../juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" -#include "../../juce_audio_devices/native/juce_MidiDataConcatenator.h" -#include "juce_AU_Shared.h" - -namespace juce -{ - -// Change this to disable logging of various activities -#ifndef AU_LOGGING - #define AU_LOGGING 1 -#endif - -#if AU_LOGGING - #define JUCE_AU_LOG(a) Logger::writeToLog(a); -#else - #define JUCE_AU_LOG(a) -#endif - -namespace AudioUnitFormatHelpers -{ - #if JUCE_DEBUG - static ThreadLocalValue insideCallback; - #endif - - String osTypeToString (OSType type) noexcept - { - const juce_wchar s[4] = { (juce_wchar) ((type >> 24) & 0xff), - (juce_wchar) ((type >> 16) & 0xff), - (juce_wchar) ((type >> 8) & 0xff), - (juce_wchar) (type & 0xff) }; - return String (s, 4); - } - - OSType stringToOSType (String s) - { - if (s.trim().length() >= 4) // (to avoid trimming leading spaces) - s = s.trim(); - - s += " "; - - return (((OSType) (unsigned char) s[0]) << 24) - | (((OSType) (unsigned char) s[1]) << 16) - | (((OSType) (unsigned char) s[2]) << 8) - | ((OSType) (unsigned char) s[3]); - } - - static const char* auIdentifierPrefix = "AudioUnit:"; - - String createPluginIdentifier (const AudioComponentDescription& desc) - { - String s (auIdentifierPrefix); - - if (desc.componentType == kAudioUnitType_MusicDevice) - s << "Synths/"; - else if (desc.componentType == kAudioUnitType_MusicEffect - || desc.componentType == kAudioUnitType_Effect) - s << "Effects/"; - else if (desc.componentType == kAudioUnitType_Generator) - s << "Generators/"; - else if (desc.componentType == kAudioUnitType_Panner) - s << "Panners/"; - else if (desc.componentType == kAudioUnitType_Mixer) - s << "Mixers/"; - - s << osTypeToString (desc.componentType) << "," - << osTypeToString (desc.componentSubType) << "," - << osTypeToString (desc.componentManufacturer); - - return s; - } - - void getNameAndManufacturer (AudioComponent comp, String& name, String& manufacturer) - { - CFStringRef cfName; - if (AudioComponentCopyName (comp, &cfName) == noErr) - { - name = String::fromCFString (cfName); - CFRelease (cfName); - } - - if (name.containsChar (':')) - { - manufacturer = name.upToFirstOccurrenceOf (":", false, false).trim(); - name = name.fromFirstOccurrenceOf (":", false, false).trim(); - } - - if (name.isEmpty()) - name = ""; - } - - bool getComponentDescFromIdentifier (const String& fileOrIdentifier, AudioComponentDescription& desc, - String& name, String& version, String& manufacturer) - { - if (fileOrIdentifier.startsWithIgnoreCase (auIdentifierPrefix)) - { - String s (fileOrIdentifier.substring (jmax (fileOrIdentifier.lastIndexOfChar (':'), - fileOrIdentifier.lastIndexOfChar ('/')) + 1)); - - StringArray tokens; - tokens.addTokens (s, ",", StringRef()); - tokens.removeEmptyStrings(); - - if (tokens.size() == 3) - { - zerostruct (desc); - desc.componentType = stringToOSType (tokens[0]); - desc.componentSubType = stringToOSType (tokens[1]); - desc.componentManufacturer = stringToOSType (tokens[2]); - - if (AudioComponent comp = AudioComponentFindNext (0, &desc)) - { - getNameAndManufacturer (comp, name, manufacturer); - - if (manufacturer.isEmpty()) - manufacturer = tokens[2]; - - if (version.isEmpty()) - { - UInt32 versionNum; - - if (AudioComponentGetVersion (comp, &versionNum) == noErr) - { - version << (int) (versionNum >> 16) << "." - << (int) ((versionNum >> 8) & 0xff) << "." - << (int) (versionNum & 0xff); - } - } - - return true; - } - } - } - - return false; - } - - bool getComponentDescFromFile (const String& fileOrIdentifier, AudioComponentDescription& desc, - String& name, String& version, String& manufacturer) - { - zerostruct (desc); - - #if JUCE_IOS - ignoreUnused (fileOrIdentifier, name, version, manufacturer); - - return false; - #else - const File file (fileOrIdentifier); - if (! file.hasFileExtension (".component") && ! file.hasFileExtension (".appex")) - return false; - - const char* const utf8 = fileOrIdentifier.toUTF8(); - - if (CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, - (CFIndex) strlen (utf8), file.isDirectory())) - { - CFBundleRef bundleRef = CFBundleCreate (kCFAllocatorDefault, url); - CFRelease (url); - - if (bundleRef != 0) - { - CFTypeRef bundleName = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleName")); - - if (bundleName != 0 && CFGetTypeID (bundleName) == CFStringGetTypeID()) - name = String::fromCFString ((CFStringRef) bundleName); - - if (name.isEmpty()) - name = file.getFileNameWithoutExtension(); - - CFTypeRef versionString = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleVersion")); - - if (versionString != 0 && CFGetTypeID (versionString) == CFStringGetTypeID()) - version = String::fromCFString ((CFStringRef) versionString); - - CFTypeRef manuString = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleGetInfoString")); - - if (manuString != 0 && CFGetTypeID (manuString) == CFStringGetTypeID()) - manufacturer = String::fromCFString ((CFStringRef) manuString); - - const ResFileRefNum resFileId = CFBundleOpenBundleResourceMap (bundleRef); - UseResFile (resFileId); - - const OSType thngType = stringToOSType ("thng"); - - for (ResourceIndex i = 1; i <= Count1Resources (thngType); ++i) - { - if (Handle h = Get1IndResource (thngType, i)) - { - HLock (h); - const uint32* const types = (const uint32*) *h; - - if (types[0] == kAudioUnitType_MusicDevice - || types[0] == kAudioUnitType_MusicEffect - || types[0] == kAudioUnitType_Effect - || types[0] == kAudioUnitType_Generator - || types[0] == kAudioUnitType_Panner - || types[0] == kAudioUnitType_Mixer) - { - desc.componentType = types[0]; - desc.componentSubType = types[1]; - desc.componentManufacturer = types[2]; - - if (AudioComponent comp = AudioComponentFindNext (0, &desc)) - getNameAndManufacturer (comp, name, manufacturer); - - break; - } - - HUnlock (h); - ReleaseResource (h); - } - } - - CFBundleCloseBundleResourceMap (bundleRef, resFileId); - CFRelease (bundleRef); - } - } - - return desc.componentType != 0 && desc.componentSubType != 0; - #endif - } - - const char* getCategory (OSType type) noexcept - { - switch (type) - { - case kAudioUnitType_Effect: - case kAudioUnitType_MusicEffect: return "Effect"; - case kAudioUnitType_MusicDevice: return "Synth"; - case kAudioUnitType_Generator: return "Generator"; - case kAudioUnitType_Panner: return "Panner"; - case kAudioUnitType_Mixer: return "Mixer"; - default: break; - } - - return nullptr; - } -} - -//============================================================================== -class AudioUnitPluginWindowCarbon; -class AudioUnitPluginWindowCocoa; - -//============================================================================== -class AudioUnitPluginInstance : public AudioPluginInstance -{ -public: - AudioUnitPluginInstance (AudioComponentInstance au) - : AudioPluginInstance (getBusesProperties (au)), - auComponent (AudioComponentInstanceGetComponent (au)), - wantsMidiMessages (false), - producesMidiMessages (false), - wasPlaying (false), - prepared (false), - isAUv3 (false), - currentBuffer (nullptr), - audioUnit (au), - #if JUCE_MAC - eventListenerRef (0), - #endif - midiConcatenator (2048) - { - using namespace AudioUnitFormatHelpers; - - AudioComponentGetDescription (auComponent, &componentDesc); - - #if JUCE_SUPPORTS_AUv3 - isAUv3 = ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0); - #endif - - wantsMidiMessages = componentDesc.componentType == kAudioUnitType_MusicDevice - || componentDesc.componentType == kAudioUnitType_MusicEffect; - - AudioComponentDescription ignore; - getComponentDescFromIdentifier (createPluginIdentifier (componentDesc), ignore, pluginName, version, manufacturer); - updateSupportedLayouts(); - } - - ~AudioUnitPluginInstance() - { - const ScopedLock sl (lock); - - #if JUCE_DEBUG - // this indicates that some kind of recursive call is getting triggered that's - // deleting this plugin while it's still under construction. - jassert (AudioUnitFormatHelpers::insideCallback.get() == 0); - #endif - - if (audioUnit != nullptr) - { - struct AUDeleter : public CallbackMessage - { - AUDeleter (AudioUnitPluginInstance& inInstance, WaitableEvent& inEvent) - : auInstance (inInstance), completionSignal (inEvent) - {} - - void messageCallback() override - { - auInstance.cleanup(); - completionSignal.signal(); - } - - AudioUnitPluginInstance& auInstance; - WaitableEvent& completionSignal; - }; - - if (MessageManager::getInstance()->isThisTheMessageThread()) - { - cleanup(); - } - else - { - WaitableEvent completionEvent; - (new AUDeleter (*this, completionEvent))->post(); - completionEvent.wait(); - } - } - } - - // called from the destructer above - void cleanup() - { - #if JUCE_MAC - if (eventListenerRef != 0) - { - AUListenerDispose (eventListenerRef); - eventListenerRef = 0; - } - #endif - - if (prepared) - releaseResources(); - - AudioComponentInstanceDispose (audioUnit); - audioUnit = nullptr; - } - - bool initialise (double rate, int blockSize) - { - producesMidiMessages = canProduceMidiOutput(); - setRateAndBufferSizeDetails (rate, blockSize); - setLatencySamples (0); - refreshParameterList(); - createPluginCallbacks(); - - return true; - } - - //============================================================================== - bool canAddBus (bool isInput) const override { return isBusCountWritable (isInput); } - bool canRemoveBus (bool isInput) const override { return isBusCountWritable (isInput); } - - bool canApplyBusCountChange (bool isInput, bool isAdding, BusProperties& outProperties) override - { - int currentCount = getBusCount (isInput); - int newCount = currentCount + (isAdding ? 1 : -1); - AudioUnitScope scope = isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output; - - if (AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ElementCount, scope, 0, &newCount, sizeof (newCount)) == noErr) - { - getBusProperties (isInput, currentCount, outProperties.busName, outProperties.defaultLayout); - outProperties.isActivatedByDefault = true; - updateSupportedLayouts(); - - return true; - } - - return false; - } - - //============================================================================== - bool isBusesLayoutSupported (const BusesLayout& layouts) const override - { - if (layouts == getBusesLayout()) - return true; - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const Array& requestedLayouts = (isInput ? layouts.inputBuses : layouts.outputBuses); - const Array& oppositeRequestedLayouts = (isInput ? layouts.outputBuses : layouts.inputBuses); - const Array >& supported = (isInput ? supportedInLayouts : supportedOutLayouts); - const int n = getBusCount (isInput); - - for (int busIdx = 0; busIdx < n; ++busIdx) - { - const AudioChannelSet& requested = requestedLayouts.getReference (busIdx); - const int oppositeBusIdx = jmin (getBusCount (! isInput) - 1, busIdx); - const bool hasOppositeBus = (oppositeBusIdx >= 0); - const AudioChannelSet oppositeRequested = (hasOppositeBus ? oppositeRequestedLayouts.getReference (oppositeBusIdx) : AudioChannelSet()); - const Array& possible = supported.getReference (busIdx); - - if (requested.isDisabled()) - return false; - - if (possible.size() > 0 && ! possible.contains (requested)) - return false; - - int i; - for (i = 0; i < numChannelInfos; ++i) - { - const AUChannelInfo& info = channelInfos[i]; - const SInt16& thisChannels = (isInput ? info.inChannels : info.outChannels); - const SInt16& opChannels = (isInput ? info.outChannels : info.inChannels); - - // this bus - if (thisChannels == 0) continue; - else if (thisChannels > 0 && requested.size() != thisChannels) continue; - else if (thisChannels < -2 && requested.size() > (thisChannels * -1)) continue; - - // opposite bus - if (opChannels == 0 && hasOppositeBus) continue; - else if (opChannels > 0 && oppositeRequested.size() != opChannels) continue; - else if (opChannels < -2 && oppositeRequested.size() > (opChannels * -1)) continue; - - // both buses - if (thisChannels == -2 && opChannels == -2) continue; - if (thisChannels == -1 && opChannels == -1) - { - int numOppositeBuses = getBusCount (! isInput); - int j; - for (j = 0; j < numOppositeBuses; ++j) - if (requested.size() != oppositeRequestedLayouts.getReference (j).size()) - break; - - if (j < numOppositeBuses) continue; - } - - break; - } - - if (i >= numChannelInfos) - return false; - } - } - - return true; - } - - bool syncBusLayouts (const BusesLayout& layouts, bool isInitialized, bool& layoutHasChanged) const - { - layoutHasChanged = false; - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const AudioUnitScope scope = isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output; - const int n = getBusCount (isInput); - - if (getElementCount (scope) != n && isBusCountWritable (isInput)) - { - OSStatus err; - UInt32 newCount = static_cast (n); - layoutHasChanged = true; - - err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ElementCount, scope, 0, &newCount, sizeof (newCount)); - jassert (err == noErr); - } - - for (int i = 0; i < n; ++i) - { - Float64 sampleRate; - UInt32 sampleRateSize = sizeof (sampleRate); - - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SampleRate, scope, static_cast (i), &sampleRate, &sampleRateSize); - - const AudioChannelSet& set = layouts.getChannelSet (isInput, i); - const int requestedNumChannels = set.size(); - - { - AudioStreamBasicDescription stream; - UInt32 dataSize = sizeof (stream); - OSStatus err = AudioUnitGetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, static_cast (i), &stream, &dataSize); - if (err != noErr || dataSize < sizeof (stream)) - return false; - - const int actualNumChannels = static_cast (stream.mChannelsPerFrame); - - if (actualNumChannels != requestedNumChannels) - { - layoutHasChanged = true; - zerostruct (stream); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct) - stream.mSampleRate = sampleRate; - stream.mFormatID = kAudioFormatLinearPCM; - stream.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved | kAudioFormatFlagsNativeEndian; - stream.mFramesPerPacket = 1; - stream.mBytesPerPacket = 4; - stream.mBytesPerFrame = 4; - stream.mBitsPerChannel = 32; - stream.mChannelsPerFrame = static_cast (requestedNumChannels); - - err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, static_cast (i), &stream, sizeof (stream)); - if (err != noErr) return false; - } - } - - if (! set.isDiscreteLayout()) - { - const AudioChannelLayoutTag requestedTag = CoreAudioLayouts::toCoreAudio (set); - - AudioChannelLayout layout; - const UInt32 minDataSize = sizeof (layout) - sizeof (AudioChannelDescription); - UInt32 dataSize = minDataSize; - - AudioChannelLayoutTag actualTag = kAudioChannelLayoutTag_Unknown; - OSStatus err = AudioUnitGetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (i), &layout, &dataSize); - bool supportsLayouts = (err == noErr && dataSize >= minDataSize); - - if (supportsLayouts) - { - const UInt32 expectedSize = - minDataSize + (sizeof (AudioChannelDescription) * layout.mNumberChannelDescriptions); - - HeapBlock layoutBuffer; - layoutBuffer.malloc (1, expectedSize); - dataSize = expectedSize; - - err = AudioUnitGetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, - static_cast (i), layoutBuffer.get(), &dataSize); - - if (err != noErr || dataSize < expectedSize) - return false; - - // try to convert the layout into a tag - actualTag = CoreAudioLayouts::toCoreAudio (CoreAudioLayouts::fromCoreAudio (layout)); - } - - if (actualTag != requestedTag) - { - zerostruct (layout); - layout.mChannelLayoutTag = requestedTag; - - err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (i), &layout, minDataSize); - - // only bail out if the plug-in claims to support layouts - // See AudioUnit headers on kAudioUnitProperty_AudioChannelLayout - if (err != noErr && supportsLayouts && isInitialized) - return false; - } - } - } - } - - return true; - } - - bool canApplyBusesLayout (const BusesLayout& layouts) const override - { - // You cannot call setBusesLayout when the AudioProcessor is processing. - // Call releaseResources first! - jassert (! prepared); - - bool layoutHasChanged = false; - - if (! syncBusLayouts (layouts, false, layoutHasChanged)) - return false; - - // did anything actually change - if (layoutHasChanged) - { - bool success = (AudioUnitInitialize (audioUnit) == noErr); - - // Some plug-ins require the LayoutTag to be set after initialization - if (success) - success = syncBusLayouts (layouts, true, layoutHasChanged); - - AudioUnitUninitialize (audioUnit); - - if (! success) - // make sure that the layout is back to it's original state - syncBusLayouts (getBusesLayout(), false, layoutHasChanged); - - return success; - } - - return true; - } - - //============================================================================== - // AudioPluginInstance methods: - - void fillInPluginDescription (PluginDescription& desc) const override - { - desc.name = pluginName; - desc.descriptiveName = pluginName; - desc.fileOrIdentifier = AudioUnitFormatHelpers::createPluginIdentifier (componentDesc); - desc.uid = ((int) componentDesc.componentType) - ^ ((int) componentDesc.componentSubType) - ^ ((int) componentDesc.componentManufacturer); - desc.lastFileModTime = Time(); - desc.lastInfoUpdateTime = Time::getCurrentTime(); - desc.pluginFormatName = "AudioUnit"; - desc.category = AudioUnitFormatHelpers::getCategory (componentDesc.componentType); - desc.manufacturerName = manufacturer; - desc.version = version; - desc.numInputChannels = getTotalNumInputChannels(); - desc.numOutputChannels = getTotalNumOutputChannels(); - desc.isInstrument = (componentDesc.componentType == kAudioUnitType_MusicDevice); - } - - void* getPlatformSpecificData() override { return audioUnit; } - const String getName() const override { return pluginName; } - - double getTailLengthSeconds() const override - { - Float64 tail = 0; - UInt32 tailSize = sizeof (tail); - - if (audioUnit != nullptr) - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_TailTime, kAudioUnitScope_Global, - 0, &tail, &tailSize); - - return tail; - } - - bool acceptsMidi() const override { return wantsMidiMessages; } - bool producesMidi() const override { return producesMidiMessages; } - - //============================================================================== - // AudioProcessor methods: - - void prepareToPlay (double newSampleRate, int estimatedSamplesPerBlock) override - { - if (audioUnit != nullptr) - { - releaseResources(); - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const AudioUnitScope scope = isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output; - const int n = getBusCount (isInput); - - for (int i = 0; i < n; ++i) - { - Float64 sampleRate; - UInt32 sampleRateSize = sizeof (sampleRate); - const Float64 sr = newSampleRate; - - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SampleRate, scope, static_cast (i), &sampleRate, &sampleRateSize); - - if (sampleRate != sr) - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SampleRate, scope, static_cast (i), &sr, sizeof (sr)); - - if (isInput) - { - AURenderCallbackStruct info; - zerostruct (info); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct) - - info.inputProcRefCon = this; - info.inputProc = renderGetInputCallback; - - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, - static_cast (i), &info, sizeof (info)); - } - else - { - outputBufferList.add (new AUBuffer (static_cast (getChannelCountOfBus (false, i)))); - } - } - } - - UInt32 frameSize = (UInt32) estimatedSamplesPerBlock; - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, - &frameSize, sizeof (frameSize)); - - setRateAndBufferSizeDetails ((double) newSampleRate, estimatedSamplesPerBlock); - - updateLatency(); - - zerostruct (timeStamp); - timeStamp.mSampleTime = 0; - timeStamp.mHostTime = GetCurrentHostTime (0, newSampleRate, isAUv3); - timeStamp.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid; - - currentBuffer = nullptr; - wasPlaying = false; - - resetBuses(); - - bool ignore; - - if (! syncBusLayouts (getBusesLayout(), false, ignore)) - return; - - prepared = (AudioUnitInitialize (audioUnit) == noErr); - - if (prepared) - { - if (! syncBusLayouts (getBusesLayout(), true, ignore)) - { - prepared = false; - AudioUnitUninitialize (audioUnit); - } - } - } - } - - void releaseResources() override - { - if (prepared) - { - AudioUnitUninitialize (audioUnit); - resetBuses(); - AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0); - - outputBufferList.clear(); - currentBuffer = nullptr; - prepared = false; - } - - incomingMidi.clear(); - } - - void resetBuses() - { - for (int i = 0; i < getBusCount (true); ++i) AudioUnitReset (audioUnit, kAudioUnitScope_Input, static_cast (i)); - for (int i = 0; i < getBusCount (false); ++i) AudioUnitReset (audioUnit, kAudioUnitScope_Output, static_cast (i)); - } - - void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) override - { - const int numSamples = buffer.getNumSamples(); - - if (prepared) - { - timeStamp.mHostTime = GetCurrentHostTime (numSamples, getSampleRate(), isAUv3); - - int chIdx = 0; - const int numOutputBuses = getBusCount (false); - for (int i = 0; i < numOutputBuses; ++i) - { - if (AUBuffer* buf = outputBufferList[i]) - { - AudioBufferList& abl = *buf; - - for (AudioUnitElement j = 0; j < abl.mNumberBuffers; ++j) - { - abl.mBuffers[j].mNumberChannels = 1; - abl.mBuffers[j].mDataByteSize = (UInt32) (sizeof (float) * (size_t) numSamples); - abl.mBuffers[j].mData = buffer.getWritePointer (chIdx++); - } - } - } - - currentBuffer = &buffer; - - if (wantsMidiMessages) - { - const uint8* midiEventData; - int midiEventSize, midiEventPosition; - - for (MidiBuffer::Iterator i (midiMessages); i.getNextEvent (midiEventData, midiEventSize, midiEventPosition);) - { - if (midiEventSize <= 3) - MusicDeviceMIDIEvent (audioUnit, - midiEventData[0], midiEventData[1], midiEventData[2], - (UInt32) midiEventPosition); - else - MusicDeviceSysEx (audioUnit, midiEventData, (UInt32) midiEventSize); - } - - midiMessages.clear(); - } - - - for (int i = 0; i < numOutputBuses; ++i) - { - AudioUnitRenderActionFlags flags = 0; - - if (AUBuffer* buf = outputBufferList[i]) - AudioUnitRender (audioUnit, &flags, &timeStamp, static_cast (i), (UInt32) numSamples, buf->bufferList.get()); - } - - timeStamp.mSampleTime += numSamples; - } - else - { - // Plugin not working correctly, so just bypass.. - for (int i = getTotalNumOutputChannels(); --i >= 0;) - buffer.clear (i, 0, buffer.getNumSamples()); - } - - if (producesMidiMessages) - { - const ScopedLock sl (midiInLock); - midiMessages.swapWith (incomingMidi); - incomingMidi.clear(); - } - } - - //============================================================================== - bool hasEditor() const override { return true; } - AudioProcessorEditor* createEditor() override; - - static AudioProcessor::BusesProperties getBusesProperties (AudioComponentInstance comp) - { - AudioProcessor::BusesProperties busProperties; - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const int n = getElementCount (comp, isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output); - - for (int i = 0; i < n; ++i) - { - String busName; - AudioChannelSet currentLayout; - - getBusProperties (comp, isInput, i, busName, currentLayout); - jassert (! currentLayout.isDisabled()); - - busProperties.addBus (isInput, busName, currentLayout, true); - } - } - - return busProperties; - } - - //============================================================================== - const String getInputChannelName (int index) const override - { - if (isPositiveAndBelow (index, getTotalNumInputChannels())) - return "Input " + String (index + 1); - - return {}; - } - - const String getOutputChannelName (int index) const override - { - if (isPositiveAndBelow (index, getTotalNumOutputChannels())) - return "Output " + String (index + 1); - - return {}; - } - - bool isInputChannelStereoPair (int index) const override { return isPositiveAndBelow (index, getTotalNumInputChannels()); } - bool isOutputChannelStereoPair (int index) const override { return isPositiveAndBelow (index, getTotalNumOutputChannels()); } - - //============================================================================== - int getNumParameters() override { return parameters.size(); } - - float getParameter (int index) override - { - const ScopedLock sl (lock); - - AudioUnitParameterValue value = 0; - - if (audioUnit != nullptr) - { - if (const ParamInfo* p = parameters[index]) - { - AudioUnitGetParameter (audioUnit, - p->paramID, - kAudioUnitScope_Global, 0, - &value); - - value = (value - p->minValue) / (p->maxValue - p->minValue); - } - } - - return value; - } - - void setParameter (int index, float newValue) override - { - const ScopedLock sl (lock); - - if (audioUnit != nullptr) - { - if (const ParamInfo* p = parameters[index]) - { - AudioUnitSetParameter (audioUnit, p->paramID, kAudioUnitScope_Global, 0, - p->minValue + (p->maxValue - p->minValue) * newValue, 0); - - sendParameterChangeEvent (index); - } - } - } - - void sendParameterChangeEvent (int index) - { - #if JUCE_MAC - jassert (audioUnit != nullptr); - - const ParamInfo& p = *parameters.getUnchecked (index); - - AudioUnitEvent ev; - ev.mEventType = kAudioUnitEvent_ParameterValueChange; - ev.mArgument.mParameter.mAudioUnit = audioUnit; - ev.mArgument.mParameter.mParameterID = p.paramID; - ev.mArgument.mParameter.mScope = kAudioUnitScope_Global; - ev.mArgument.mParameter.mElement = 0; - - AUEventListenerNotify (nullptr, nullptr, &ev); - #else - ignoreUnused (index); - #endif - } - - void sendAllParametersChangedEvents() - { - #if JUCE_MAC - jassert (audioUnit != nullptr); - - AudioUnitParameter param; - param.mAudioUnit = audioUnit; - param.mParameterID = kAUParameterListener_AnyParameter; - - AUParameterListenerNotify (nullptr, nullptr, ¶m); - #endif - } - - const String getParameterName (int index) override - { - if (auto* p = parameters[index]) - return p->name; - - return {}; - } - - const String getParameterText (int index) override { return String (getParameter (index)); } - - int getParameterNumSteps (int index) override - { - if (auto* p = parameters[index]) - return p->numSteps; - - return AudioProcessor::getDefaultNumParameterSteps(); - } - - bool isParameterDiscrete (int index) const override - { - if (auto* p = parameters[index]) - return p->discrete; - - return false; - } - - bool isParameterAutomatable (int index) const override - { - if (auto* p = parameters[index]) - return p->automatable; - - return false; - } - - //============================================================================== - int getNumPrograms() override - { - CFArrayRef presets; - UInt32 sz = sizeof (CFArrayRef); - int num = 0; - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets, - kAudioUnitScope_Global, 0, &presets, &sz) == noErr) - { - num = (int) CFArrayGetCount (presets); - CFRelease (presets); - } - - return num; - } - - int getCurrentProgram() override - { - AUPreset current; - current.presetNumber = 0; - UInt32 sz = sizeof (AUPreset); - - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_PresentPreset, - kAudioUnitScope_Global, 0, ¤t, &sz); - - return current.presetNumber; - } - - void setCurrentProgram (int newIndex) override - { - AUPreset current; - current.presetNumber = newIndex; - current.presetName = CFSTR(""); - - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_PresentPreset, - kAudioUnitScope_Global, 0, ¤t, sizeof (AUPreset)); - - sendAllParametersChangedEvents(); - } - - const String getProgramName (int index) override - { - String s; - CFArrayRef presets; - UInt32 sz = sizeof (CFArrayRef); - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets, - kAudioUnitScope_Global, 0, &presets, &sz) == noErr) - { - for (CFIndex i = 0; i < CFArrayGetCount (presets); ++i) - { - if (const AUPreset* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, i)) - { - if (p->presetNumber == index) - { - s = String::fromCFString (p->presetName); - break; - } - } - } - - CFRelease (presets); - } - - return s; - } - - void changeProgramName (int /*index*/, const String& /*newName*/) override - { - jassertfalse; // xxx not implemented! - } - - //============================================================================== - void updateTrackProperties (const TrackProperties& properties) override - { - if (properties.name.isNotEmpty()) - { - CFStringRef contextName = properties.name.toCFString(); - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ContextName, kAudioUnitScope_Global, - 0, &contextName, sizeof (CFStringRef)); - - CFRelease (contextName); - } - } - - //============================================================================== - void getStateInformation (MemoryBlock& destData) override - { - getCurrentProgramStateInformation (destData); - } - - void getCurrentProgramStateInformation (MemoryBlock& destData) override - { - CFPropertyListRef propertyList = 0; - UInt32 sz = sizeof (CFPropertyListRef); - - if (AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_ClassInfo, - kAudioUnitScope_Global, - 0, &propertyList, &sz) == noErr) - { - CFWriteStreamRef stream = CFWriteStreamCreateWithAllocatedBuffers (kCFAllocatorDefault, kCFAllocatorDefault); - CFWriteStreamOpen (stream); - - CFIndex bytesWritten = CFPropertyListWriteToStream (propertyList, stream, kCFPropertyListBinaryFormat_v1_0, 0); - CFWriteStreamClose (stream); - - CFDataRef data = (CFDataRef) CFWriteStreamCopyProperty (stream, kCFStreamPropertyDataWritten); - - destData.setSize ((size_t) bytesWritten); - destData.copyFrom (CFDataGetBytePtr (data), 0, destData.getSize()); - CFRelease (data); - - CFRelease (stream); - CFRelease (propertyList); - } - } - - void setStateInformation (const void* data, int sizeInBytes) override - { - setCurrentProgramStateInformation (data, sizeInBytes); - } - - void setCurrentProgramStateInformation (const void* data, int sizeInBytes) override - { - CFReadStreamRef stream = CFReadStreamCreateWithBytesNoCopy (kCFAllocatorDefault, (const UInt8*) data, - sizeInBytes, kCFAllocatorNull); - CFReadStreamOpen (stream); - - CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0; - CFPropertyListRef propertyList = CFPropertyListCreateFromStream (kCFAllocatorDefault, stream, 0, - kCFPropertyListImmutable, &format, 0); - CFRelease (stream); - - if (propertyList != 0) - { - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, - 0, &propertyList, sizeof (propertyList)); - - sendAllParametersChangedEvents(); - - CFRelease (propertyList); - } - } - - void refreshParameterList() override - { - parameters.clear(); - paramIDToIndex.clear(); - - if (audioUnit != nullptr) - { - UInt32 paramListSize = 0; - AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, - 0, ¶mListSize, nullptr); - - if (paramListSize > 0) - { - const size_t numParams = paramListSize / sizeof (int); - - HeapBlock ids; - ids.calloc (numParams); - - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, - 0, ids, ¶mListSize); - - for (size_t i = 0; i < numParams; ++i) - { - AudioUnitParameterInfo info; - UInt32 sz = sizeof (info); - - if (AudioUnitGetProperty (audioUnit, - kAudioUnitProperty_ParameterInfo, - kAudioUnitScope_Global, - ids[i], &info, &sz) == noErr) - { - ParamInfo* const param = new ParamInfo(); - parameters.add (param); - param->paramID = ids[i]; - paramIDToIndex.getReference (ids[i]) = i; - param->minValue = info.minValue; - param->maxValue = info.maxValue; - param->automatable = (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0; - param->discrete = (info.unit == kAudioUnitParameterUnit_Indexed); - param->numSteps = param->discrete ? (int) (info.maxValue + 1.0f) : AudioProcessor::getDefaultNumParameterSteps(); - - if ((info.flags & kAudioUnitParameterFlag_HasCFNameString) != 0) - { - param->name = String::fromCFString (info.cfNameString); - - if ((info.flags & kAudioUnitParameterFlag_CFNameRelease) != 0) - CFRelease (info.cfNameString); - } - else - { - param->name = String (info.name, sizeof (info.name)); - } - } - } - } - } - } - - void updateLatency() - { - Float64 latencySecs = 0.0; - UInt32 latencySize = sizeof (latencySecs); - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, - 0, &latencySecs, &latencySize); - - setLatencySamples (roundToInt (latencySecs * getSampleRate())); - } - - void handleIncomingMidiMessage (void*, const MidiMessage& message) - { - const ScopedLock sl (midiInLock); - incomingMidi.addEvent (message, 0); - } - - void handlePartialSysexMessage (void*, const uint8*, int, double) {} - -private: - //============================================================================== - friend class AudioUnitPluginWindowCarbon; - friend class AudioUnitPluginWindowCocoa; - friend class AudioUnitPluginFormat; - - AudioComponentDescription componentDesc; - AudioComponent auComponent; - String pluginName, manufacturer, version; - String fileOrIdentifier; - CriticalSection lock; - bool wantsMidiMessages, producesMidiMessages, wasPlaying, prepared, isAUv3; - - struct AUBuffer - { - AUBuffer (size_t numBuffers) - { - bufferList.calloc (1, (sizeof (AudioBufferList) - sizeof (::AudioBuffer)) + (sizeof (::AudioBuffer) * numBuffers)); - AudioBufferList& buffer = *bufferList.get(); - - buffer.mNumberBuffers = static_cast (numBuffers); - } - - operator AudioBufferList&() - { - return *bufferList.get(); - } - - HeapBlock bufferList; - }; - - OwnedArray outputBufferList; - AudioTimeStamp timeStamp; - AudioSampleBuffer* currentBuffer; - Array > supportedInLayouts, supportedOutLayouts; - - int numChannelInfos; - HeapBlock channelInfos; - - AudioUnit audioUnit; - #if JUCE_MAC - AUEventListenerRef eventListenerRef; - #endif - - struct ParamInfo - { - UInt32 paramID; - String name; - AudioUnitParameterValue minValue, maxValue; - bool automatable, discrete; - int numSteps; - }; - - OwnedArray parameters; - HashMap paramIDToIndex; - - MidiDataConcatenator midiConcatenator; - CriticalSection midiInLock; - MidiBuffer incomingMidi; - - void createPluginCallbacks() - { - if (audioUnit != nullptr) - { - #if JUCE_MAC - if (producesMidiMessages) - { - AUMIDIOutputCallbackStruct info; - zerostruct (info); - - info.userData = this; - info.midiOutputCallback = renderMidiOutputCallback; - - producesMidiMessages = (AudioUnitSetProperty (audioUnit, kAudioUnitProperty_MIDIOutputCallback, - kAudioUnitScope_Global, 0, &info, sizeof (info)) == noErr); - } - #endif - - { - HostCallbackInfo info; - zerostruct (info); - - info.hostUserData = this; - info.beatAndTempoProc = getBeatAndTempoCallback; - info.musicalTimeLocationProc = getMusicalTimeLocationCallback; - info.transportStateProc = getTransportStateCallback; - - AudioUnitSetProperty (audioUnit, kAudioUnitProperty_HostCallbacks, - kAudioUnitScope_Global, 0, &info, sizeof (info)); - } - #if JUCE_MAC - AUEventListenerCreate (eventListenerCallback, this, CFRunLoopGetMain(), - kCFRunLoopDefaultMode, 0, 0, &eventListenerRef); - - for (int i = 0; i < parameters.size(); ++i) - { - AudioUnitEvent event; - event.mArgument.mParameter.mAudioUnit = audioUnit; - event.mArgument.mParameter.mParameterID = parameters.getUnchecked(i)->paramID; - event.mArgument.mParameter.mScope = kAudioUnitScope_Global; - event.mArgument.mParameter.mElement = 0; - - event.mEventType = kAudioUnitEvent_ParameterValueChange; - AUEventListenerAddEventType (eventListenerRef, nullptr, &event); - - event.mEventType = kAudioUnitEvent_BeginParameterChangeGesture; - AUEventListenerAddEventType (eventListenerRef, nullptr, &event); - - event.mEventType = kAudioUnitEvent_EndParameterChangeGesture; - AUEventListenerAddEventType (eventListenerRef, nullptr, &event); - } - - addPropertyChangeListener (kAudioUnitProperty_PresentPreset); - addPropertyChangeListener (kAudioUnitProperty_ParameterList); - addPropertyChangeListener (kAudioUnitProperty_Latency); - #endif - } - } - - #if JUCE_MAC - void addPropertyChangeListener (AudioUnitPropertyID type) const - { - - AudioUnitEvent event; - event.mEventType = kAudioUnitEvent_PropertyChange; - event.mArgument.mProperty.mPropertyID = type; - event.mArgument.mProperty.mAudioUnit = audioUnit; - event.mArgument.mProperty.mScope = kAudioUnitScope_Global; - event.mArgument.mProperty.mElement = 0; - AUEventListenerAddEventType (eventListenerRef, nullptr, &event); - } - - void eventCallback (const AudioUnitEvent& event, AudioUnitParameterValue newValue) - { - int paramIndex = -1; - - if (event.mEventType == kAudioUnitEvent_ParameterValueChange - || event.mEventType == kAudioUnitEvent_BeginParameterChangeGesture - || event.mEventType == kAudioUnitEvent_EndParameterChangeGesture) - { - auto paramID = event.mArgument.mParameter.mParameterID; - - if (! paramIDToIndex.contains (paramID)) - return; - - paramIndex = static_cast (paramIDToIndex [paramID]); - - if (! isPositiveAndBelow (paramIndex, parameters.size())) - return; - } - - switch (event.mEventType) - { - case kAudioUnitEvent_ParameterValueChange: - { - auto& p = *parameters.getUnchecked (paramIndex); - sendParamChangeMessageToListeners (paramIndex, (newValue - p.minValue) / (p.maxValue - p.minValue)); - } - break; - - case kAudioUnitEvent_BeginParameterChangeGesture: - beginParameterChangeGesture (paramIndex); - break; - - case kAudioUnitEvent_EndParameterChangeGesture: - endParameterChangeGesture (paramIndex); - break; - - default: - if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_ParameterList) - updateHostDisplay(); - else if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_PresentPreset) - sendAllParametersChangedEvents(); - else if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_Latency) - updateLatency(); - - break; - } - } - - static void eventListenerCallback (void* userRef, void*, const AudioUnitEvent* event, - UInt64, AudioUnitParameterValue value) - { - jassert (event != nullptr); - static_cast (userRef)->eventCallback (*event, value); - } - #endif - - //============================================================================== - OSStatus renderGetInput (AudioUnitRenderActionFlags*, - const AudioTimeStamp*, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList* ioData) const - { - if (currentBuffer != nullptr) - { - // if this ever happens, might need to add extra handling - jassert (inNumberFrames == (UInt32) currentBuffer->getNumSamples()); - AudioSampleBuffer buffer = - (static_cast (inBusNumber) < getBusCount (true) - ? getBusBuffer (*currentBuffer, true, static_cast (inBusNumber)) - : AudioSampleBuffer()); - - for (int i = 0; i < static_cast (ioData->mNumberBuffers); ++i) - { - if (i < buffer.getNumChannels()) - { - memcpy (ioData->mBuffers[i].mData, - buffer.getReadPointer (i), - sizeof (float) * inNumberFrames); - } - else - { - zeromem (ioData->mBuffers[i].mData, - sizeof (float) * inNumberFrames); - } - } - } - - return noErr; - } - - OSStatus renderMidiOutput (const MIDIPacketList* pktlist) - { - if (pktlist != nullptr && pktlist->numPackets) - { - const double time = Time::getMillisecondCounterHiRes() * 0.001; - const MIDIPacket* packet = &pktlist->packet[0]; - - for (UInt32 i = 0; i < pktlist->numPackets; ++i) - { - midiConcatenator.pushMidiData (packet->data, (int) packet->length, time, (void*) nullptr, *this); - packet = MIDIPacketNext (packet); - } - } - - return noErr; - } - - template - static void setIfNotNull (Type1* p, Type2 value) noexcept - { - if (p != nullptr) *p = value; - } - - OSStatus getBeatAndTempo (Float64* outCurrentBeat, Float64* outCurrentTempo) const - { - AudioPlayHead* const ph = getPlayHead(); - AudioPlayHead::CurrentPositionInfo result; - - if (ph != nullptr && ph->getCurrentPosition (result)) - { - setIfNotNull (outCurrentBeat, result.ppqPosition); - setIfNotNull (outCurrentTempo, result.bpm); - } - else - { - setIfNotNull (outCurrentBeat, 0); - setIfNotNull (outCurrentTempo, 120.0); - } - - return noErr; - } - - OSStatus getMusicalTimeLocation (UInt32* outDeltaSampleOffsetToNextBeat, Float32* outTimeSig_Numerator, - UInt32* outTimeSig_Denominator, Float64* outCurrentMeasureDownBeat) const - { - if (AudioPlayHead* const ph = getPlayHead()) - { - AudioPlayHead::CurrentPositionInfo result; - - if (ph->getCurrentPosition (result)) - { - setIfNotNull (outDeltaSampleOffsetToNextBeat, (UInt32) 0); //xxx - setIfNotNull (outTimeSig_Numerator, (UInt32) result.timeSigNumerator); - setIfNotNull (outTimeSig_Denominator, (UInt32) result.timeSigDenominator); - setIfNotNull (outCurrentMeasureDownBeat, result.ppqPositionOfLastBarStart); //xxx wrong - return noErr; - } - } - - setIfNotNull (outDeltaSampleOffsetToNextBeat, (UInt32) 0); - setIfNotNull (outTimeSig_Numerator, (UInt32) 4); - setIfNotNull (outTimeSig_Denominator, (UInt32) 4); - setIfNotNull (outCurrentMeasureDownBeat, 0); - return noErr; - } - - OSStatus getTransportState (Boolean* outIsPlaying, Boolean* outTransportStateChanged, - Float64* outCurrentSampleInTimeLine, Boolean* outIsCycling, - Float64* outCycleStartBeat, Float64* outCycleEndBeat) - { - if (AudioPlayHead* const ph = getPlayHead()) - { - AudioPlayHead::CurrentPositionInfo result; - - if (ph->getCurrentPosition (result)) - { - setIfNotNull (outIsPlaying, result.isPlaying); - - if (outTransportStateChanged != nullptr) - { - *outTransportStateChanged = result.isPlaying != wasPlaying; - wasPlaying = result.isPlaying; - } - - setIfNotNull (outCurrentSampleInTimeLine, result.timeInSamples); - setIfNotNull (outIsCycling, result.isLooping); - setIfNotNull (outCycleStartBeat, result.ppqLoopStart); - setIfNotNull (outCycleEndBeat, result.ppqLoopEnd); - return noErr; - } - } - - setIfNotNull (outIsPlaying, false); - setIfNotNull (outTransportStateChanged, false); - setIfNotNull (outCurrentSampleInTimeLine, 0); - setIfNotNull (outIsCycling, false); - setIfNotNull (outCycleStartBeat, 0.0); - setIfNotNull (outCycleEndBeat, 0.0); - return noErr; - } - - //============================================================================== - static OSStatus renderGetInputCallback (void* hostRef, AudioUnitRenderActionFlags* ioActionFlags, - const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, - UInt32 inNumberFrames, AudioBufferList* ioData) - { - return static_cast (hostRef) - ->renderGetInput (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); - } - - static OSStatus renderMidiOutputCallback (void* hostRef, const AudioTimeStamp*, UInt32 /*midiOutNum*/, - const MIDIPacketList* pktlist) - { - return static_cast (hostRef)->renderMidiOutput (pktlist); - } - - static OSStatus getBeatAndTempoCallback (void* hostRef, Float64* outCurrentBeat, Float64* outCurrentTempo) - { - return static_cast (hostRef)->getBeatAndTempo (outCurrentBeat, outCurrentTempo); - } - - static OSStatus getMusicalTimeLocationCallback (void* hostRef, UInt32* outDeltaSampleOffsetToNextBeat, - Float32* outTimeSig_Numerator, UInt32* outTimeSig_Denominator, - Float64* outCurrentMeasureDownBeat) - { - return static_cast (hostRef) - ->getMusicalTimeLocation (outDeltaSampleOffsetToNextBeat, outTimeSig_Numerator, - outTimeSig_Denominator, outCurrentMeasureDownBeat); - } - - static OSStatus getTransportStateCallback (void* hostRef, Boolean* outIsPlaying, Boolean* outTransportStateChanged, - Float64* outCurrentSampleInTimeLine, Boolean* outIsCycling, - Float64* outCycleStartBeat, Float64* outCycleEndBeat) - { - return static_cast (hostRef) - ->getTransportState (outIsPlaying, outTransportStateChanged, outCurrentSampleInTimeLine, - outIsCycling, outCycleStartBeat, outCycleEndBeat); - } - - //============================================================================== - static inline UInt64 GetCurrentHostTime (int numSamples, double sampleRate, bool isAUv3) noexcept - { - #if ! JUCE_IOS - if (! isAUv3) - return AudioGetCurrentHostTime(); - #else - ignoreUnused (isAUv3); - #endif - - UInt64 currentTime = mach_absolute_time(); - static mach_timebase_info_data_t sTimebaseInfo = {0, 0}; - - if (sTimebaseInfo.denom == 0) - mach_timebase_info (&sTimebaseInfo); - - double bufferNanos = static_cast (numSamples) * 1.0e9 / sampleRate; - UInt64 bufferTicks = static_cast (std::ceil (bufferNanos * (static_cast (sTimebaseInfo.denom) / static_cast (sTimebaseInfo.numer)))); - currentTime += bufferTicks; - - return currentTime; - } - - bool isBusCountWritable (bool isInput) const noexcept - { - UInt32 countSize; - Boolean writable; - OSStatus err; - AudioUnitScope scope = (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output); - - err = AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_ElementCount, scope, 0, &countSize, &writable); - - return (err == noErr && writable != 0 && countSize == sizeof (UInt32)); - } - - //============================================================================== - int getElementCount (AudioUnitScope scope) const noexcept - { - return static_cast (getElementCount (audioUnit, scope)); - } - - static int getElementCount (AudioUnit comp, AudioUnitScope scope) noexcept - { - UInt32 count; - UInt32 countSize = sizeof (count); - - OSStatus err = AudioUnitGetProperty (comp, kAudioUnitProperty_ElementCount, scope, 0, &count, &countSize); - jassert (err == noErr); - ignoreUnused (err); - - return static_cast (count); - } - - //============================================================================== - void getBusProperties (bool isInput, int busIdx, String& busName, AudioChannelSet& currentLayout) const - { - getBusProperties (audioUnit, isInput, busIdx, busName, currentLayout); - } - - static void getBusProperties (AudioUnit comp, bool isInput, int busIdx, String& busName, AudioChannelSet& currentLayout) - { - const AudioUnitScope scope = isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output; - busName = (isInput ? "Input #" : "Output #") + String (busIdx + 1); - - { - CFStringRef busNameCF = nullptr; - UInt32 propertySize = sizeof (busNameCF); - - if (AudioUnitGetProperty (comp, kAudioUnitProperty_ElementName, scope, static_cast (busIdx), &busNameCF, &propertySize) == noErr - && busNameCF != nullptr) - { - busName = nsStringToJuce ((NSString*) busNameCF); - CFRelease (busNameCF); - } - - { - AudioChannelLayout auLayout; - propertySize = sizeof (auLayout); - - if (AudioUnitGetProperty (comp, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (busIdx), &auLayout, &propertySize) == noErr) - currentLayout = CoreAudioLayouts::fromCoreAudio (auLayout); - } - - if (currentLayout.isDisabled()) - { - AudioStreamBasicDescription descr; - propertySize = sizeof (descr); - - if (AudioUnitGetProperty (comp, kAudioUnitProperty_StreamFormat, scope, static_cast (busIdx), &descr, &propertySize) == noErr) - currentLayout = AudioChannelSet::canonicalChannelSet (static_cast (descr.mChannelsPerFrame)); - } - } - } - - //============================================================================== - void numBusesChanged() override - { - updateSupportedLayouts(); - } - - void updateSupportedLayouts() - { - supportedInLayouts.clear(); - supportedOutLayouts.clear(); - numChannelInfos = 0; - channelInfos.free(); - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const AudioUnitScope scope = isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output; - const int n = getElementCount (scope); - - for (int busIdx = 0; busIdx < n; ++busIdx) - { - Array supported; - AudioChannelSet currentLayout; - - { - AudioChannelLayout auLayout; - UInt32 propertySize = sizeof (auLayout); - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (busIdx), &auLayout, &propertySize) == noErr) - currentLayout = CoreAudioLayouts::fromCoreAudio (auLayout); - } - - if (currentLayout.isDisabled()) - { - AudioStreamBasicDescription descr; - UInt32 propertySize = sizeof (descr); - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, static_cast (busIdx), &descr, &propertySize) == noErr) - currentLayout = AudioChannelSet::canonicalChannelSet (static_cast (descr.mChannelsPerFrame)); - } - - supported.clear(); - { - UInt32 propertySize = 0; - Boolean writable; - - if (AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_SupportedChannelLayoutTags, scope, static_cast (busIdx), &propertySize, &writable) == noErr - && propertySize > 0) - { - const size_t numElements = propertySize / sizeof (AudioChannelLayoutTag); - HeapBlock layoutTags (numElements); - propertySize = static_cast (sizeof (AudioChannelLayoutTag) * numElements); - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SupportedChannelLayoutTags, scope, - static_cast (busIdx), layoutTags.get(), &propertySize) == noErr) - { - for (int j = 0; j < static_cast (numElements); ++j) - { - const AudioChannelLayoutTag tag = layoutTags[j]; - - if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) - { - AudioChannelLayout caLayout; - - caLayout.mChannelLayoutTag = tag; - supported.addIfNotAlreadyThere (CoreAudioLayouts::fromCoreAudio (caLayout)); - } - } - - if (supported.size() > 0) - supported.addIfNotAlreadyThere (currentLayout); - } - } - } - - (isInput ? supportedInLayouts : supportedOutLayouts).add (supported); - } - } - - { - UInt32 propertySize = 0; - Boolean writable; - - if (AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, &propertySize, &writable) == noErr - && propertySize > 0) - { - numChannelInfos = propertySize / sizeof (AUChannelInfo); - channelInfos.malloc (static_cast (numChannelInfos)); - propertySize = static_cast (sizeof (AUChannelInfo) * static_cast (numChannelInfos)); - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, channelInfos.get(), &propertySize) != noErr) - numChannelInfos = 0; - } - else - { - numChannelInfos = 1; - channelInfos.malloc (static_cast (numChannelInfos)); - channelInfos.get()->inChannels = -1; - channelInfos.get()->outChannels = -1; - } - } - } - - bool canProduceMidiOutput() - { - #if JUCE_MAC - UInt32 dataSize = 0; - Boolean isWritable = false; - - if (AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_MIDIOutputCallbackInfo, - kAudioUnitScope_Global, 0, &dataSize, &isWritable) == noErr - && dataSize != 0) - { - CFArrayRef midiArray; - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_MIDIOutputCallbackInfo, - kAudioUnitScope_Global, 0, &midiArray, &dataSize) == noErr) - { - bool result = (CFArrayGetCount (midiArray) > 0); - CFRelease (midiArray); - return result; - } - } - - return false; - #else - return false; - #endif - } - - bool supportsMPE() const override - { - UInt32 dataSize = 0; - Boolean isWritable = false; - - if (AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_SupportsMPE, - kAudioUnitScope_Global, 0, &dataSize, &isWritable) == noErr - && dataSize == sizeof (UInt32)) - { - UInt32 result = 0; - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SupportsMPE, - kAudioUnitScope_Global, 0, &result, &dataSize) == noErr) - { - return result > 0; - } - } - - return false; - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioUnitPluginInstance) -}; - -//============================================================================== -class AudioUnitPluginWindowCocoa : public AudioProcessorEditor -{ -public: - AudioUnitPluginWindowCocoa (AudioUnitPluginInstance& p, bool createGenericViewIfNeeded) - : AudioProcessorEditor (&p), - plugin (p), waitingForViewCallback (false) - { - addAndMakeVisible (wrapper); - - #if JUCE_SUPPORTS_AUv3 - viewControllerCallback = - CreateObjCBlock (this, &AudioUnitPluginWindowCocoa::requestViewControllerCallback); - #endif - - setOpaque (true); - setVisible (true); - setSize (100, 100); - - createView (createGenericViewIfNeeded); - } - - ~AudioUnitPluginWindowCocoa() - { - if (wrapper.getView() != nil) - { - wrapper.setVisible (false); - removeChildComponent (&wrapper); - wrapper.setView (nil); - plugin.editorBeingDeleted (this); - } - } - - #if JUCE_SUPPORTS_AUv3 - void embedViewController (JUCE_IOS_MAC_VIEW* pluginView, const CGSize& size) - { - wrapper.setView (pluginView); - waitingForViewCallback = false; - - #if JUCE_MAC - ignoreUnused (size); - if (pluginView != nil) - wrapper.resizeToFitView(); - #else - [pluginView setBounds: CGRectMake (0.f, 0.f, static_cast (size.width), static_cast (size.height))]; - wrapper.setSize (static_cast (size.width), static_cast (size.height)); - #endif - } - #endif - - bool isValid() const { return wrapper.getView() != nil || waitingForViewCallback; } - - void paint (Graphics& g) override - { - g.fillAll (Colours::white); - } - - void resized() override - { - wrapper.setSize (getWidth(), getHeight()); - } - - void childBoundsChanged (Component*) override - { - setSize (wrapper.getWidth(), wrapper.getHeight()); - } - -private: - - AudioUnitPluginInstance& plugin; - AutoResizingNSViewComponent wrapper; - - #if JUCE_SUPPORTS_AUv3 - typedef void (^ViewControllerCallbackBlock)(AUViewControllerBase *); - ObjCBlock viewControllerCallback; - #endif - - bool waitingForViewCallback; - - bool createView (const bool createGenericViewIfNeeded) - { - JUCE_IOS_MAC_VIEW* pluginView = nil; - UInt32 dataSize = 0; - Boolean isWritable = false; - - #if JUCE_MAC - if (AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, - 0, &dataSize, &isWritable) == noErr - && dataSize != 0 - && AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, - 0, &dataSize, &isWritable) == noErr) - { - HeapBlock info; - info.calloc (dataSize, 1); - - if (AudioUnitGetProperty (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, - 0, info, &dataSize) == noErr) - { - NSString* viewClassName = (NSString*) (info->mCocoaAUViewClass[0]); - CFStringRef path = CFURLCopyPath (info->mCocoaAUViewBundleLocation); - NSString* unescapedPath = (NSString*) CFURLCreateStringByReplacingPercentEscapes (0, path, CFSTR ("")); - CFRelease (path); - NSBundle* viewBundle = [NSBundle bundleWithPath: [unescapedPath autorelease]]; - Class viewClass = [viewBundle classNamed: viewClassName]; - - if ([viewClass conformsToProtocol: @protocol (AUCocoaUIBase)] - && [viewClass instancesRespondToSelector: @selector (interfaceVersion)] - && [viewClass instancesRespondToSelector: @selector (uiViewForAudioUnit: withSize:)]) - { - id factory = [[[viewClass alloc] init] autorelease]; - pluginView = [factory uiViewForAudioUnit: plugin.audioUnit - withSize: NSMakeSize (getWidth(), getHeight())]; - } - - for (int i = (dataSize - sizeof (CFURLRef)) / sizeof (CFStringRef); --i >= 0;) - CFRelease (info->mCocoaAUViewClass[i]); - - CFRelease (info->mCocoaAUViewBundleLocation); - } - } - #endif - - dataSize = 0; - isWritable = false; - - #if JUCE_SUPPORTS_AUv3 - if (AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_RequestViewController, kAudioUnitScope_Global, - 0, &dataSize, &isWritable) == noErr - && dataSize == sizeof (ViewControllerCallbackBlock) - && AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_RequestViewController, kAudioUnitScope_Global, - 0, &dataSize, &isWritable) == noErr) - { - waitingForViewCallback = true; - ViewControllerCallbackBlock callback; - callback = viewControllerCallback; - - ViewControllerCallbackBlock* info = &callback; - - if (noErr == AudioUnitSetProperty (plugin.audioUnit, kAudioUnitProperty_RequestViewController, kAudioUnitScope_Global, 0, info, dataSize)) - return true; - - waitingForViewCallback = false; - } - #endif - - #if JUCE_MAC - if (createGenericViewIfNeeded && (pluginView == nil)) - { - { - // This forces CoreAudio.component to be loaded, otherwise the AUGenericView will assert - AudioComponentDescription desc; - String name, version, manufacturer; - AudioUnitFormatHelpers::getComponentDescFromIdentifier ("AudioUnit:Output/auou,genr,appl", - desc, name, version, manufacturer); - } - - pluginView = [[AUGenericView alloc] initWithAudioUnit: plugin.audioUnit]; - } - #else - ignoreUnused (createGenericViewIfNeeded); - #endif - - wrapper.setView (pluginView); - - if (pluginView != nil) - wrapper.resizeToFitView(); - - return pluginView != nil; - } - - #if JUCE_SUPPORTS_AUv3 - void requestViewControllerCallback (AUViewControllerBase* controller) - { - auto nsSize = [controller preferredContentSize]; - auto viewSize = CGSizeMake (nsSize.width, nsSize.height); - - if (! MessageManager::getInstance()->isThisTheMessageThread()) - { - struct AsyncViewControllerCallback : public CallbackMessage - { - AudioUnitPluginWindowCocoa* owner; - JUCE_IOS_MAC_VIEW* controllerView; - CGSize size; - - AsyncViewControllerCallback (AudioUnitPluginWindowCocoa* plugInWindow, JUCE_IOS_MAC_VIEW* inView, - const CGSize& preferredSize) - : owner (plugInWindow), controllerView ([inView retain]), size (preferredSize) - {} - - void messageCallback() override - { - owner->embedViewController (controllerView, size); - [controllerView release]; - } - }; - - (new AsyncViewControllerCallback (this, [controller view], viewSize))->post(); - } - else - { - embedViewController ([controller view], viewSize); - } - } - #endif -}; - -#if JUCE_SUPPORT_CARBON - -//============================================================================== -class AudioUnitPluginWindowCarbon : public AudioProcessorEditor -{ -public: - AudioUnitPluginWindowCarbon (AudioUnitPluginInstance& p) - : AudioProcessorEditor (&p), - plugin (p), - audioComponent (nullptr), - viewComponent (nullptr) - { - addAndMakeVisible (innerWrapper = new InnerWrapperComponent (*this)); - - setOpaque (true); - setVisible (true); - setSize (400, 300); - - UInt32 propertySize; - if (AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_GetUIComponentList, - kAudioUnitScope_Global, 0, &propertySize, NULL) == noErr - && propertySize > 0) - { - HeapBlock views (propertySize / sizeof (AudioComponentDescription)); - - if (AudioUnitGetProperty (plugin.audioUnit, kAudioUnitProperty_GetUIComponentList, - kAudioUnitScope_Global, 0, &views[0], &propertySize) == noErr) - { - audioComponent = AudioComponentFindNext (nullptr, &views[0]); - } - } - } - - ~AudioUnitPluginWindowCarbon() - { - innerWrapper = nullptr; - - if (isValid()) - plugin.editorBeingDeleted (this); - } - - bool isValid() const noexcept { return audioComponent != nullptr; } - - //============================================================================== - void paint (Graphics& g) override - { - g.fillAll (Colours::black); - } - - void resized() override - { - if (innerWrapper != nullptr) - innerWrapper->setSize (getWidth(), getHeight()); - } - - //============================================================================== - bool keyStateChanged (bool) override { return false; } - bool keyPressed (const KeyPress&) override { return false; } - - //============================================================================== - AudioUnit getAudioUnit() const { return plugin.audioUnit; } - - AudioUnitCarbonView getViewComponent() - { - if (viewComponent == nullptr && audioComponent != nullptr) - AudioComponentInstanceNew (audioComponent, &viewComponent); - - return viewComponent; - } - - void closeViewComponent() - { - if (viewComponent != nullptr) - { - JUCE_AU_LOG ("Closing AU GUI: " + plugin.getName()); - - AudioComponentInstanceDispose (viewComponent); - viewComponent = nullptr; - } - } - -private: - //============================================================================== - AudioUnitPluginInstance& plugin; - AudioComponent audioComponent; - AudioUnitCarbonView viewComponent; - - //============================================================================== - class InnerWrapperComponent : public CarbonViewWrapperComponent - { - public: - InnerWrapperComponent (AudioUnitPluginWindowCarbon& w) : owner (w) {} - - ~InnerWrapperComponent() - { - deleteWindow(); - } - - HIViewRef attachView (WindowRef windowRef, HIViewRef rootView) override - { - JUCE_AU_LOG ("Opening AU GUI: " + owner.plugin.getName()); - - AudioUnitCarbonView carbonView = owner.getViewComponent(); - - if (carbonView == 0) - return 0; - - Float32Point pos = { 0, 0 }; - Float32Point size = { 250, 200 }; - HIViewRef pluginView = 0; - - AudioUnitCarbonViewCreate (carbonView, owner.getAudioUnit(), windowRef, rootView, - &pos, &size, (ControlRef*) &pluginView); - - return pluginView; - } - - void removeView (HIViewRef) override - { - owner.closeViewComponent(); - } - - private: - AudioUnitPluginWindowCarbon& owner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InnerWrapperComponent) - }; - - friend class InnerWrapperComponent; - ScopedPointer innerWrapper; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioUnitPluginWindowCarbon) -}; - -#endif - -//============================================================================== -AudioProcessorEditor* AudioUnitPluginInstance::createEditor() -{ - ScopedPointer w (new AudioUnitPluginWindowCocoa (*this, false)); - - if (! static_cast (w.get())->isValid()) - w = nullptr; - - #if JUCE_SUPPORT_CARBON - if (w == nullptr) - { - w = new AudioUnitPluginWindowCarbon (*this); - - if (! static_cast (w.get())->isValid()) - w = nullptr; - } - #endif - - if (w == nullptr) - w = new AudioUnitPluginWindowCocoa (*this, true); // use AUGenericView as a fallback - - return w.release(); -} - - -//============================================================================== -//============================================================================== -AudioUnitPluginFormat::AudioUnitPluginFormat() -{ -} - -AudioUnitPluginFormat::~AudioUnitPluginFormat() -{ -} - -void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray& results, - const String& fileOrIdentifier) -{ - if (! fileMightContainThisPluginType (fileOrIdentifier)) - return; - - PluginDescription desc; - desc.fileOrIdentifier = fileOrIdentifier; - desc.uid = 0; - - if (MessageManager::getInstance()->isThisTheMessageThread() - && requiresUnblockedMessageThreadDuringCreation (desc)) - return; - - try - { - ScopedPointer createdInstance (createInstanceFromDescription (desc, 44100.0, 512)); - - if (AudioUnitPluginInstance* auInstance = dynamic_cast (createdInstance.get())) - results.add (new PluginDescription (auInstance->getPluginDescription())); - } - catch (...) - { - // crashed while loading... - } -} - -void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, - double rate, - int blockSize, - void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) -{ - using namespace AudioUnitFormatHelpers; - - if (fileMightContainThisPluginType (desc.fileOrIdentifier)) - { - - String pluginName, version, manufacturer; - AudioComponentDescription componentDesc; - AudioComponent auComponent; - String errMessage = NEEDS_TRANS ("Cannot find AudioUnit from description"); - - if ((! getComponentDescFromIdentifier (desc.fileOrIdentifier, componentDesc, pluginName, version, manufacturer)) - && (! getComponentDescFromFile (desc.fileOrIdentifier, componentDesc, pluginName, version, manufacturer))) - { - callback (userData, nullptr, errMessage); - return; - } - - if ((auComponent = AudioComponentFindNext (0, &componentDesc)) == nullptr) - { - callback (userData, nullptr, errMessage); - return; - } - - if (AudioComponentGetDescription (auComponent, &componentDesc) != noErr) - { - callback (userData, nullptr, errMessage); - return; - } - - struct AUAsyncInitializationCallback - { - #if JUCE_SUPPORTS_AUv3 - typedef void (^AUCompletionCallbackBlock)(AudioComponentInstance, OSStatus); - #endif - - AUAsyncInitializationCallback (double inSampleRate, int inFramesPerBuffer, - void* inUserData, void (*inOriginalCallback) (void*, AudioPluginInstance*, const String&)) - : sampleRate (inSampleRate), framesPerBuffer (inFramesPerBuffer), - passUserData (inUserData), originalCallback (inOriginalCallback) - { - #if JUCE_SUPPORTS_AUv3 - block = CreateObjCBlock (this, &AUAsyncInitializationCallback::completion); - #endif - } - - #if JUCE_SUPPORTS_AUv3 - AUCompletionCallbackBlock getBlock() noexcept { return block; } - #endif - - void completion (AudioComponentInstance audioUnit, OSStatus err) - { - if (err == noErr) - { - ScopedPointer instance (new AudioUnitPluginInstance (audioUnit)); - - if (instance->initialise (sampleRate, framesPerBuffer)) - originalCallback (passUserData, instance.release(), StringRef()); - else - originalCallback (passUserData, nullptr, - NEEDS_TRANS ("Unable to initialise the AudioUnit plug-in")); - } - else - { - String errMsg = NEEDS_TRANS ("An OS error occurred during initialisation of the plug-in (XXX)"); - originalCallback (passUserData, nullptr, errMsg.replace ("XXX", String (err))); - } - - delete this; - } - - double sampleRate; - int framesPerBuffer; - void* passUserData; - void (*originalCallback) (void*, AudioPluginInstance*, const String&); - - #if JUCE_SUPPORTS_AUv3 - ObjCBlock block; - #endif - }; - - AUAsyncInitializationCallback* callbackBlock - = new AUAsyncInitializationCallback (rate, blockSize, userData, callback); - - #if JUCE_SUPPORTS_AUv3 - //============================================================================== - bool isAUv3 = ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0); - - if (isAUv3) - { - AudioComponentInstantiate (auComponent, kAudioComponentInstantiation_LoadOutOfProcess, - callbackBlock->getBlock()); - - return; - } - #endif // JUCE_SUPPORTS_AUv3 - - AudioComponentInstance audioUnit; - OSStatus err = AudioComponentInstanceNew(auComponent, &audioUnit); - callbackBlock->completion (err != noErr ? nullptr : audioUnit, err); - } - else - { - callback (userData, nullptr, NEEDS_TRANS ("Plug-in description is not an AudioUnit plug-in")); - } -} - -bool AudioUnitPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription& desc) const noexcept -{ - #if JUCE_SUPPORTS_AUv3 - String pluginName, version, manufacturer; - AudioComponentDescription componentDesc; - - if (AudioUnitFormatHelpers::getComponentDescFromIdentifier (desc.fileOrIdentifier, componentDesc, - pluginName, version, manufacturer) - || AudioUnitFormatHelpers::getComponentDescFromFile (desc.fileOrIdentifier, componentDesc, - pluginName, version, manufacturer)) - { - if (AudioComponent auComp = AudioComponentFindNext (0, &componentDesc)) - if (AudioComponentGetDescription (auComp, &componentDesc) == noErr) - return ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0); - } - #else - ignoreUnused (desc); - #endif - - return false; -} - -StringArray AudioUnitPluginFormat::searchPathsForPlugins (const FileSearchPath&, bool /*recursive*/, bool allowPluginsWhichRequireAsynchronousInstantiation) -{ - StringArray result; - AudioComponent comp = nullptr; - - for (;;) - { - AudioComponentDescription desc; - zerostruct (desc); - - comp = AudioComponentFindNext (comp, &desc); - - if (comp == nullptr) - break; - - if (AudioComponentGetDescription (comp, &desc) != noErr) - continue; - - if (desc.componentType == kAudioUnitType_MusicDevice - || desc.componentType == kAudioUnitType_MusicEffect - || desc.componentType == kAudioUnitType_Effect - || desc.componentType == kAudioUnitType_Generator - || desc.componentType == kAudioUnitType_Panner - || desc.componentType == kAudioUnitType_Mixer) - { - ignoreUnused (allowPluginsWhichRequireAsynchronousInstantiation); - - #if JUCE_SUPPORTS_AUv3 - bool isAUv3 = ((desc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0); - - if (allowPluginsWhichRequireAsynchronousInstantiation || ! isAUv3) - #endif - result.add (AudioUnitFormatHelpers::createPluginIdentifier (desc)); - } - } - - return result; -} - -bool AudioUnitPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) -{ - AudioComponentDescription desc; - - String name, version, manufacturer; - if (AudioUnitFormatHelpers::getComponentDescFromIdentifier (fileOrIdentifier, desc, name, version, manufacturer)) - return AudioComponentFindNext (nullptr, &desc) != nullptr; - - const File f (File::createFileWithoutCheckingPath (fileOrIdentifier)); - - return (f.hasFileExtension (".component") || f.hasFileExtension (".appex")) - && f.isDirectory(); -} - -String AudioUnitPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) -{ - AudioComponentDescription desc; - String name, version, manufacturer; - AudioUnitFormatHelpers::getComponentDescFromIdentifier (fileOrIdentifier, desc, name, version, manufacturer); - - if (name.isEmpty()) - name = fileOrIdentifier; - - return name; -} - -bool AudioUnitPluginFormat::pluginNeedsRescanning (const PluginDescription& desc) -{ - AudioComponentDescription newDesc; - String name, version, manufacturer; - - return ! (AudioUnitFormatHelpers::getComponentDescFromIdentifier (desc.fileOrIdentifier, newDesc, - name, version, manufacturer) - && version == desc.version); -} - -bool AudioUnitPluginFormat::doesPluginStillExist (const PluginDescription& desc) -{ - if (desc.fileOrIdentifier.startsWithIgnoreCase (AudioUnitFormatHelpers::auIdentifierPrefix)) - return fileMightContainThisPluginType (desc.fileOrIdentifier); - - return File (desc.fileOrIdentifier).exists(); -} - -FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() -{ - return {}; -} - -#undef JUCE_AU_LOG - -} // namespace juce - -#endif diff --git a/source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp b/source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp deleted file mode 100644 index 85f307ca2..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp +++ /dev/null @@ -1,718 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -#if JUCE_PLUGINHOST_LADSPA && JUCE_LINUX - -#include "ladspa.h" - -namespace juce -{ - -static int shellLADSPAUIDToCreate = 0; -static int insideLADSPACallback = 0; - -#define JUCE_LADSPA_LOGGING 1 - -#if JUCE_LADSPA_LOGGING - #define JUCE_LADSPA_LOG(x) Logger::writeToLog (x); -#else - #define JUCE_LADSPA_LOG(x) -#endif - -//============================================================================== -class LADSPAModuleHandle : public ReferenceCountedObject -{ -public: - LADSPAModuleHandle (const File& f) - : file (f), moduleMain (nullptr) - { - getActiveModules().add (this); - } - - ~LADSPAModuleHandle() - { - getActiveModules().removeFirstMatchingValue (this); - close(); - } - - typedef ReferenceCountedObjectPtr Ptr; - - static Array & getActiveModules() - { - static Array activeModules; - return activeModules; - } - - static LADSPAModuleHandle* findOrCreateModule (const File& file) - { - for (int i = getActiveModules().size(); --i >= 0;) - { - LADSPAModuleHandle* const module = getActiveModules().getUnchecked(i); - - if (module->file == file) - return module; - } - - ++insideLADSPACallback; - shellLADSPAUIDToCreate = 0; - - JUCE_LADSPA_LOG ("Loading LADSPA module: " + file.getFullPathName()); - - ScopedPointer m (new LADSPAModuleHandle (file)); - - if (! m->open()) - m = nullptr; - - --insideLADSPACallback; - - return m.release(); - } - - File file; - LADSPA_Descriptor_Function moduleMain; - -private: - DynamicLibrary module; - - bool open() - { - module.open (file.getFullPathName()); - moduleMain = (LADSPA_Descriptor_Function) module.getFunction ("ladspa_descriptor"); - return moduleMain != nullptr; - } - - void close() - { - module.close(); - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LADSPAModuleHandle) -}; - - -//============================================================================== -class LADSPAPluginInstance : public AudioPluginInstance -{ -public: - LADSPAPluginInstance (const LADSPAModuleHandle::Ptr& m) - : module (m), plugin (nullptr), handle (nullptr), - initialised (false), tempBuffer (1, 1) - { - ++insideLADSPACallback; - - name = module->file.getFileNameWithoutExtension(); - - JUCE_LADSPA_LOG ("Creating LADSPA instance: " + name); - - if (module->moduleMain != nullptr) - { - plugin = module->moduleMain (shellLADSPAUIDToCreate); - - if (plugin == nullptr) - { - JUCE_LADSPA_LOG ("Cannot find any valid descriptor in shared library"); - --insideLADSPACallback; - return; - } - } - else - { - JUCE_LADSPA_LOG ("Cannot find any valid plugin in shared library"); - --insideLADSPACallback; - return; - } - - const double sampleRate = getSampleRate() > 0 ? getSampleRate() : 44100.0; - - handle = plugin->instantiate (plugin, (uint32) sampleRate); - - --insideLADSPACallback; - } - - ~LADSPAPluginInstance() - { - const ScopedLock sl (lock); - - jassert (insideLADSPACallback == 0); - - if (handle != nullptr && plugin != nullptr && plugin->cleanup != nullptr) - plugin->cleanup (handle); - - initialised = false; - module = nullptr; - plugin = nullptr; - handle = nullptr; - } - - void initialise (double initialSampleRate, int initialBlockSize) - { - setPlayConfigDetails (inputs.size(), outputs.size(), initialSampleRate, initialBlockSize); - - if (initialised || plugin == nullptr || handle == nullptr) - return; - - JUCE_LADSPA_LOG ("Initialising LADSPA: " + name); - - initialised = true; - - inputs.clear(); - outputs.clear(); - parameters.clear(); - - for (unsigned int i = 0; i < plugin->PortCount; ++i) - { - const LADSPA_PortDescriptor portDesc = plugin->PortDescriptors[i]; - - if ((portDesc & LADSPA_PORT_CONTROL) != 0) - parameters.add (i); - - if ((portDesc & LADSPA_PORT_AUDIO) != 0) - { - if ((portDesc & LADSPA_PORT_INPUT) != 0) inputs.add (i); - if ((portDesc & LADSPA_PORT_OUTPUT) != 0) outputs.add (i); - } - } - - parameterValues.calloc (parameters.size()); - - for (int i = 0; i < parameters.size(); ++i) - plugin->connect_port (handle, parameters[i], &(parameterValues[i].scaled)); - - setPlayConfigDetails (inputs.size(), outputs.size(), initialSampleRate, initialBlockSize); - - setCurrentProgram (0); - setLatencySamples (0); - - // Some plugins crash if this doesn't happen: - if (plugin->activate != nullptr) plugin->activate (handle); - if (plugin->deactivate != nullptr) plugin->deactivate (handle); - } - - //============================================================================== - // AudioPluginInstance methods: - - void fillInPluginDescription (PluginDescription& desc) const - { - desc.name = getName(); - desc.fileOrIdentifier = module->file.getFullPathName(); - desc.uid = getUID(); - desc.lastFileModTime = module->file.getLastModificationTime(); - desc.lastInfoUpdateTime = Time::getCurrentTime(); - desc.pluginFormatName = "LADSPA"; - desc.category = getCategory(); - desc.manufacturerName = plugin != nullptr ? String (plugin->Maker) : String(); - desc.version = getVersion(); - desc.numInputChannels = getTotalNumInputChannels(); - desc.numOutputChannels = getTotalNumOutputChannels(); - desc.isInstrument = false; - } - - const String getName() const - { - if (plugin != nullptr && plugin->Label != nullptr) - return plugin->Label; - - return name; - } - - int getUID() const - { - if (plugin != nullptr && plugin->UniqueID != 0) - return (int) plugin->UniqueID; - - return module->file.hashCode(); - } - - String getVersion() const { return LADSPA_VERSION; } - String getCategory() const { return "Effect"; } - - bool acceptsMidi() const { return false; } - bool producesMidi() const { return false; } - - double getTailLengthSeconds() const { return 0.0; } - - //============================================================================== - void prepareToPlay (double newSampleRate, int samplesPerBlockExpected) - { - setLatencySamples (0); - - initialise (newSampleRate, samplesPerBlockExpected); - - if (initialised) - { - tempBuffer.setSize (jmax (1, outputs.size()), samplesPerBlockExpected); - - // dodgy hack to force some plugins to initialise the sample rate.. - if (getNumParameters() > 0) - { - const float old = getParameter (0); - setParameter (0, (old < 0.5f) ? 1.0f : 0.0f); - setParameter (0, old); - } - - if (plugin->activate != nullptr) - plugin->activate (handle); - } - } - - void releaseResources() - { - if (handle != nullptr && plugin->deactivate != nullptr) - plugin->deactivate (handle); - - tempBuffer.setSize (1, 1); - } - - void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) - { - const int numSamples = buffer.getNumSamples(); - - if (initialised && plugin != nullptr && handle != nullptr) - { - for (int i = 0; i < inputs.size(); ++i) - plugin->connect_port (handle, inputs[i], - i < buffer.getNumChannels() ? buffer.getWritePointer (i) : nullptr); - - if (plugin->run != nullptr) - { - for (int i = 0; i < outputs.size(); ++i) - plugin->connect_port (handle, outputs.getUnchecked(i), - i < buffer.getNumChannels() ? buffer.getWritePointer (i) : nullptr); - - plugin->run (handle, numSamples); - return; - } - - if (plugin->run_adding != nullptr) - { - tempBuffer.setSize (outputs.size(), numSamples); - tempBuffer.clear(); - - for (int i = 0; i < outputs.size(); ++i) - plugin->connect_port (handle, outputs.getUnchecked(i), tempBuffer.getWritePointer (i)); - - plugin->run_adding (handle, numSamples); - - for (int i = 0; i < outputs.size(); ++i) - if (i < buffer.getNumChannels()) - buffer.copyFrom (i, 0, tempBuffer, i, 0, numSamples); - - return; - } - - jassertfalse; // no callback to use? - } - - for (int i = getTotalNumInputChannels(), e = getTotalNumOutputChannels(); i < e; ++i) - buffer.clear (i, 0, numSamples); - } - - bool isInputChannelStereoPair (int index) const { return isPositiveAndBelow (index, getTotalNumInputChannels()); } - bool isOutputChannelStereoPair (int index) const { return isPositiveAndBelow (index, getTotalNumOutputChannels()); } - - const String getInputChannelName (const int index) const - { - if (isPositiveAndBelow (index, getTotalNumInputChannels())) - return String (plugin->PortNames [inputs [index]]).trim(); - - return {}; - } - - const String getOutputChannelName (const int index) const - { - if (isPositiveAndBelow (index, getTotalNumInputChannels())) - return String (plugin->PortNames [outputs [index]]).trim(); - - return {}; - } - - //============================================================================== - int getNumParameters() { return handle != nullptr ? parameters.size() : 0; } - - bool isParameterAutomatable (int index) const - { - return plugin != nullptr - && (plugin->PortDescriptors [parameters[index]] & LADSPA_PORT_INPUT) != 0; - } - - float getParameter (int index) - { - if (plugin != nullptr && isPositiveAndBelow (index, parameters.size())) - { - const ScopedLock sl (lock); - return parameterValues[index].unscaled; - } - - return 0.0f; - } - - void setParameter (int index, float newValue) - { - if (plugin != nullptr && isPositiveAndBelow (index, parameters.size())) - { - const ScopedLock sl (lock); - - ParameterValue& p = parameterValues[index]; - - if (p.unscaled != newValue) - p = ParameterValue (getNewParamScaled (plugin->PortRangeHints [parameters[index]], newValue), newValue); - } - } - - const String getParameterName (int index) - { - if (plugin != nullptr) - { - jassert (isPositiveAndBelow (index, parameters.size())); - return String (plugin->PortNames [parameters [index]]).trim(); - } - - return {}; - } - - const String getParameterText (int index) - { - if (plugin != nullptr) - { - jassert (index >= 0 && index < parameters.size()); - - const LADSPA_PortRangeHint& hint = plugin->PortRangeHints [parameters [index]]; - - if (LADSPA_IS_HINT_INTEGER (hint.HintDescriptor)) - return String ((int) parameterValues[index].scaled); - - return String (parameterValues[index].scaled, 4); - } - - return {}; - } - - //============================================================================== - int getNumPrograms() { return 0; } - int getCurrentProgram() { return 0; } - - void setCurrentProgram (int newIndex) - { - if (plugin != nullptr) - for (int i = 0; i < parameters.size(); ++i) - parameterValues[i] = getParamValue (plugin->PortRangeHints [parameters[i]]); - } - - const String getProgramName (int index) - { - // XXX - return {}; - } - - void changeProgramName (int index, const String& newName) - { - // XXX - } - - //============================================================================== - void getStateInformation (MemoryBlock& destData) - { - destData.setSize (sizeof (float) * getNumParameters()); - destData.fillWith (0); - - float* const p = (float*) ((char*) destData.getData()); - for (int i = 0; i < getNumParameters(); ++i) - p[i] = getParameter(i); - } - - void getCurrentProgramStateInformation (MemoryBlock& destData) - { - getStateInformation (destData); - } - - void setStateInformation (const void* data, int sizeInBytes) - { - const float* p = static_cast (data); - - for (int i = 0; i < getNumParameters(); ++i) - setParameter (i, p[i]); - } - - void setCurrentProgramStateInformation (const void* data, int sizeInBytes) - { - setStateInformation (data, sizeInBytes); - } - - bool hasEditor() const - { - return false; - } - - AudioProcessorEditor* createEditor() - { - return nullptr; - } - - bool isValid() const - { - return handle != nullptr; - } - - LADSPAModuleHandle::Ptr module; - const LADSPA_Descriptor* plugin; - -private: - LADSPA_Handle handle; - String name; - CriticalSection lock; - bool initialised; - AudioSampleBuffer tempBuffer; - Array inputs, outputs, parameters; - - struct ParameterValue - { - inline ParameterValue() noexcept : scaled (0), unscaled (0) {} - inline ParameterValue (float s, float u) noexcept : scaled (s), unscaled (u) {} - - float scaled, unscaled; - }; - - HeapBlock parameterValues; - - //============================================================================== - static float scaledValue (float low, float high, float alpha, bool useLog) noexcept - { - if (useLog && low > 0 && high > 0) - return expf (logf (low) * (1.0f - alpha) + logf (high) * alpha); - - return low + (high - low) * alpha; - } - - static float toIntIfNecessary (const LADSPA_PortRangeHintDescriptor& desc, float value) - { - return LADSPA_IS_HINT_INTEGER (desc) ? ((float) (int) value) : value; - } - - float getNewParamScaled (const LADSPA_PortRangeHint& hint, float newValue) const - { - const LADSPA_PortRangeHintDescriptor& desc = hint.HintDescriptor; - - if (LADSPA_IS_HINT_TOGGLED (desc)) - return (newValue < 0.5f) ? 0.0f : 1.0f; - - const float scale = LADSPA_IS_HINT_SAMPLE_RATE (desc) ? (float) getSampleRate() : 1.0f; - const float lower = hint.LowerBound * scale; - const float upper = hint.UpperBound * scale; - - if (LADSPA_IS_HINT_BOUNDED_BELOW (desc) && LADSPA_IS_HINT_BOUNDED_ABOVE (desc)) - return toIntIfNecessary (desc, scaledValue (lower, upper, newValue, LADSPA_IS_HINT_LOGARITHMIC (desc))); - - if (LADSPA_IS_HINT_BOUNDED_BELOW (desc)) return toIntIfNecessary (desc, newValue); - if (LADSPA_IS_HINT_BOUNDED_ABOVE (desc)) return toIntIfNecessary (desc, newValue * upper); - - return 0.0f; - } - - ParameterValue getParamValue (const LADSPA_PortRangeHint& hint) const - { - const LADSPA_PortRangeHintDescriptor& desc = hint.HintDescriptor; - - if (LADSPA_IS_HINT_HAS_DEFAULT (desc)) - { - if (LADSPA_IS_HINT_DEFAULT_0 (desc)) return ParameterValue(); - if (LADSPA_IS_HINT_DEFAULT_1 (desc)) return ParameterValue (1.0f, 1.0f); - if (LADSPA_IS_HINT_DEFAULT_100 (desc)) return ParameterValue (100.0f, 0.5f); - if (LADSPA_IS_HINT_DEFAULT_440 (desc)) return ParameterValue (440.0f, 0.5f); - - const float scale = LADSPA_IS_HINT_SAMPLE_RATE (desc) ? (float) getSampleRate() : 1.0f; - const float lower = hint.LowerBound * scale; - const float upper = hint.UpperBound * scale; - - if (LADSPA_IS_HINT_BOUNDED_BELOW (desc) && LADSPA_IS_HINT_DEFAULT_MINIMUM (desc)) return ParameterValue (lower, 0.0f); - if (LADSPA_IS_HINT_BOUNDED_ABOVE (desc) && LADSPA_IS_HINT_DEFAULT_MAXIMUM (desc)) return ParameterValue (upper, 1.0f); - - if (LADSPA_IS_HINT_BOUNDED_BELOW (desc)) - { - const bool useLog = LADSPA_IS_HINT_LOGARITHMIC (desc); - - if (LADSPA_IS_HINT_DEFAULT_LOW (desc)) return ParameterValue (scaledValue (lower, upper, 0.25f, useLog), 0.25f); - if (LADSPA_IS_HINT_DEFAULT_MIDDLE (desc)) return ParameterValue (scaledValue (lower, upper, 0.50f, useLog), 0.50f); - if (LADSPA_IS_HINT_DEFAULT_HIGH (desc)) return ParameterValue (scaledValue (lower, upper, 0.75f, useLog), 0.75f); - } - } - - return ParameterValue(); - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LADSPAPluginInstance) -}; - - -//============================================================================== -//============================================================================== -LADSPAPluginFormat::LADSPAPluginFormat() {} -LADSPAPluginFormat::~LADSPAPluginFormat() {} - -void LADSPAPluginFormat::findAllTypesForFile (OwnedArray & results, - const String& fileOrIdentifier) -{ - if (! fileMightContainThisPluginType (fileOrIdentifier)) - return; - - PluginDescription desc; - desc.fileOrIdentifier = fileOrIdentifier; - desc.uid = 0; - - ScopedPointer instance (dynamic_cast (createInstanceFromDescription (desc, 44100.0, 512))); - - if (instance == nullptr || ! instance->isValid()) - return; - - instance->initialise (44100.0, 512); - - instance->fillInPluginDescription (desc); - - if (instance->module->moduleMain != nullptr) - { - for (int uid = 0;; ++uid) - { - if (const LADSPA_Descriptor* plugin = instance->module->moduleMain (uid)) - { - desc.uid = uid; - desc.name = plugin->Name != nullptr ? plugin->Name : "Unknown"; - - if (! arrayContainsPlugin (results, desc)) - results.add (new PluginDescription (desc)); - } - else - { - break; - } - } - } -} - -void LADSPAPluginFormat::createPluginInstance (const PluginDescription& desc, - double sampleRate, int blockSize, - void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) -{ - ScopedPointer result; - - - if (fileMightContainThisPluginType (desc.fileOrIdentifier)) - { - File file (desc.fileOrIdentifier); - - const File previousWorkingDirectory (File::getCurrentWorkingDirectory()); - file.getParentDirectory().setAsCurrentWorkingDirectory(); - - const LADSPAModuleHandle::Ptr module (LADSPAModuleHandle::findOrCreateModule (file)); - - if (module != nullptr) - { - shellLADSPAUIDToCreate = desc.uid; - - result = new LADSPAPluginInstance (module); - - if (result->plugin != nullptr && result->isValid()) - result->initialise (sampleRate, blockSize); - else - result = nullptr; - } - - previousWorkingDirectory.setAsCurrentWorkingDirectory(); - } - - String errorMsg; - - if (result == nullptr) - errorMsg = String (NEEDS_TRANS ("Unable to load XXX plug-in file")).replace ("XXX", "LADSPA"); - - callback (userData, result.release(), errorMsg); -} - -bool LADSPAPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept -{ - return false; -} - -bool LADSPAPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) -{ - const File f (File::createFileWithoutCheckingPath (fileOrIdentifier)); - return f.existsAsFile() && f.hasFileExtension (".so"); -} - -String LADSPAPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) -{ - return fileOrIdentifier; -} - -bool LADSPAPluginFormat::pluginNeedsRescanning (const PluginDescription& desc) -{ - return File (desc.fileOrIdentifier).getLastModificationTime() != desc.lastFileModTime; -} - -bool LADSPAPluginFormat::doesPluginStillExist (const PluginDescription& desc) -{ - return File::createFileWithoutCheckingPath (desc.fileOrIdentifier).exists(); -} - -StringArray LADSPAPluginFormat::searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive, bool) -{ - StringArray results; - - for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j) - recursiveFileSearch (results, directoriesToSearch[j], recursive); - - return results; -} - -void LADSPAPluginFormat::recursiveFileSearch (StringArray& results, const File& dir, const bool recursive) -{ - DirectoryIterator iter (dir, false, "*", File::findFilesAndDirectories); - - while (iter.next()) - { - const File f (iter.getFile()); - bool isPlugin = false; - - if (fileMightContainThisPluginType (f.getFullPathName())) - { - isPlugin = true; - results.add (f.getFullPathName()); - } - - if (recursive && (! isPlugin) && f.isDirectory()) - recursiveFileSearch (results, f, true); - } -} - -FileSearchPath LADSPAPluginFormat::getDefaultLocationsToSearch() -{ - return FileSearchPath (SystemStats::getEnvironmentVariable ("LADSPA_PATH", - "/usr/lib/ladspa;/usr/local/lib/ladspa;~/.ladspa") - .replace (":", ";")); -} - -} // namespace juce - -#endif diff --git a/source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.h b/source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.h deleted file mode 100644 index 7002c5181..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -#if (JUCE_PLUGINHOST_LADSPA && JUCE_LINUX) || DOXYGEN - -//============================================================================== -/** - Implements a plugin format manager for LADSPA plugins. -*/ -class JUCE_API LADSPAPluginFormat : public AudioPluginFormat -{ -public: - LADSPAPluginFormat(); - ~LADSPAPluginFormat(); - - //============================================================================== - String getName() const override { return "LADSPA"; } - void findAllTypesForFile (OwnedArray&, const String& fileOrIdentifier) override; - bool fileMightContainThisPluginType (const String& fileOrIdentifier) override; - String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override; - bool pluginNeedsRescanning (const PluginDescription&) override; - StringArray searchPathsForPlugins (const FileSearchPath&, bool recursive, bool) override; - bool doesPluginStillExist (const PluginDescription&) override; - FileSearchPath getDefaultLocationsToSearch() override; - bool canScanForPlugins() const override { return true; } - -private: - //============================================================================== - void createPluginInstance (const PluginDescription&, double initialSampleRate, - int initialBufferSize, void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) override; - - bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; - -private: - void recursiveFileSearch (StringArray&, const File&, bool recursive); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LADSPAPluginFormat) -}; - - -#endif - -} diff --git a/source/modules/juce_audio_processors/format_types/juce_VST3Common.h b/source/modules/juce_audio_processors/format_types/juce_VST3Common.h deleted file mode 100644 index 7ac3608ae..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ /dev/null @@ -1,633 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -#define JUCE_DECLARE_VST3_COM_REF_METHODS \ - Steinberg::uint32 PLUGIN_API addRef() override { return (Steinberg::uint32) ++refCount; } \ - Steinberg::uint32 PLUGIN_API release() override { const int r = --refCount; if (r == 0) delete this; return (Steinberg::uint32) r; } - -#define JUCE_DECLARE_VST3_COM_QUERY_METHODS \ - Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID, void** obj) override \ - { \ - jassertfalse; \ - *obj = nullptr; \ - return Steinberg::kNotImplemented; \ - } - -static bool doUIDsMatch (const Steinberg::TUID a, const Steinberg::TUID b) noexcept -{ - return std::memcmp (a, b, sizeof (Steinberg::TUID)) == 0; -} - -#define TEST_FOR_AND_RETURN_IF_VALID(iidToTest, ClassType) \ - if (doUIDsMatch (iidToTest, ClassType::iid)) \ - { \ - addRef(); \ - *obj = dynamic_cast (this); \ - return Steinberg::kResultOk; \ - } - -#define TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID(iidToTest, CommonClassType, SourceClassType) \ - if (doUIDsMatch (iidToTest, CommonClassType::iid)) \ - { \ - addRef(); \ - *obj = (CommonClassType*) static_cast (this); \ - return Steinberg::kResultOk; \ - } - -//============================================================================== -inline juce::String toString (const Steinberg::char8* string) noexcept { return juce::String (string); } -inline juce::String toString (const Steinberg::char16* string) noexcept { return juce::String (juce::CharPointer_UTF16 ((juce::CharPointer_UTF16::CharType*) string)); } - -// NB: The casts are handled by a Steinberg::UString operator -inline juce::String toString (const Steinberg::UString128& string) noexcept { return toString (static_cast (string)); } -inline juce::String toString (const Steinberg::UString256& string) noexcept { return toString (static_cast (string)); } - -inline void toString128 (Steinberg::Vst::String128 result, const char* source) -{ - Steinberg::UString (result, 128).fromAscii (source); -} - -inline void toString128 (Steinberg::Vst::String128 result, const juce::String& source) -{ - Steinberg::UString (result, 128).fromAscii (source.toUTF8()); -} - -inline Steinberg::Vst::TChar* toString (const juce::String& source) noexcept -{ - return reinterpret_cast (source.toUTF16().getAddress()); -} - -#if JUCE_WINDOWS - static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeHWND; -#else - static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeNSView; -#endif - - -//============================================================================== -static inline Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg::Vst::IAudioProcessor* processor, - bool isInput, int busIndex) -{ - Steinberg::Vst::SpeakerArrangement arrangement = Steinberg::Vst::SpeakerArr::kEmpty; - - if (processor != nullptr) - processor->getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput, - (Steinberg::int32) busIndex, arrangement); - - return arrangement; -} - -/** For the sake of simplicity, there can only be 1 arrangement type per channel count. - i.e.: 4 channels == k31Cine OR k40Cine -*/ -static inline Steinberg::Vst::SpeakerArrangement getArrangementForNumChannels (int numChannels) noexcept -{ - using namespace Steinberg::Vst::SpeakerArr; - - switch (numChannels) - { - case 0: return kEmpty; - case 1: return kMono; - case 2: return kStereo; - case 3: return k30Cine; - case 4: return k31Cine; - case 5: return k50; - case 6: return k51; - case 7: return k61Cine; - case 8: return k71CineFullFront; - case 9: return k90; - case 10: return k91; - case 11: return k101; - case 12: return k111; - case 13: return k130; - case 14: return k131; - case 24: return (Steinberg::Vst::SpeakerArrangement) 1929904127; // k222 - default: break; - } - - jassert (numChannels >= 0); - - juce::BigInteger bi; - bi.setRange (0, jmin (numChannels, (int) (sizeof (Steinberg::Vst::SpeakerArrangement) * 8)), true); - return (Steinberg::Vst::SpeakerArrangement) bi.toInt64(); -} - -static inline Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set, AudioChannelSet::ChannelType type) noexcept -{ - using namespace Steinberg::Vst; - - switch (type) - { - case AudioChannelSet::left: return kSpeakerL; - case AudioChannelSet::right: return kSpeakerR; - case AudioChannelSet::centre: return (set == AudioChannelSet::mono() ? kSpeakerM : kSpeakerC); - - case AudioChannelSet::LFE: return kSpeakerLfe; - case AudioChannelSet::leftSurround: return kSpeakerLs; - case AudioChannelSet::rightSurround: return kSpeakerRs; - case AudioChannelSet::leftCentre: return kSpeakerLc; - case AudioChannelSet::rightCentre: return kSpeakerRc; - case AudioChannelSet::centreSurround: return kSpeakerCs; - case AudioChannelSet::leftSurroundSide: return (1 << 26); /* kSpeakerLcs */ - case AudioChannelSet::rightSurroundSide: return (1 << 27); /* kSpeakerRcs */ - case AudioChannelSet::topMiddle: return (1 << 11); /* kSpeakerTm */ - case AudioChannelSet::topFrontLeft: return kSpeakerTfl; - case AudioChannelSet::topFrontCentre: return kSpeakerTfc; - case AudioChannelSet::topFrontRight: return kSpeakerTfr; - case AudioChannelSet::topRearLeft: return kSpeakerTrl; - case AudioChannelSet::topRearCentre: return kSpeakerTrc; - case AudioChannelSet::topRearRight: return kSpeakerTrr; - case AudioChannelSet::LFE2: return kSpeakerLfe2; - case AudioChannelSet::leftSurroundRear: return kSpeakerSl; - case AudioChannelSet::rightSurroundRear: return kSpeakerSr; - case AudioChannelSet::wideLeft: return kSpeakerPl; - case AudioChannelSet::wideRight: return kSpeakerPr; - case AudioChannelSet::ambisonicW: return (1 << 20); /* kSpeakerW */ - case AudioChannelSet::ambisonicX: return (1 << 21); /* kSpeakerX */ - case AudioChannelSet::ambisonicY: return (1 << 22); /* kSpeakerY */ - case AudioChannelSet::ambisonicZ: return (1 << 23); /* kSpeakerZ */ - case AudioChannelSet::topSideLeft: return (1 << 24); /* kSpeakerTsl */ - case AudioChannelSet::topSideRight: return (1 << 25); /* kSpeakerTsr */ - - case AudioChannelSet::discreteChannel0: return kSpeakerM; - default: - break; - } - - - switch (static_cast (type)) - { - case (int) AudioChannelSet::discreteChannel0 + 3: return (1 << 28); /* kSpeakerBfl */ - case (int) AudioChannelSet::discreteChannel0 + 4: return (1 << 29); /* kSpeakerBfc */ - case (int) AudioChannelSet::discreteChannel0 + 5: return (1 << 30); /* kSpeakerBfr */ - default: - break; - } - - auto channelIndex = static_cast (type) - (static_cast (AudioChannelSet::discreteChannel0) + 6ull); - return (1ull << (channelIndex + 33ull /* last speaker in vst layout + 1 */)); -} - -static inline AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::SpeakerArrangement arr, Steinberg::Vst::Speaker type) noexcept -{ - using namespace Steinberg::Vst; - - switch (type) - { - case kSpeakerL: return AudioChannelSet::left; - case kSpeakerR: return AudioChannelSet::right; - case kSpeakerC: return AudioChannelSet::centre; - case kSpeakerLfe: return AudioChannelSet::LFE; - case kSpeakerLs: return AudioChannelSet::leftSurround; - case kSpeakerRs: return AudioChannelSet::rightSurround; - case kSpeakerLc: return AudioChannelSet::leftCentre; - case kSpeakerRc: return AudioChannelSet::rightCentre; - case kSpeakerCs: return AudioChannelSet::centreSurround; - case kSpeakerSl: return AudioChannelSet::leftSurroundRear; - case kSpeakerSr: return AudioChannelSet::rightSurroundRear; - case (1 << 11): return AudioChannelSet::topMiddle; /* kSpeakerTm */ - case kSpeakerTfl: return AudioChannelSet::topFrontLeft; - case kSpeakerTfc: return AudioChannelSet::topFrontCentre; - case kSpeakerTfr: return AudioChannelSet::topFrontRight; - case kSpeakerTrl: return AudioChannelSet::topRearLeft; - case kSpeakerTrc: return AudioChannelSet::topRearCentre; - case kSpeakerTrr: return AudioChannelSet::topRearRight; - case kSpeakerLfe2: return AudioChannelSet::LFE2; - case (1 << 19): return ((arr & kSpeakerC) != 0 ? AudioChannelSet::discreteChannel0 : AudioChannelSet::centre); - case (1 << 20): return AudioChannelSet::ambisonicW; /* kSpeakerW */ - case (1 << 21): return AudioChannelSet::ambisonicX; /* kSpeakerX */ - case (1 << 22): return AudioChannelSet::ambisonicY; /* kSpeakerY */ - case (1 << 23): return AudioChannelSet::ambisonicZ; /* kSpeakerZ */ - case (1 << 24): return AudioChannelSet::topSideLeft; /* kSpeakerTsl */ - case (1 << 25): return AudioChannelSet::topSideRight; /* kSpeakerTsr */ - case (1 << 26): return AudioChannelSet::leftSurroundSide; /* kSpeakerLcs */ - case (1 << 27): return AudioChannelSet::rightSurroundSide; /* kSpeakerRcs */ - case (1 << 28): return static_cast ((int)AudioChannelSet::discreteChannel0 + 3); /* kSpeakerBfl */ - case (1 << 29): return static_cast ((int)AudioChannelSet::discreteChannel0 + 4); /* kSpeakerBfc */ - case (1 << 30): return static_cast ((int)AudioChannelSet::discreteChannel0 + 5); /* kSpeakerBfr */ - case kSpeakerPl: return AudioChannelSet::wideLeft; - case kSpeakerPr: return AudioChannelSet::wideRight; - default: break; - } - - auto channelType = BigInteger (static_cast (type)).findNextSetBit (0); - - // VST3 <-> JUCE layout conversion error: report this bug to the JUCE forum - jassert (channelType >= 33); - - return static_cast (static_cast (AudioChannelSet::discreteChannel0) + 6 + (channelType - 33)); -} - -static inline Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (const AudioChannelSet& channels) noexcept -{ - using namespace Steinberg::Vst::SpeakerArr; - - if (channels == AudioChannelSet::disabled()) return kEmpty; - else if (channels == AudioChannelSet::mono()) return kMono; - else if (channels == AudioChannelSet::stereo()) return kStereo; - else if (channels == AudioChannelSet::createLCR()) return k30Cine; - else if (channels == AudioChannelSet::createLRS()) return k30Music; - else if (channels == AudioChannelSet::createLCRS()) return k40Cine; - else if (channels == AudioChannelSet::create5point0()) return k50; - else if (channels == AudioChannelSet::create5point1()) return k51; - else if (channels == AudioChannelSet::create6point0()) return k60Cine; - else if (channels == AudioChannelSet::create6point1()) return k61Cine; - else if (channels == AudioChannelSet::create6point0Music()) return k60Music; - else if (channels == AudioChannelSet::create6point1Music()) return k61Music; - else if (channels == AudioChannelSet::create7point0()) return k70Music; - else if (channels == AudioChannelSet::create7point0SDDS()) return k70Cine; - else if (channels == AudioChannelSet::create7point1()) return k71CineSideFill; - else if (channels == AudioChannelSet::create7point1SDDS()) return k71Cine; - else if (channels == AudioChannelSet::ambisonic()) return kBFormat; - else if (channels == AudioChannelSet::quadraphonic()) return k40Music; - else if (channels == AudioChannelSet::create7point0point2()) return k71_2 & ~(Steinberg::Vst::kSpeakerLfe); - else if (channels == AudioChannelSet::create7point1point2()) return k71_2; - - Steinberg::Vst::SpeakerArrangement result = 0; - - Array types (channels.getChannelTypes()); - - for (int i = 0; i < types.size(); ++i) - result |= getSpeakerType (channels, types.getReference(i)); - - return result; -} - -static inline AudioChannelSet getChannelSetForSpeakerArrangement (Steinberg::Vst::SpeakerArrangement arr) noexcept -{ - using namespace Steinberg::Vst::SpeakerArr; - - if (arr == kEmpty) return AudioChannelSet::disabled(); - else if (arr == kMono) return AudioChannelSet::mono(); - else if (arr == kStereo) return AudioChannelSet::stereo(); - else if (arr == k30Cine) return AudioChannelSet::createLCR(); - else if (arr == k30Music) return AudioChannelSet::createLRS(); - else if (arr == k40Cine) return AudioChannelSet::createLCRS(); - else if (arr == k50) return AudioChannelSet::create5point0(); - else if (arr == k51) return AudioChannelSet::create5point1(); - else if (arr == k60Cine) return AudioChannelSet::create6point0(); - else if (arr == k61Cine) return AudioChannelSet::create6point1(); - else if (arr == k60Music) return AudioChannelSet::create6point0Music(); - else if (arr == k61Music) return AudioChannelSet::create6point1Music(); - else if (arr == k70Music) return AudioChannelSet::create7point0(); - else if (arr == k70Cine) return AudioChannelSet::create7point0SDDS(); - else if (arr == k71CineSideFill) return AudioChannelSet::create7point1(); - else if (arr == k71Cine) return AudioChannelSet::create7point1SDDS(); - else if (arr == kBFormat) return AudioChannelSet::ambisonic(); - else if (arr == k40Music) return AudioChannelSet::quadraphonic(); - else if (arr == k71_2) return AudioChannelSet::create7point1point2(); - else if (arr == (k71_2 & ~(Steinberg::Vst::kSpeakerLfe))) return AudioChannelSet::create7point0point2(); - - AudioChannelSet result; - - BigInteger vstChannels (static_cast (arr)); - for (auto bit = vstChannels.findNextSetBit (0); bit != -1; bit = vstChannels.findNextSetBit (bit + 1)) - { - AudioChannelSet::ChannelType channelType = getChannelType (arr, 1ull << static_cast (bit)); - if (channelType != AudioChannelSet::unknown) - result.addChannel (channelType); - } - - // VST3 <-> JUCE layout conversion error: report this bug to the JUCE forum - jassert (result.size() == vstChannels.countNumberOfSetBits()); - - return result; -} - -//============================================================================== -template -class ComSmartPtr -{ -public: - ComSmartPtr() noexcept : source (nullptr) {} - ComSmartPtr (ObjectType* object, bool autoAddRef = true) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); } - ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); } - ~ComSmartPtr() { if (source != nullptr) source->release(); } - - operator ObjectType*() const noexcept { return source; } - ObjectType* get() const noexcept { return source; } - ObjectType& operator*() const noexcept { return *source; } - ObjectType* operator->() const noexcept { return source; } - - ComSmartPtr& operator= (const ComSmartPtr& other) { return operator= (other.source); } - - ComSmartPtr& operator= (ObjectType* const newObjectToTakePossessionOf) - { - ComSmartPtr p (newObjectToTakePossessionOf); - std::swap (p.source, source); - return *this; - } - - bool operator== (ObjectType* const other) noexcept { return source == other; } - bool operator!= (ObjectType* const other) noexcept { return source != other; } - - bool loadFrom (Steinberg::FUnknown* o) - { - *this = nullptr; - return o != nullptr && o->queryInterface (ObjectType::iid, (void**) &source) == Steinberg::kResultOk; - } - - bool loadFrom (Steinberg::IPluginFactory* factory, const Steinberg::TUID& uuid) - { - jassert (factory != nullptr); - *this = nullptr; - return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == Steinberg::kResultOk; - } - -private: - ObjectType* source; -}; - -//============================================================================== -class MidiEventList : public Steinberg::Vst::IEventList -{ -public: - MidiEventList() {} - virtual ~MidiEventList() {} - - JUCE_DECLARE_VST3_COM_REF_METHODS - JUCE_DECLARE_VST3_COM_QUERY_METHODS - - //============================================================================== - void clear() - { - events.clearQuick(); - } - - Steinberg::int32 PLUGIN_API getEventCount() override - { - return (Steinberg::int32) events.size(); - } - - // NB: This has to cope with out-of-range indexes from some plugins. - Steinberg::tresult PLUGIN_API getEvent (Steinberg::int32 index, Steinberg::Vst::Event& e) override - { - if (isPositiveAndBelow ((int) index, events.size())) - { - e = events.getReference ((int) index); - return Steinberg::kResultTrue; - } - - return Steinberg::kResultFalse; - } - - Steinberg::tresult PLUGIN_API addEvent (Steinberg::Vst::Event& e) override - { - events.add (e); - return Steinberg::kResultTrue; - } - - //============================================================================== - static void toMidiBuffer (MidiBuffer& result, Steinberg::Vst::IEventList& eventList) - { - const int32 numEvents = eventList.getEventCount(); - - for (Steinberg::int32 i = 0; i < numEvents; ++i) - { - Steinberg::Vst::Event e; - - if (eventList.getEvent (i, e) == Steinberg::kResultOk) - { - switch (e.type) - { - case Steinberg::Vst::Event::kNoteOnEvent: - result.addEvent (MidiMessage::noteOn (createSafeChannel (e.noteOn.channel), - createSafeNote (e.noteOn.pitch), - (Steinberg::uint8) denormaliseToMidiValue (e.noteOn.velocity)), - e.sampleOffset); - break; - - case Steinberg::Vst::Event::kNoteOffEvent: - result.addEvent (MidiMessage::noteOff (createSafeChannel (e.noteOff.channel), - createSafeNote (e.noteOff.pitch), - (Steinberg::uint8) denormaliseToMidiValue (e.noteOff.velocity)), - e.sampleOffset); - break; - - case Steinberg::Vst::Event::kPolyPressureEvent: - result.addEvent (MidiMessage::aftertouchChange (createSafeChannel (e.polyPressure.channel), - createSafeNote (e.polyPressure.pitch), - denormaliseToMidiValue (e.polyPressure.pressure)), - e.sampleOffset); - break; - - case Steinberg::Vst::Event::kDataEvent: - result.addEvent (MidiMessage::createSysExMessage (e.data.bytes, (int) e.data.size), - e.sampleOffset); - break; - - default: - break; - } - } - } - } - - static void toEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer) - { - MidiBuffer::Iterator iterator (midiBuffer); - MidiMessage msg; - int midiEventPosition = 0; - - enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once - int numEvents = 0; - - while (iterator.getNextEvent (msg, midiEventPosition)) - { - if (++numEvents > maxNumEvents) - break; - - Steinberg::Vst::Event e = { 0 }; - - if (msg.isNoteOn()) - { - e.type = Steinberg::Vst::Event::kNoteOnEvent; - e.noteOn.channel = createSafeChannel (msg.getChannel()); - e.noteOn.pitch = createSafeNote (msg.getNoteNumber()); - e.noteOn.velocity = normaliseMidiValue (msg.getVelocity()); - e.noteOn.length = 0; - e.noteOn.tuning = 0.0f; - e.noteOn.noteId = -1; - } - else if (msg.isNoteOff()) - { - e.type = Steinberg::Vst::Event::kNoteOffEvent; - e.noteOff.channel = createSafeChannel (msg.getChannel()); - e.noteOff.pitch = createSafeNote (msg.getNoteNumber()); - e.noteOff.velocity = normaliseMidiValue (msg.getVelocity()); - e.noteOff.tuning = 0.0f; - e.noteOff.noteId = -1; - } - else if (msg.isSysEx()) - { - e.type = Steinberg::Vst::Event::kDataEvent; - e.data.bytes = msg.getSysExData(); - e.data.size = (uint32) msg.getSysExDataSize(); - e.data.type = Steinberg::Vst::DataEvent::kMidiSysEx; - } - else if (msg.isAftertouch()) - { - e.type = Steinberg::Vst::Event::kPolyPressureEvent; - e.polyPressure.channel = createSafeChannel (msg.getChannel()); - e.polyPressure.pitch = createSafeNote (msg.getNoteNumber()); - e.polyPressure.pressure = normaliseMidiValue (msg.getAfterTouchValue()); - } - else - { - continue; - } - - e.busIndex = 0; - e.sampleOffset = midiEventPosition; - - result.addEvent (e); - } - } - -private: - Array events; - Atomic refCount; - - static Steinberg::int16 createSafeChannel (int channel) noexcept { return (Steinberg::int16) jlimit (0, 15, channel - 1); } - static int createSafeChannel (Steinberg::int16 channel) noexcept { return (int) jlimit (1, 16, channel + 1); } - - static Steinberg::int16 createSafeNote (int note) noexcept { return (Steinberg::int16) jlimit (0, 127, note); } - static int createSafeNote (Steinberg::int16 note) noexcept { return jlimit (0, 127, (int) note); } - - static float normaliseMidiValue (int value) noexcept { return jlimit (0.0f, 1.0f, (float) value / 127.0f); } - static int denormaliseToMidiValue (float value) noexcept { return roundToInt (jlimit (0.0f, 127.0f, value * 127.0f)); } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiEventList) -}; - -//============================================================================== -template -struct VST3BufferExchange -{ - typedef Array Bus; - typedef Array BusMap; - - static inline void assignRawPointer (Steinberg::Vst::AudioBusBuffers& vstBuffers, float** raw) { vstBuffers.channelBuffers32 = raw; } - static inline void assignRawPointer (Steinberg::Vst::AudioBusBuffers& vstBuffers, double** raw) { vstBuffers.channelBuffers64 = raw; } - - /** Assigns a series of AudioSampleBuffer's channels to an AudioBusBuffers' - - @warning For speed, does not check the channel count and offsets - according to the AudioSampleBuffer - */ - static void associateBufferTo (Steinberg::Vst::AudioBusBuffers& vstBuffers, - Bus& bus, - AudioBuffer& buffer, - int numChannels, int channelStartOffset, - int sampleOffset = 0) - { - const int channelEnd = numChannels + channelStartOffset; - jassert (channelEnd >= 0 && channelEnd <= buffer.getNumChannels()); - - bus.clearQuick(); - - for (int i = channelStartOffset; i < channelEnd; ++i) - bus.add (buffer.getWritePointer (i, sampleOffset)); - - assignRawPointer (vstBuffers, (numChannels > 0 ? bus.getRawDataPointer() : nullptr)); - vstBuffers.numChannels = numChannels; - vstBuffers.silenceFlags = 0; - } - - static void mapArrangementToBuses (int& channelIndexOffset, int index, - Array& result, - BusMap& busMapToUse, const AudioChannelSet& arrangement, - AudioBuffer& source) - { - const int numChansForBus = arrangement.size(); - - if (index >= result.size()) - result.add (Steinberg::Vst::AudioBusBuffers()); - - if (index >= busMapToUse.size()) - busMapToUse.add (Bus()); - - associateBufferTo (result.getReference (index), - busMapToUse.getReference (index), - source, numChansForBus, channelIndexOffset); - - channelIndexOffset += numChansForBus; - } - - static inline void mapBufferToBuses (Array& result, BusMap& busMapToUse, - const Array& arrangements, - AudioBuffer& source) - { - int channelIndexOffset = 0; - - for (int i = 0; i < arrangements.size(); ++i) - mapArrangementToBuses (channelIndexOffset, i, result, busMapToUse, - arrangements.getUnchecked (i), source); - } - - static inline void mapBufferToBuses (Array& result, - Steinberg::Vst::IAudioProcessor& processor, - BusMap& busMapToUse, bool isInput, int numBuses, - AudioBuffer& source) - { - int channelIndexOffset = 0; - - for (int i = 0; i < numBuses; ++i) - mapArrangementToBuses (channelIndexOffset, i, - result, busMapToUse, - getArrangementForBus (&processor, isInput, i), - source); - } -}; - -template -struct VST3FloatAndDoubleBusMapCompositeHelper {}; - -struct VST3FloatAndDoubleBusMapComposite -{ - VST3BufferExchange::BusMap floatVersion; - VST3BufferExchange::BusMap doubleVersion; - - template - inline typename VST3BufferExchange::BusMap& get() { return VST3FloatAndDoubleBusMapCompositeHelper::get (*this); } -}; - - -template <> struct VST3FloatAndDoubleBusMapCompositeHelper -{ - static inline VST3BufferExchange::BusMap& get (VST3FloatAndDoubleBusMapComposite& impl) { return impl.floatVersion; } -}; - -template <> struct VST3FloatAndDoubleBusMapCompositeHelper -{ - static inline VST3BufferExchange::BusMap& get (VST3FloatAndDoubleBusMapComposite& impl) { return impl.doubleVersion; } -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/format_types/juce_VST3Headers.h b/source/modules/juce_audio_processors/format_types/juce_VST3Headers.h deleted file mode 100644 index 6a68bc210..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VST3Headers.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -// Wow, those Steinberg guys really don't worry too much about compiler warnings. -#if _MSC_VER - #pragma warning (disable: 4505) - #pragma warning (push, 0) - #pragma warning (disable: 4702) -#elif __clang__ - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wnon-virtual-dtor" - #pragma clang diagnostic ignored "-Wreorder" - #pragma clang diagnostic ignored "-Wunsequenced" - #pragma clang diagnostic ignored "-Wint-to-pointer-cast" - #pragma clang diagnostic ignored "-Wunused-parameter" - #pragma clang diagnostic ignored "-Wconversion" - #pragma clang diagnostic ignored "-Woverloaded-virtual" - #pragma clang diagnostic ignored "-Wshadow" - #pragma clang diagnostic ignored "-Wdeprecated-register" - #pragma clang diagnostic ignored "-Wunused-function" - #pragma clang diagnostic ignored "-Wsign-conversion" - #pragma clang diagnostic ignored "-Wsign-compare" - #pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor" - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - #pragma clang diagnostic ignored "-Wextra-semi" -#endif - -#undef DEVELOPMENT -#define DEVELOPMENT 0 // This avoids a Clang warning in Steinberg code about unused values - -/* These files come with the Steinberg VST3 SDK - to get them, you'll need to - visit the Steinberg website and agree to whatever is currently required to - get them. - - Then, you'll need to make sure your include path contains your "VST3 SDK" - directory (or whatever you've named it on your machine). The Projucer has - a special box for setting this path. -*/ -#if JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include -#else - #if JUCE_MINGW - #define _set_abort_behavior(...) - #endif - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - -//============================================================================== -namespace Steinberg -{ - /** Missing IIDs */ - DEF_CLASS_IID (IPluginBase) - DEF_CLASS_IID (IPlugView) - DEF_CLASS_IID (IPlugFrame) - DEF_CLASS_IID (IBStream) - DEF_CLASS_IID (IPluginFactory) - DEF_CLASS_IID (IPluginFactory2) - DEF_CLASS_IID (IPluginFactory3) - DEF_CLASS_IID (IPlugViewContentScaleSupport) -} -#endif //JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY - -#if _MSC_VER - #pragma warning (pop) -#elif __clang__ - #pragma clang diagnostic pop -#endif - -#if JUCE_WINDOWS - #include -#endif - -//============================================================================== -#undef ASSERT -#undef WARNING -#undef PRINTSYSERROR -#undef DEBUGSTR -#undef DBPRT0 -#undef DBPRT1 -#undef DBPRT2 -#undef DBPRT3 -#undef DBPRT4 -#undef DBPRT5 -#undef min -#undef max -#undef MIN -#undef MAX -#undef calloc -#undef free -#undef malloc -#undef realloc -#undef NEW -#undef NEWVEC -#undef VERIFY -#undef VERIFY_IS -#undef VERIFY_NOT -#undef META_CREATE_FUNC -#undef CLASS_CREATE_FUNC -#undef SINGLE_CREATE_FUNC -#undef _META_CLASS -#undef _META_CLASS_IFACE -#undef _META_CLASS_SINGLE -#undef META_CLASS -#undef META_CLASS_IFACE -#undef META_CLASS_SINGLE -#undef SINGLETON -#undef OBJ_METHODS -#undef QUERY_INTERFACE -#undef LICENCE_UID -#undef BEGIN_FACTORY -#undef DEF_CLASS -#undef DEF_CLASS1 -#undef DEF_CLASS2 -#undef DEF_CLASS_W -#undef END_FACTORY diff --git a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp deleted file mode 100644 index 48ade86b5..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ /dev/null @@ -1,2983 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -#if JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS) - -#include -#include "juce_VST3Headers.h" -#include "juce_VST3Common.h" - -namespace juce -{ - -using namespace Steinberg; - -//============================================================================== -struct VST3Classes -{ - -#ifndef JUCE_VST3_DEBUGGING - #define JUCE_VST3_DEBUGGING 0 -#endif - -#if JUCE_VST3_DEBUGGING - #define VST3_DBG(a) Logger::writeToLog (a); -#else - #define VST3_DBG(a) -#endif - -#if JUCE_DEBUG -static int warnOnFailure (int result) noexcept -{ - const char* message = "Unknown result!"; - - switch (result) - { - case kResultOk: return result; - case kNotImplemented: message = "kNotImplemented"; break; - case kNoInterface: message = "kNoInterface"; break; - case kResultFalse: message = "kResultFalse"; break; - case kInvalidArgument: message = "kInvalidArgument"; break; - case kInternalError: message = "kInternalError"; break; - case kNotInitialized: message = "kNotInitialized"; break; - case kOutOfMemory: message = "kOutOfMemory"; break; - default: break; - } - - DBG (message); - return result; -} -#else - #define warnOnFailure(x) x -#endif - -//============================================================================== -static int getHashForTUID (const TUID& tuid) noexcept -{ - int value = 0; - - for (int i = 0; i < numElementsInArray (tuid); ++i) - value = (value * 31) + tuid[i]; - - return value; -} - -template -static void fillDescriptionWith (PluginDescription& description, ObjectType& object) -{ - description.version = toString (object.version).trim(); - description.category = toString (object.subCategories).trim(); - - if (description.manufacturerName.trim().isEmpty()) - description.manufacturerName = toString (object.vendor).trim(); -} - -static void createPluginDescription (PluginDescription& description, - const File& pluginFile, const String& company, const String& name, - const PClassInfo& info, PClassInfo2* info2, PClassInfoW* infoW, - int numInputs, int numOutputs) -{ - description.fileOrIdentifier = pluginFile.getFullPathName(); - description.lastFileModTime = pluginFile.getLastModificationTime(); - description.lastInfoUpdateTime = Time::getCurrentTime(); - description.manufacturerName = company; - description.name = name; - description.descriptiveName = name; - description.pluginFormatName = "VST3"; - description.numInputChannels = numInputs; - description.numOutputChannels = numOutputs; - description.uid = getHashForTUID (info.cid); - - if (infoW != nullptr) fillDescriptionWith (description, *infoW); - else if (info2 != nullptr) fillDescriptionWith (description, *info2); - - if (description.category.isEmpty()) - description.category = toString (info.category).trim(); - - description.isInstrument = description.category.containsIgnoreCase ("Instrument"); // This seems to be the only way to find that out! ARGH! -} - -static int getNumSingleDirectionBusesFor (Vst::IComponent* component, - bool checkInputs, - bool checkAudioChannels) -{ - jassert (component != nullptr); - - return (int) component->getBusCount (checkAudioChannels ? Vst::kAudio : Vst::kEvent, - checkInputs ? Vst::kInput : Vst::kOutput); -} - -/** Gives the total number of channels for a particular type of bus direction and media type */ -static int getNumSingleDirectionChannelsFor (Vst::IComponent* component, - bool checkInputs, - bool checkAudioChannels) -{ - jassert (component != nullptr); - - const Vst::BusDirections direction = checkInputs ? Vst::kInput : Vst::kOutput; - const Vst::MediaTypes mediaType = checkAudioChannels ? Vst::kAudio : Vst::kEvent; - const Steinberg::int32 numBuses = component->getBusCount (mediaType, direction); - - int numChannels = 0; - - for (Steinberg::int32 i = numBuses; --i >= 0;) - { - Vst::BusInfo busInfo; - warnOnFailure (component->getBusInfo (mediaType, direction, i, busInfo)); - numChannels += ((busInfo.flags & Vst::BusInfo::kDefaultActive) != 0 ? (int) busInfo.channelCount : 0); - } - - return numChannels; -} - -static void setStateForAllBusesOfType (Vst::IComponent* component, - bool state, - bool activateInputs, - bool activateAudioChannels) -{ - jassert (component != nullptr); - - const Vst::BusDirections direction = activateInputs ? Vst::kInput : Vst::kOutput; - const Vst::MediaTypes mediaType = activateAudioChannels ? Vst::kAudio : Vst::kEvent; - const Steinberg::int32 numBuses = component->getBusCount (mediaType, direction); - - for (Steinberg::int32 i = numBuses; --i >= 0;) - warnOnFailure (component->activateBus (mediaType, direction, i, state)); -} - -//============================================================================== -/** Assigns a complete AudioSampleBuffer's channels to an AudioBusBuffers' */ -static void associateWholeBufferTo (Vst::AudioBusBuffers& vstBuffers, AudioSampleBuffer& buffer) noexcept -{ - vstBuffers.channelBuffers32 = buffer.getArrayOfWritePointers(); - vstBuffers.numChannels = buffer.getNumChannels(); - vstBuffers.silenceFlags = 0; -} - -//============================================================================== -static void toProcessContext (Vst::ProcessContext& context, AudioPlayHead* playHead, double sampleRate) -{ - jassert (sampleRate > 0.0); //Must always be valid, as stated by the VST3 SDK - - using namespace Vst; - - zerostruct (context); - context.sampleRate = sampleRate; - auto& fr = context.frameRate; - - if (playHead != nullptr) - { - AudioPlayHead::CurrentPositionInfo position; - playHead->getCurrentPosition (position); - - context.projectTimeSamples = position.timeInSamples; //Must always be valid, as stated by the VST3 SDK - context.projectTimeMusic = position.timeInSeconds; //Does not always need to be valid... - context.tempo = position.bpm; - context.timeSigNumerator = position.timeSigNumerator; - context.timeSigDenominator = position.timeSigDenominator; - context.barPositionMusic = position.ppqPositionOfLastBarStart; - context.cycleStartMusic = position.ppqLoopStart; - context.cycleEndMusic = position.ppqLoopEnd; - - switch (position.frameRate) - { - case AudioPlayHead::fps23976: fr.framesPerSecond = 24; fr.flags = FrameRate::kPullDownRate; break; - case AudioPlayHead::fps24: fr.framesPerSecond = 24; fr.flags = 0; break; - case AudioPlayHead::fps25: fr.framesPerSecond = 25; fr.flags = 0; break; - case AudioPlayHead::fps2997: fr.framesPerSecond = 30; fr.flags = FrameRate::kPullDownRate; break; - case AudioPlayHead::fps2997drop: fr.framesPerSecond = 30; fr.flags = FrameRate::kPullDownRate | FrameRate::kDropRate; break; - case AudioPlayHead::fps30: fr.framesPerSecond = 30; fr.flags = 0; break; - case AudioPlayHead::fps30drop: fr.framesPerSecond = 30; fr.flags = FrameRate::kDropRate; break; - case AudioPlayHead::fps60: fr.framesPerSecond = 60; fr.flags = 0; break; - case AudioPlayHead::fps60drop: fr.framesPerSecond = 60; fr.flags = FrameRate::kDropRate; break; - case AudioPlayHead::fpsUnknown: break; - default: jassertfalse; break; // New frame rate? - } - - if (position.isPlaying) context.state |= ProcessContext::kPlaying; - if (position.isRecording) context.state |= ProcessContext::kRecording; - if (position.isLooping) context.state |= ProcessContext::kCycleActive; - } - else - { - context.tempo = 120.0; - context.timeSigNumerator = 4; - context.timeSigDenominator = 4; - fr.framesPerSecond = 30; - fr.flags = 0; - } - - if (context.projectTimeMusic >= 0.0) context.state |= ProcessContext::kProjectTimeMusicValid; - if (context.barPositionMusic >= 0.0) context.state |= ProcessContext::kBarPositionValid; - if (context.tempo > 0.0) context.state |= ProcessContext::kTempoValid; - if (context.frameRate.framesPerSecond > 0) context.state |= ProcessContext::kSmpteValid; - - if (context.cycleStartMusic >= 0.0 - && context.cycleEndMusic > 0.0 - && context.cycleEndMusic > context.cycleStartMusic) - { - context.state |= ProcessContext::kCycleValid; - } - - if (context.timeSigNumerator > 0 && context.timeSigDenominator > 0) - context.state |= ProcessContext::kTimeSigValid; -} - -//============================================================================== -/** Get a list of speaker arrangements as per their speaker names - - (e.g.: 2 regular channels, aliased as 'kStringStereoS', is "L R") -*/ -static StringArray getSpeakerArrangements() -{ - using namespace Vst::SpeakerArr; - - const Vst::CString arrangements[] = - { - kStringMonoS, kStringStereoS, kStringStereoRS, kStringStereoCS, - kStringStereoSS, kStringStereoCLfeS, kString30CineS, kString30MusicS, - kString31CineS, kString31MusicS, kString40CineS, kString40MusicS, - kString41CineS, kString41MusicS, kString50S, kString51S, - kString60CineS, kString60MusicS, kString61CineS, kString61MusicS, - kString70CineS, kString70MusicS, kString71CineS, kString71MusicS, - kString80CineS, kString80MusicS, kString81CineS, kString81MusicS, - kString80CubeS, kStringBFormat1stOrderS, kString71CineTopCenterS, - kString71CineCenterHighS, kString71CineFrontHighS, kString71CineSideHighS, - kString71CineFullRearS, kString90S, kString91S, - kString100S, kString101S, kString110S, kString111S, - kString130S, kString131S, kString102S, kString122S, - nullptr - }; - - return StringArray (arrangements); -} - -/** Get a list of speaker arrangements as per their named configurations - - (e.g.: 2 regular channels, aliased as 'kStringStereoS', is "L R") -*/ -static StringArray getNamedSpeakerArrangements() -{ - using namespace Vst::SpeakerArr; - - const Vst::CString arrangements[] = - { - kStringEmpty, kStringMono, kStringStereo, kStringStereoR, - kStringStereoC, kStringStereoSide, kStringStereoCLfe, kString30Cine, - kString30Music, kString31Cine, kString31Music, kString40Cine, - kString40Music, kString41Cine, kString41Music, kString50, - kString51, kString60Cine, kString60Music, kString61Cine, - kString61Music, kString70Cine, kString70Music, kString71Cine, - kString71Music, kString71CineTopCenter, kString71CineCenterHigh, - kString71CineFrontHigh, kString71CineSideHigh, kString71CineFullRear, - kString80Cine, kString80Music, kString80Cube, kString81Cine, - kString81Music, kString102, kString122, kString90, - kString91, kString100, kString101, kString110, - kString111, kString130, kString131, - nullptr - }; - - return StringArray (arrangements); -} - -static Vst::SpeakerArrangement getSpeakerArrangementFrom (const String& string) -{ - return Vst::SpeakerArr::getSpeakerArrangementFromString (string.toUTF8()); -} - -//============================================================================== -static StringArray getPluginEffectCategories() -{ - using namespace Vst::PlugType; - - const Vst::CString categories[] = - { - kFxAnalyzer, kFxDelay, kFxDistortion, kFxDynamics, - kFxEQ, kFxFilter, kFx, kFxInstrument, - kFxInstrumentExternal, kFxSpatial, kFxGenerator, kFxMastering, - kFxModulation, kFxPitchShift, kFxRestoration, kFxReverb, - kFxSurround, kFxTools, kSpatial, kSpatialFx, - nullptr - }; - - return StringArray (categories); -} - -static StringArray getPluginInstrumentCategories() -{ - using namespace Vst::PlugType; - - const Vst::CString categories[] = - { - kInstrumentSynthSampler, kInstrumentDrum, - kInstrumentSampler, kInstrumentSynth, - kInstrumentExternal, kFxInstrument, - kFxInstrumentExternal, kFxSpatial, - kFxGenerator, - nullptr - }; - - return StringArray (categories); -} - -//============================================================================== -struct VST3PluginInstance; - -struct VST3HostContext : public Vst::IComponentHandler, // From VST V3.0.0 - public Vst::IComponentHandler2, // From VST V3.1.0 (a very well named class, of course!) - public Vst::IComponentHandler3, // From VST V3.5.0 (also very well named!) - public Vst::IContextMenuTarget, - public Vst::IHostApplication, - public Vst::IUnitHandler -{ - VST3HostContext() - { - appName = File::getSpecialLocation (File::currentApplicationFile).getFileNameWithoutExtension(); - attributeList = new AttributeList (this); - } - - virtual ~VST3HostContext() {} - - JUCE_DECLARE_VST3_COM_REF_METHODS - - FUnknown* getFUnknown() { return static_cast (this); } - - static bool hasFlag (Steinberg::int32 source, Steinberg::int32 flag) noexcept - { - return (source & flag) == flag; - } - - //============================================================================== - tresult PLUGIN_API beginEdit (Vst::ParamID paramID) override - { - if (plugin != nullptr) - { - auto index = getIndexOfParamID (paramID); - - if (index < 0) - return kResultFalse; - - plugin->beginParameterChangeGesture (index); - } - - return kResultTrue; - } - - tresult PLUGIN_API performEdit (Vst::ParamID paramID, Vst::ParamValue valueNormalized) override - { - if (plugin != nullptr) - { - auto index = getIndexOfParamID (paramID); - - if (index < 0) - return kResultFalse; - - plugin->sendParamChangeMessageToListeners (index, (float) valueNormalized); - - { - Steinberg::int32 eventIndex; - plugin->inputParameterChanges->addParameterData (paramID, eventIndex)->addPoint (0, valueNormalized, eventIndex); - } - - // did the plug-in already update the parameter internally - if (plugin->editController->getParamNormalized (paramID) != (float) valueNormalized) - return plugin->editController->setParamNormalized (paramID, valueNormalized); - } - - return kResultTrue; - } - - tresult PLUGIN_API endEdit (Vst::ParamID paramID) override - { - if (plugin != nullptr) - { - auto index = getIndexOfParamID (paramID); - - if (index < 0) - return kResultFalse; - - plugin->endParameterChangeGesture (index); - } - - return kResultTrue; - } - - tresult PLUGIN_API restartComponent (Steinberg::int32 flags) override - { - if (plugin != nullptr) - { - if (hasFlag (flags, Vst::kReloadComponent)) - plugin->reset(); - - if (hasFlag (flags, Vst::kIoChanged)) - { - auto sampleRate = plugin->getSampleRate(); - auto blockSize = plugin->getBlockSize(); - - plugin->prepareToPlay (sampleRate >= 8000 ? sampleRate : 44100.0, - blockSize > 0 ? blockSize : 1024); - } - - if (hasFlag (flags, Vst::kLatencyChanged)) - if (plugin->processor != nullptr) - plugin->setLatencySamples (jmax (0, (int) plugin->processor->getLatencySamples())); - - plugin->updateHostDisplay(); - return kResultTrue; - } - - jassertfalse; - return kResultFalse; - } - - //============================================================================== - tresult PLUGIN_API setDirty (TBool) override - { - return kResultFalse; - } - - tresult PLUGIN_API requestOpenEditor (FIDString name) override - { - ignoreUnused (name); - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API startGroupEdit() override - { - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API finishGroupEdit() override - { - jassertfalse; - return kResultFalse; - } - - void setPlugin (VST3PluginInstance* instance) - { - jassert (plugin == nullptr); - plugin = instance; - } - - //============================================================================== - struct ContextMenu : public Vst::IContextMenu - { - ContextMenu (VST3PluginInstance& pluginInstance) : owner (pluginInstance) {} - virtual ~ContextMenu() {} - - JUCE_DECLARE_VST3_COM_REF_METHODS - JUCE_DECLARE_VST3_COM_QUERY_METHODS - - Steinberg::int32 PLUGIN_API getItemCount() override { return (Steinberg::int32) items.size(); } - - tresult PLUGIN_API addItem (const Item& item, IContextMenuTarget* target) override - { - jassert (target != nullptr); - - ItemAndTarget newItem; - newItem.item = item; - newItem.target = target; - - items.add (newItem); - return kResultOk; - } - - tresult PLUGIN_API removeItem (const Item& toRemove, IContextMenuTarget* target) override - { - for (int i = items.size(); --i >= 0;) - { - auto& item = items.getReference(i); - - if (item.item.tag == toRemove.tag && item.target == target) - items.remove (i); - } - - return kResultOk; - } - - tresult PLUGIN_API getItem (Steinberg::int32 tag, Item& result, IContextMenuTarget** target) override - { - for (int i = 0; i < items.size(); ++i) - { - auto& item = items.getReference(i); - - if (item.item.tag == tag) - { - result = item.item; - - if (target != nullptr) - *target = item.target; - - return kResultTrue; - } - } - - zerostruct (result); - return kResultFalse; - } - - tresult PLUGIN_API popup (Steinberg::UCoord x, Steinberg::UCoord y) override - { - Array subItemStack; - OwnedArray menuStack; - PopupMenu* topLevelMenu = menuStack.add (new PopupMenu()); - - for (int i = 0; i < items.size(); ++i) - { - auto& item = items.getReference (i).item; - auto* menuToUse = menuStack.getLast(); - - if (hasFlag (item.flags, Item::kIsGroupStart & ~Item::kIsDisabled)) - { - subItemStack.add (&item); - menuStack.add (new PopupMenu()); - } - else if (hasFlag (item.flags, Item::kIsGroupEnd)) - { - if (auto* subItem = subItemStack.getLast()) - { - if (auto* m = menuStack [menuStack.size() - 2]) - m->addSubMenu (toString (subItem->name), *menuToUse, - ! hasFlag (subItem->flags, Item::kIsDisabled), - nullptr, - hasFlag (subItem->flags, Item::kIsChecked)); - - menuStack.removeLast (1); - subItemStack.removeLast (1); - } - } - else if (hasFlag (item.flags, Item::kIsSeparator)) - { - menuToUse->addSeparator(); - } - else - { - menuToUse->addItem (item.tag != 0 ? (int) item.tag : (int) zeroTagReplacement, - toString (item.name), - ! hasFlag (item.flags, Item::kIsDisabled), - hasFlag (item.flags, Item::kIsChecked)); - } - } - - PopupMenu::Options options; - - if (auto* ed = owner.getActiveEditor()) - options = options.withTargetScreenArea (ed->getScreenBounds().translated ((int) x, (int) y).withSize (1, 1)); - - #if JUCE_MODAL_LOOPS_PERMITTED - // Unfortunately, Steinberg's docs explicitly say this should be modal.. - handleResult (topLevelMenu->showMenu (options)); - #else - topLevelMenu->showMenuAsync (options, ModalCallbackFunction::create (menuFinished, ComSmartPtr (this))); - #endif - - return kResultOk; - } - - #if ! JUCE_MODAL_LOOPS_PERMITTED - static void menuFinished (int modalResult, ComSmartPtr menu) { menu->handleResult (modalResult); } - #endif - - private: - enum { zeroTagReplacement = 0x7fffffff }; - - Atomic refCount; - VST3PluginInstance& owner; - - struct ItemAndTarget - { - Item item; - ComSmartPtr target; - }; - - Array items; - - void handleResult (int result) - { - if (result == 0) - return; - - if (result == zeroTagReplacement) - result = 0; - - for (int i = 0; i < items.size(); ++i) - { - auto& item = items.getReference(i); - - if ((int) item.item.tag == result) - { - if (item.target != nullptr) - item.target->executeMenuItem ((Steinberg::int32) result); - - break; - } - } - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContextMenu) - }; - - Vst::IContextMenu* PLUGIN_API createContextMenu (IPlugView*, const Vst::ParamID*) override - { - if (plugin != nullptr) - return new ContextMenu (*plugin); - - return nullptr; - } - - tresult PLUGIN_API executeMenuItem (Steinberg::int32) override - { - jassertfalse; - return kResultFalse; - } - - //============================================================================== - tresult PLUGIN_API getName (Vst::String128 name) override - { - Steinberg::String str (appName.toUTF8()); - str.copyTo (name, 0, 127); - return kResultOk; - } - - tresult PLUGIN_API createInstance (TUID cid, TUID iid, void** obj) override - { - *obj = nullptr; - - if (! doUIDsMatch (cid, iid)) - { - jassertfalse; - return kInvalidArgument; - } - - if (doUIDsMatch (cid, Vst::IMessage::iid) && doUIDsMatch (iid, Vst::IMessage::iid)) - { - ComSmartPtr m (new Message (attributeList)); - messageQueue.add (m); - m->addRef(); - *obj = m; - return kResultOk; - } - else if (doUIDsMatch (cid, Vst::IAttributeList::iid) && doUIDsMatch (iid, Vst::IAttributeList::iid)) - { - ComSmartPtr l (new AttributeList (this)); - l->addRef(); - *obj = l; - return kResultOk; - } - - jassertfalse; - return kNotImplemented; - } - - //============================================================================== - tresult PLUGIN_API notifyUnitSelection (Vst::UnitID) override - { - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API notifyProgramListChange (Vst::ProgramListID, Steinberg::int32) override - { - if (plugin != nullptr) - plugin->syncProgramNames(); - - return kResultTrue; - } - - //============================================================================== - tresult PLUGIN_API queryInterface (const TUID iid, void** obj) override - { - if (doUIDsMatch (iid, Vst::IAttributeList::iid)) - { - *obj = attributeList.get(); - return kResultOk; - } - - TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IComponentHandler) - TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IComponentHandler2) - TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IComponentHandler3) - TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IContextMenuTarget) - TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IHostApplication) - TEST_FOR_AND_RETURN_IF_VALID (iid, Vst::IUnitHandler) - TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (iid, FUnknown, Vst::IComponentHandler) - - *obj = nullptr; - return kNotImplemented; - } - -private: - //============================================================================== - VST3PluginInstance* plugin = nullptr; - Atomic refCount; - String appName; - - typedef std::map ParamMapType; - ParamMapType paramToIndexMap; - - int getIndexOfParamID (Vst::ParamID paramID) - { - if (plugin == nullptr || plugin->editController == nullptr) - return -1; - - auto result = getMappedParamID (paramID); - - if (result < 0) - { - auto numParams = plugin->editController->getParameterCount(); - - for (int i = 0; i < numParams; ++i) - { - Vst::ParameterInfo paramInfo; - plugin->editController->getParameterInfo (i, paramInfo); - paramToIndexMap[paramInfo.id] = i; - } - - result = getMappedParamID (paramID); - } - - return result; - } - - int getMappedParamID (Vst::ParamID paramID) - { - auto it = paramToIndexMap.find (paramID); - return it != paramToIndexMap.end() ? it->second : -1; - } - - //============================================================================== - struct Message : public Vst::IMessage - { - Message (Vst::IAttributeList* list) - : attributeList (list) - { - } - - Message (Vst::IAttributeList* list, FIDString id) - : attributeList (list), messageId (toString (id)) - { - } - - Message (Vst::IAttributeList* list, FIDString id, const var& v) - : value (v), attributeList (list), messageId (toString (id)) - { - } - - virtual ~Message() {} - - JUCE_DECLARE_VST3_COM_REF_METHODS - JUCE_DECLARE_VST3_COM_QUERY_METHODS - - FIDString PLUGIN_API getMessageID() override { return messageId.toRawUTF8(); } - void PLUGIN_API setMessageID (FIDString id) override { messageId = toString (id); } - Vst::IAttributeList* PLUGIN_API getAttributes() override { return attributeList; } - - var value; - - private: - ComSmartPtr attributeList; - String messageId; - Atomic refCount; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message) - }; - - Array, CriticalSection> messageQueue; - - //============================================================================== - struct AttributeList : public Vst::IAttributeList - { - AttributeList (VST3HostContext* o) : owner (o) {} - virtual ~AttributeList() {} - - JUCE_DECLARE_VST3_COM_REF_METHODS - JUCE_DECLARE_VST3_COM_QUERY_METHODS - - //============================================================================== - tresult PLUGIN_API setInt (AttrID id, Steinberg::int64 value) override - { - addMessageToQueue (id, value); - return kResultTrue; - } - - tresult PLUGIN_API setFloat (AttrID id, double value) override - { - addMessageToQueue (id, value); - return kResultTrue; - } - - tresult PLUGIN_API setString (AttrID id, const Vst::TChar* string) override - { - addMessageToQueue (id, toString (string)); - return kResultTrue; - } - - tresult PLUGIN_API setBinary (AttrID id, const void* data, Steinberg::uint32 size) override - { - jassert (size >= 0 && (data != nullptr || size == 0)); - addMessageToQueue (id, MemoryBlock (data, (size_t) size)); - return kResultTrue; - } - - //============================================================================== - tresult PLUGIN_API getInt (AttrID id, Steinberg::int64& result) override - { - jassert (id != nullptr); - - if (findMessageOnQueueWithID (id, result)) - return kResultTrue; - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API getFloat (AttrID id, double& result) override - { - jassert (id != nullptr); - - if (findMessageOnQueueWithID (id, result)) - return kResultTrue; - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API getString (AttrID id, Vst::TChar* result, Steinberg::uint32 length) override - { - jassert (id != nullptr); - - String stringToFetch; - if (findMessageOnQueueWithID (id, stringToFetch)) - { - Steinberg::String str (stringToFetch.toRawUTF8()); - str.copyTo (result, 0, (Steinberg::int32) jmin (length, (Steinberg::uint32) std::numeric_limits::max())); - - return kResultTrue; - } - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API getBinary (AttrID id, const void*& data, Steinberg::uint32& size) override - { - jassert (id != nullptr); - - for (auto&& m : owner->messageQueue) - { - if (std::strcmp (m->getMessageID(), id) == 0) - { - if (auto* binaryData = m->value.getBinaryData()) - { - data = binaryData->getData(); - size = (Steinberg::uint32) binaryData->getSize(); - return kResultTrue; - } - } - } - - return kResultFalse; - } - - private: - VST3HostContext* owner; - Atomic refCount; - - //============================================================================== - template - void addMessageToQueue (AttrID id, const Type& value) - { - jassert (id != nullptr); - - for (auto&& m : owner->messageQueue) - { - if (std::strcmp (m->getMessageID(), id) == 0) - { - m->value = value; - return; - } - } - - owner->messageQueue.add (ComSmartPtr (new Message (this, id, value))); - } - - template - bool findMessageOnQueueWithID (AttrID id, Type& value) - { - jassert (id != nullptr); - - for (auto&& m : owner->messageQueue) - { - if (std::strcmp (m->getMessageID(), id) == 0) - { - value = m->value; - return true; - } - } - - return false; - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AttributeList) - }; - - ComSmartPtr attributeList; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3HostContext) -}; - -//============================================================================== -struct DescriptionFactory -{ - DescriptionFactory (VST3HostContext* host, IPluginFactory* pluginFactory) - : vst3HostContext (host), factory (pluginFactory) - { - jassert (pluginFactory != nullptr); - } - - virtual ~DescriptionFactory() {} - - Result findDescriptionsAndPerform (const File& file) - { - StringArray foundNames; - PFactoryInfo factoryInfo; - factory->getFactoryInfo (&factoryInfo); - auto companyName = toString (factoryInfo.vendor).trim(); - - Result result (Result::ok()); - - auto numClasses = factory->countClasses(); - - for (Steinberg::int32 i = 0; i < numClasses; ++i) - { - PClassInfo info; - factory->getClassInfo (i, &info); - - if (std::strcmp (info.category, kVstAudioEffectClass) != 0) - continue; - - const String name (toString (info.name).trim()); - - if (foundNames.contains (name, true)) - continue; - - ScopedPointer info2; - ScopedPointer infoW; - - { - ComSmartPtr pf2; - ComSmartPtr pf3; - - if (pf2.loadFrom (factory)) - { - info2 = new PClassInfo2(); - pf2->getClassInfo2 (i, info2); - } - - if (pf3.loadFrom (factory)) - { - infoW = new PClassInfoW(); - pf3->getClassInfoUnicode (i, infoW); - } - } - - foundNames.add (name); - - PluginDescription desc; - - { - ComSmartPtr component; - - if (component.loadFrom (factory, info.cid)) - { - if (component->initialize (vst3HostContext->getFUnknown()) == kResultOk) - { - auto numInputs = getNumSingleDirectionChannelsFor (component, true, true); - auto numOutputs = getNumSingleDirectionChannelsFor (component, false, true); - - createPluginDescription (desc, file, companyName, name, - info, info2, infoW, numInputs, numOutputs); - - component->terminate(); - } - else - { - jassertfalse; - } - } - else - { - jassertfalse; - } - } - - result = performOnDescription (desc); - - if (result.failed()) - break; - } - - return result; - } - - virtual Result performOnDescription (PluginDescription&) = 0; - -private: - ComSmartPtr vst3HostContext; - ComSmartPtr factory; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DescriptionFactory) -}; - -struct MatchingDescriptionFinder : public DescriptionFactory -{ - MatchingDescriptionFinder (VST3HostContext* h, IPluginFactory* f, const PluginDescription& desc) - : DescriptionFactory (h, f), description (desc) - { - } - - static const char* getSuccessString() noexcept { return "Found Description"; } - - Result performOnDescription (PluginDescription& desc) - { - if (description.isDuplicateOf (desc)) - return Result::fail (getSuccessString()); - - return Result::ok(); - } - -private: - const PluginDescription& description; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MatchingDescriptionFinder) -}; - -struct DescriptionLister : public DescriptionFactory -{ - DescriptionLister (VST3HostContext* host, IPluginFactory* pluginFactory) - : DescriptionFactory (host, pluginFactory) - { - } - - Result performOnDescription (PluginDescription& desc) - { - list.add (new PluginDescription (desc)); - return Result::ok(); - } - - OwnedArray list; - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DescriptionLister) -}; - -//============================================================================== -struct DLLHandle -{ - DLLHandle (const String& modulePath) - { - if (modulePath.trim().isNotEmpty()) - open (modulePath); - } - - ~DLLHandle() - { - typedef bool (PLUGIN_API *ExitModuleFn) (); - - #if JUCE_WINDOWS - releaseFactory(); - - if (auto exitFn = (ExitModuleFn) getFunction ("ExitDll")) - exitFn(); - - library.close(); - - #else - if (bundleRef != nullptr) - { - releaseFactory(); - - if (auto exitFn = (ExitModuleFn) getFunction ("bundleExit")) - exitFn(); - - CFRelease (bundleRef); - bundleRef = nullptr; - } - #endif - } - - void open (const PluginDescription& description) - { - #if JUCE_WINDOWS - jassert (description.fileOrIdentifier.isNotEmpty()); - jassert (File (description.fileOrIdentifier).existsAsFile()); - library.open (description.fileOrIdentifier); - #else - open (description.fileOrIdentifier); - #endif - } - - /** @note The factory should begin with a refCount of 1, - so don't increment the reference count - (ie: don't use a ComSmartPtr in here)! - Its lifetime will be handled by this DllHandle, - when such will be destroyed. - - @see releaseFactory - */ - IPluginFactory* JUCE_CALLTYPE getPluginFactory() - { - if (factory == nullptr) - if (auto proc = (GetFactoryProc) getFunction ("GetPluginFactory")) - factory = proc(); - - // The plugin NEEDS to provide a factory to be able to be called a VST3! - // Most likely you are trying to load a 32-bit VST3 from a 64-bit host - // or vice versa. - jassert (factory != nullptr); - return factory; - } - - void* getFunction (const char* functionName) - { - #if JUCE_WINDOWS - return library.getFunction (functionName); - #else - if (bundleRef == nullptr) - return nullptr; - - CFStringRef name = String (functionName).toCFString(); - void* fn = CFBundleGetFunctionPointerForName (bundleRef, name); - CFRelease (name); - return fn; - #endif - } - -private: - IPluginFactory* factory = nullptr; - - void releaseFactory() - { - if (factory != nullptr) - factory->release(); - } - - #if JUCE_WINDOWS - DynamicLibrary library; - - bool open (const String& filePath) - { - if (library.open (filePath)) - { - typedef bool (PLUGIN_API *InitModuleProc) (); - - if (auto proc = (InitModuleProc) getFunction ("InitDll")) - { - if (proc()) - return true; - } - else - { - return true; - } - - library.close(); - } - - return false; - } - - #else - CFBundleRef bundleRef; - - bool open (const String& filePath) - { - const File file (filePath); - const char* const utf8 = file.getFullPathName().toRawUTF8(); - - if (CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, (CFIndex) std::strlen (utf8), file.isDirectory())) - { - bundleRef = CFBundleCreate (kCFAllocatorDefault, url); - CFRelease (url); - - if (bundleRef != nullptr) - { - CFErrorRef error = nullptr; - - if (CFBundleLoadExecutableAndReturnError (bundleRef, &error)) - { - typedef bool (*BundleEntryProc)(CFBundleRef); - - if (auto proc = (BundleEntryProc) getFunction ("bundleEntry")) - { - if (proc (bundleRef)) - return true; - } - else - { - return true; - } - } - - if (error != nullptr) - { - if (CFStringRef failureMessage = CFErrorCopyFailureReason (error)) - { - DBG (String::fromCFString (failureMessage)); - CFRelease (failureMessage); - } - - CFRelease (error); - } - - CFRelease (bundleRef); - bundleRef = nullptr; - } - } - - return false; - } - #endif - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DLLHandle) -}; - -//============================================================================== -struct VST3ModuleHandle : public ReferenceCountedObject -{ - explicit VST3ModuleHandle (const File& pluginFile) : file (pluginFile) - { - getActiveModules().add (this); - } - - ~VST3ModuleHandle() - { - getActiveModules().removeFirstMatchingValue (this); - } - - /** - Since there is no apparent indication if a VST3 plugin is a shell or not, - we're stuck iterating through a VST3's factory, creating a description - for every housed plugin. - */ - static bool getAllDescriptionsForFile (OwnedArray& results, - const String& fileOrIdentifier) - { - DLLHandle tempModule (fileOrIdentifier); - - ComSmartPtr pluginFactory (tempModule.getPluginFactory()); - - if (pluginFactory != nullptr) - { - ComSmartPtr host (new VST3HostContext()); - DescriptionLister lister (host, pluginFactory); - auto result = lister.findDescriptionsAndPerform (File (fileOrIdentifier)); - - results.addCopiesOf (lister.list); - - return result.wasOk(); - } - - jassertfalse; - return false; - } - - //============================================================================== - typedef ReferenceCountedObjectPtr Ptr; - - static VST3ModuleHandle::Ptr findOrCreateModule (const File& file, const PluginDescription& description) - { - for (auto* module : getActiveModules()) - // VST3s are basically shells, you must therefore check their name along with their file: - if (module->file == file && module->name == description.name) - return module; - - VST3ModuleHandle::Ptr m (new VST3ModuleHandle (file)); - - if (! m->open (file, description)) - m = nullptr; - - return m; - } - - //============================================================================== - IPluginFactory* getPluginFactory() { return dllHandle->getPluginFactory(); } - - File file; - String name; - -private: - ScopedPointer dllHandle; - - //============================================================================== - static Array& getActiveModules() - { - static Array activeModules; - return activeModules; - } - - //============================================================================== - bool open (const File& f, const PluginDescription& description) - { - dllHandle = new DLLHandle (f.getFullPathName()); - - ComSmartPtr pluginFactory (dllHandle->getPluginFactory()); - - if (pluginFactory != nullptr) - { - ComSmartPtr host (new VST3HostContext()); - MatchingDescriptionFinder finder (host, pluginFactory, description); - - auto result = finder.findDescriptionsAndPerform (f); - - if (result.getErrorMessage() == MatchingDescriptionFinder::getSuccessString() || - result.getErrorMessage().isEmpty()) - { - name = description.name; - return true; - } - } - - return false; - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3ModuleHandle) -}; - -//============================================================================== -struct VST3PluginWindow : public AudioProcessorEditor, - public ComponentMovementWatcher, - public IPlugFrame -{ - VST3PluginWindow (AudioProcessor* owner, IPlugView* pluginView) - : AudioProcessorEditor (owner), - ComponentMovementWatcher (this), - view (pluginView, false) - { - setSize (10, 10); - setOpaque (true); - setVisible (true); - - warnOnFailure (view->setFrame (this)); - resizeToFit(); - } - - ~VST3PluginWindow() - { - warnOnFailure (view->removed()); - warnOnFailure (view->setFrame (nullptr)); - - processor.editorBeingDeleted (this); - - #if JUCE_MAC - embeddedComponent.setView (nullptr); - #endif - - view = nullptr; - } - - JUCE_DECLARE_VST3_COM_REF_METHODS - JUCE_DECLARE_VST3_COM_QUERY_METHODS - - void paint (Graphics& g) override - { - g.fillAll (Colours::black); - } - - void mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel) override - { - view->onWheel (wheel.deltaY); - } - - void focusGained (FocusChangeType) override { view->onFocus (true); } - void focusLost (FocusChangeType) override { view->onFocus (false); } - - /** It seems that most, if not all, plugins do their own keyboard hooks, - but IPlugView does have a set of keyboard related methods... - */ - bool keyStateChanged (bool /*isKeyDown*/) override { return true; } - bool keyPressed (const KeyPress& /*key*/) override { return true; } - - //============================================================================== - void componentMovedOrResized (bool, bool wasResized) override - { - if (recursiveResize) - return; - - auto* topComp = getTopLevelComponent(); - - if (topComp->getPeer() != nullptr) - { - #if JUCE_WINDOWS - auto pos = topComp->getLocalPoint (this, Point()); - #endif - - recursiveResize = true; - - ViewRect rect; - - if (wasResized && view->canResize() == kResultTrue) - { - rect.right = (Steinberg::int32) getWidth(); - rect.bottom = (Steinberg::int32) getHeight(); - view->checkSizeConstraint (&rect); - - auto w = (int) rect.getWidth(); - auto h = (int) rect.getHeight(); - setSize (w, h); - - #if JUCE_WINDOWS - SetWindowPos (pluginHandle, 0, - pos.x, pos.y, w, h, - isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); - #elif JUCE_MAC - embeddedComponent.setBounds (getLocalBounds()); - #endif - - view->onSize (&rect); - } - else - { - warnOnFailure (view->getSize (&rect)); - - #if JUCE_WINDOWS - SetWindowPos (pluginHandle, 0, - pos.x, pos.y, rect.getWidth(), rect.getHeight(), - isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); - #elif JUCE_MAC - embeddedComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight()); - #endif - } - - // Some plugins don't update their cursor correctly when mousing out the window - Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); - - recursiveResize = false; - } - } - - void componentPeerChanged() override {} - - void componentVisibilityChanged() override - { - attachPluginWindow(); - componentMovedOrResized (true, true); - } - - void resizeToFit() - { - ViewRect rect; - warnOnFailure (view->getSize (&rect)); - resizeWithRect (*this, rect); - } - - tresult PLUGIN_API resizeView (IPlugView* incomingView, ViewRect* newSize) override - { - if (incomingView != nullptr - && newSize != nullptr - && incomingView == view) - { - resizeWithRect (embeddedComponent, *newSize); - setSize (embeddedComponent.getWidth(), embeddedComponent.getHeight()); - return kResultTrue; - } - - jassertfalse; - return kInvalidArgument; - } - - void setScaleFactor (float newScale) override - { - Steinberg::IPlugViewContentScaleSupport* scaleInterface = nullptr; - view->queryInterface (Steinberg::IPlugViewContentScaleSupport::iid, (void**) &scaleInterface); - - if (scaleInterface != nullptr) - { - scaleInterface->setContentScaleFactor ((Steinberg::IPlugViewContentScaleSupport::ScaleFactor) newScale); - scaleInterface->release(); - resizeToFit(); - } - } - -private: - //============================================================================== - Atomic refCount { 1 }; - ComSmartPtr view; - - #if JUCE_WINDOWS - struct ChildComponent : public Component - { - ChildComponent() {} - void paint (Graphics& g) override { g.fillAll (Colours::cornflowerblue); } - using Component::createNewPeer; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildComponent) - }; - - ChildComponent embeddedComponent; - ScopedPointer peer; - typedef HWND HandleFormat; - #elif JUCE_MAC - AutoResizingNSViewComponentWithParent embeddedComponent; - typedef NSView* HandleFormat; - #else - Component embeddedComponent; - typedef void* HandleFormat; - #endif - - HandleFormat pluginHandle = {}; - bool recursiveResize = false; - - //============================================================================== - static void resizeWithRect (Component& comp, const ViewRect& rect) - { - comp.setBounds ((int) rect.left, (int) rect.top, - jmax (10, std::abs ((int) rect.getWidth())), - jmax (10, std::abs ((int) rect.getHeight()))); - } - - void attachPluginWindow() - { - if (pluginHandle == nullptr) - { - #if JUCE_WINDOWS - if (auto* topComp = getTopLevelComponent()) - peer = embeddedComponent.createNewPeer (0, topComp->getWindowHandle()); - else - peer = nullptr; - - if (peer != nullptr) - pluginHandle = (HandleFormat) peer->getNativeHandle(); - #elif JUCE_MAC - embeddedComponent.setBounds (getLocalBounds()); - addAndMakeVisible (embeddedComponent); - pluginHandle = (NSView*) embeddedComponent.getView(); - jassert (pluginHandle != nil); - #endif - - if (pluginHandle != nullptr) - warnOnFailure (view->attached (pluginHandle, defaultVST3WindowType)); - } - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3PluginWindow) -}; - -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4996) // warning about overriding deprecated methods -#endif - -//============================================================================== -struct VST3ComponentHolder -{ - VST3ComponentHolder (const VST3ModuleHandle::Ptr& m) : module (m) - { - host = new VST3HostContext(); - } - - ~VST3ComponentHolder() - { - terminate(); - - component = nullptr; - host = nullptr; - factory = nullptr; - module = nullptr; - } - - // transfers ownership to the plugin instance! - AudioPluginInstance* createPluginInstance(); - - bool fetchController (ComSmartPtr& editController) - { - if (! isComponentInitialised && ! initialise()) - return false; - - // Get the IEditController: - TUID controllerCID = { 0 }; - - if (component->getControllerClassId (controllerCID) == kResultTrue && FUID (controllerCID).isValid()) - editController.loadFrom (factory, controllerCID); - - if (editController == nullptr) - { - // Try finding the IEditController the long way around: - auto numClasses = factory->countClasses(); - - for (Steinberg::int32 i = 0; i < numClasses; ++i) - { - PClassInfo classInfo; - factory->getClassInfo (i, &classInfo); - - if (std::strcmp (classInfo.category, kVstComponentControllerClass) == 0) - editController.loadFrom (factory, classInfo.cid); - } - } - - if (editController == nullptr) - editController.loadFrom (component); - - return (editController != nullptr); - } - - //============================================================================== - void fillInPluginDescription (PluginDescription& description) const - { - jassert (module != nullptr && isComponentInitialised); - - PFactoryInfo factoryInfo; - factory->getFactoryInfo (&factoryInfo); - - auto classIdx = getClassIndex (module->name); - - if (classIdx >= 0) - { - PClassInfo info; - bool success = (factory->getClassInfo (classIdx, &info) == kResultOk); - ignoreUnused (success); - jassert (success); - - ComSmartPtr pf2; - ComSmartPtr pf3; - - ScopedPointer info2; - ScopedPointer infoW; - - if (pf2.loadFrom (factory)) - { - info2 = new PClassInfo2(); - pf2->getClassInfo2 (classIdx, info2); - } - else - { - info2 = nullptr; - } - - if (pf3.loadFrom (factory)) - { - pf3->setHostContext (host->getFUnknown()); - infoW = new PClassInfoW(); - pf3->getClassInfoUnicode (classIdx, infoW); - } - else - { - infoW = nullptr; - } - - Vst::BusInfo bus; - int totalNumInputChannels = 0, totalNumOutputChannels = 0; - - int n = component->getBusCount(Vst::kAudio, Vst::kInput); - for (int i = 0; i < n; ++i) - if (component->getBusInfo (Vst::kAudio, Vst::kInput, i, bus) == kResultOk) - totalNumInputChannels += ((bus.flags & Vst::BusInfo::kDefaultActive) != 0 ? bus.channelCount : 0); - - n = component->getBusCount(Vst::kAudio, Vst::kOutput); - for (int i = 0; i < n; ++i) - if (component->getBusInfo (Vst::kAudio, Vst::kOutput, i, bus) == kResultOk) - totalNumOutputChannels += ((bus.flags & Vst::BusInfo::kDefaultActive) != 0 ? bus.channelCount : 0); - - createPluginDescription (description, module->file, - factoryInfo.vendor, module->name, - info, info2, infoW, - totalNumInputChannels, - totalNumOutputChannels); - - return; - } - - jassertfalse; - } - - //============================================================================== - bool initialise() - { - if (isComponentInitialised) return true; - - #if JUCE_WINDOWS - // On Windows it's highly advisable to create your plugins using the message thread, - // because many plugins need a chance to create HWNDs that will get their messages - // delivered by the main message thread, and that's not possible from a background thread. - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - #endif - - factory = ComSmartPtr (module->getPluginFactory()); - - int classIdx; - if ((classIdx = getClassIndex (module->name)) < 0) - return false; - - PClassInfo info; - if (factory->getClassInfo (classIdx, &info) != kResultOk) - return false; - - if (! component.loadFrom (factory, info.cid) || component == nullptr) - return false; - - if (warnOnFailure (component->initialize (host->getFUnknown())) != kResultOk) - return false; - - isComponentInitialised = true; - - return true; - } - - void terminate() - { - if (isComponentInitialised) component->terminate(); - isComponentInitialised = false; - } - - //============================================================================== - int getClassIndex (const String& className) const - { - PClassInfo info; - const Steinberg::int32 numClasses = factory->countClasses(); - - for (Steinberg::int32 j = 0; j < numClasses; ++j) - if (factory->getClassInfo (j, &info) == kResultOk - && std::strcmp (info.category, kVstAudioEffectClass) == 0 - && toString (info.name).trim() == className) - return j; - - return -1; - } - - //============================================================================== - VST3ModuleHandle::Ptr module; - ComSmartPtr factory; - ComSmartPtr host; - ComSmartPtr component; - - bool isComponentInitialised = false; -}; - -//============================================================================== -struct VST3PluginInstance : public AudioPluginInstance -{ - VST3PluginInstance (VST3ComponentHolder* componentHolder) - : AudioPluginInstance (getBusProperties (componentHolder->component)), - holder (componentHolder), - inputParameterChanges (new ParamValueQueueList()), - outputParameterChanges (new ParamValueQueueList()), - midiInputs (new MidiEventList()), - midiOutputs (new MidiEventList()) - { - holder->host->setPlugin (this); - } - - ~VST3PluginInstance() - { - jassert (getActiveEditor() == nullptr); // You must delete any editors before deleting the plugin instance! - - releaseResources(); - - if (editControllerConnection != nullptr && componentConnection != nullptr) - { - editControllerConnection->disconnect (componentConnection); - componentConnection->disconnect (editControllerConnection); - } - - editController->setComponentHandler (nullptr); - - if (isControllerInitialised) editController->terminate(); - holder->terminate(); - - componentConnection = nullptr; - editControllerConnection = nullptr; - unitData = nullptr; - unitInfo = nullptr; - programListData = nullptr; - componentHandler2 = nullptr; - componentHandler = nullptr; - processor = nullptr; - editController2 = nullptr; - editController = nullptr; - } - - bool initialise() - { - #if JUCE_WINDOWS - // On Windows it's highly advisable to create your plugins using the message thread, - // because many plugins need a chance to create HWNDs that will get their messages - // delivered by the main message thread, and that's not possible from a background thread. - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - #endif - - if (! holder->initialise()) - return false; - - if (! isControllerInitialised) - { - if (! holder->fetchController (editController)) - return false; - } - - // (May return an error if the plugin combines the IComponent and IEditController implementations) - editController->initialize (holder->host->getFUnknown()); - - isControllerInitialised = true; - editController->setComponentHandler (holder->host); - grabInformationObjects(); - interconnectComponentAndController(); - synchroniseStates(); - syncProgramNames(); - setupIO(); - return true; - } - - void* getPlatformSpecificData() override { return holder->component; } - void refreshParameterList() override {} - - //============================================================================== - const String getName() const override - { - VST3ModuleHandle::Ptr& module = holder->module; - return module != nullptr ? module->name : String(); - } - - void repopulateArrangements (Array& inputArrangements, Array& outputArrangements) const - { - inputArrangements.clearQuick(); - outputArrangements.clearQuick(); - - auto numInputAudioBuses = getBusCount (true); - auto numOutputAudioBuses = getBusCount (false); - - for (int i = 0; i < numInputAudioBuses; ++i) - inputArrangements.add (getArrangementForBus (processor, true, i)); - - for (int i = 0; i < numOutputAudioBuses; ++i) - outputArrangements.add (getArrangementForBus (processor, false, i)); - } - - void processorLayoutsToArrangements (Array& inputArrangements, Array& outputArrangements) - { - inputArrangements.clearQuick(); - outputArrangements.clearQuick(); - - auto numInputBuses = getBusCount (true); - auto numOutputBuses = getBusCount (false); - - for (int i = 0; i < numInputBuses; ++i) - inputArrangements.add (getVst3SpeakerArrangement (getBus (true, i)->getLastEnabledLayout())); - - for (int i = 0; i < numOutputBuses; ++i) - outputArrangements.add (getVst3SpeakerArrangement (getBus (false, i)->getLastEnabledLayout())); - } - - void prepareToPlay (double newSampleRate, int estimatedSamplesPerBlock) override - { - // Avoid redundantly calling things like setActive, which can be a heavy-duty call for some plugins: - if (isActive - && getSampleRate() == newSampleRate - && getBlockSize() == estimatedSamplesPerBlock) - return; - - using namespace Vst; - - ProcessSetup setup; - setup.symbolicSampleSize = isUsingDoublePrecision() ? kSample64 : kSample32; - setup.maxSamplesPerBlock = estimatedSamplesPerBlock; - setup.sampleRate = newSampleRate; - setup.processMode = isNonRealtime() ? kOffline : kRealtime; - - warnOnFailure (processor->setupProcessing (setup)); - - holder->initialise(); - editController->setComponentHandler (holder->host); - - - Array inputArrangements, outputArrangements; - processorLayoutsToArrangements (inputArrangements, outputArrangements); - - warnOnFailure (processor->setBusArrangements (inputArrangements.getRawDataPointer(), inputArrangements.size(), - outputArrangements.getRawDataPointer(), outputArrangements.size())); - - Array actualInArr, actualOutArr; - repopulateArrangements (actualInArr, actualOutArr); - - jassert (actualInArr == inputArrangements && actualOutArr == outputArrangements); - - // Needed for having the same sample rate in processBlock(); some plugins need this! - setRateAndBufferSizeDetails (newSampleRate, estimatedSamplesPerBlock); - - auto numInputBuses = getBusCount (true); - auto numOutputBuses = getBusCount (false); - - for (int i = 0; i < numInputBuses; ++i) - warnOnFailure (holder->component->activateBus (Vst::kAudio, Vst::kInput, i, getBus (true, i)->isEnabled() ? 1 : 0)); - - for (int i = 0; i < numOutputBuses; ++i) - warnOnFailure (holder->component->activateBus (Vst::kAudio, Vst::kOutput, i, getBus (false, i)->isEnabled() ? 1 : 0)); - - setLatencySamples (jmax (0, (int) processor->getLatencySamples())); - cachedBusLayouts = getBusesLayout(); - - warnOnFailure (holder->component->setActive (true)); - warnOnFailure (processor->setProcessing (true)); - - isActive = true; - } - - void releaseResources() override - { - if (! isActive) - return; // Avoids redundantly calling things like setActive - - isActive = false; - - setStateForAllMidiBuses (false); - - if (processor != nullptr) - warnOnFailure (processor->setProcessing (false)); - - if (holder->component != nullptr) - warnOnFailure (holder->component->setActive (false)); - } - - bool supportsDoublePrecisionProcessing() const override - { - return (processor->canProcessSampleSize (Vst::kSample64) == kResultTrue); - } - - void processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) override - { - jassert (! isUsingDoublePrecision()); - - if (isActive && processor != nullptr) - processAudio (buffer, midiMessages, Vst::kSample32); - } - - void processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) override - { - jassert (isUsingDoublePrecision()); - - if (isActive && processor != nullptr) - processAudio (buffer, midiMessages, Vst::kSample64); - } - - template - void processAudio (AudioBuffer& buffer, MidiBuffer& midiMessages, - Vst::SymbolicSampleSizes sampleSize) - { - using namespace Vst; - auto numSamples = buffer.getNumSamples(); - - auto numInputAudioBuses = getBusCount (true); - auto numOutputAudioBuses = getBusCount (false); - - ProcessData data; - data.processMode = isNonRealtime() ? kOffline : kRealtime; - data.symbolicSampleSize = sampleSize; - data.numInputs = numInputAudioBuses; - data.numOutputs = numOutputAudioBuses; - data.inputParameterChanges = inputParameterChanges; - data.outputParameterChanges = outputParameterChanges; - data.numSamples = (Steinberg::int32) numSamples; - - updateTimingInformation (data, getSampleRate()); - - for (int i = getTotalNumInputChannels(); i < buffer.getNumChannels(); ++i) - buffer.clear (i, 0, numSamples); - - associateTo (data, buffer); - associateTo (data, midiMessages); - - processor->process (data); - - MidiEventList::toMidiBuffer (midiMessages, *midiOutputs); - - inputParameterChanges->clearAllQueues(); - } - - //============================================================================== - bool canAddBus (bool) const override { return false; } - bool canRemoveBus (bool) const override { return false; } - - bool isBusesLayoutSupported (const BusesLayout& layouts) const override - { - // if the processor is not active, we ask the underlying plug-in if the - // layout is actually supported - if (! isActive) - return canApplyBusesLayout (layouts); - - // not much we can do to check the layout while the audio processor is running - // Let's at least check if it is a VST3 compatible layout - for (int dir = 0; dir < 2; ++dir) - { - bool isInput = (dir == 0); - auto n = getBusCount (isInput); - - for (int i = 0; i < n; ++i) - if (getChannelLayoutOfBus (isInput, i).isDiscreteLayout()) - return false; - } - - return true; - } - - bool syncBusLayouts (const BusesLayout& layouts) const - { - for (int dir = 0; dir < 2; ++dir) - { - bool isInput = (dir == 0); - auto n = getBusCount (isInput); - const Vst::BusDirection vstDir = (isInput ? Vst::kInput : Vst::kOutput); - - for (int busIdx = 0; busIdx < n; ++busIdx) - { - const bool isEnabled = (! layouts.getChannelSet (isInput, busIdx).isDisabled()); - - if (holder->component->activateBus (Vst::kAudio, vstDir, busIdx, (isEnabled ? 1 : 0)) != kResultOk) - return false; - } - } - - Array inputArrangements, outputArrangements; - - for (int i = 0; i < layouts.inputBuses.size(); ++i) - { - const auto& requested = layouts.getChannelSet (true, i); - inputArrangements.add (getVst3SpeakerArrangement (requested.isDisabled() ? getBus (true, i)->getLastEnabledLayout() : requested)); - } - - for (int i = 0; i < layouts.outputBuses.size(); ++i) - { - const auto& requested = layouts.getChannelSet (false, i); - outputArrangements.add (getVst3SpeakerArrangement (requested.isDisabled() ? getBus (false, i)->getLastEnabledLayout() : requested)); - } - - if (processor->setBusArrangements (inputArrangements.getRawDataPointer(), inputArrangements.size(), - outputArrangements.getRawDataPointer(), outputArrangements.size()) != kResultTrue) - return false; - - // check if the layout matches the request - Array actualIn, actualOut; - repopulateArrangements (actualIn, actualOut); - - return (actualIn == inputArrangements && actualOut == outputArrangements); - } - - bool canApplyBusesLayout (const BusesLayout& layouts) const override - { - // someone tried to change the layout while the AudioProcessor is running - // call releaseResources first! - jassert (! isActive); - - bool result = syncBusLayouts (layouts); - - // didn't succeed? Make sure it's back in it's original state - if (! result) - syncBusLayouts (getBusesLayout()); - - return result; - } - - //============================================================================== - void updateTrackProperties (const TrackProperties& properties) override - { - if (trackInfoListener != nullptr) - { - ComSmartPtr l (new TrackPropertiesAttributeList (properties)); - trackInfoListener->setChannelContextInfos (l); - } - } - - struct TrackPropertiesAttributeList : public Vst::IAttributeList - { - TrackPropertiesAttributeList (const TrackProperties& properties) : props (properties) {} - virtual ~TrackPropertiesAttributeList() {} - - JUCE_DECLARE_VST3_COM_REF_METHODS - - tresult PLUGIN_API queryInterface (const TUID queryIid, void** obj) override - { - TEST_FOR_AND_RETURN_IF_VALID (queryIid, Vst::IAttributeList) - TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (queryIid, FUnknown, Vst::IAttributeList) - - *obj = nullptr; - return kNotImplemented; - } - - tresult PLUGIN_API setInt (AttrID, Steinberg::int64) override { return kOutOfMemory; } - tresult PLUGIN_API setFloat (AttrID, double) override { return kOutOfMemory; } - tresult PLUGIN_API setString (AttrID, const Vst::TChar*) override { return kOutOfMemory; } - tresult PLUGIN_API setBinary (AttrID, const void*, Steinberg::uint32) override { return kOutOfMemory; } - tresult PLUGIN_API getFloat (AttrID, double&) override { return kResultFalse; } - tresult PLUGIN_API getBinary (AttrID, const void*&, Steinberg::uint32&) override { return kResultFalse; } - - tresult PLUGIN_API getString (AttrID id, Vst::TChar* string, Steinberg::uint32 size) override - { - if (! std::strcmp (id, Vst::ChannelContext::kChannelNameKey)) - { - Steinberg::String str (props.name.toRawUTF8()); - str.copyTo (string, 0, (Steinberg::int32) jmin (size, (Steinberg::uint32) std::numeric_limits::max())); - - return kResultTrue; - } - - return kResultFalse; - } - - tresult PLUGIN_API getInt (AttrID id, Steinberg::int64& value) override - { - if (! std::strcmp (Vst::ChannelContext::kChannelNameLengthKey, id)) value = props.name.length(); - else if (! std::strcmp (Vst::ChannelContext::kChannelColorKey, id)) value = static_cast (props.colour.getARGB()); - else return kResultFalse; - - return kResultTrue; - } - - Atomic refCount; - TrackProperties props; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TrackPropertiesAttributeList) - }; - - //============================================================================== - String getChannelName (int channelIndex, bool forInput, bool forAudioChannel) const - { - auto numBuses = getNumSingleDirectionBusesFor (holder->component, forInput, forAudioChannel); - int numCountedChannels = 0; - - for (int i = 0; i < numBuses; ++i) - { - auto busInfo = getBusInfo (forInput, forAudioChannel, i); - - numCountedChannels += busInfo.channelCount; - - if (channelIndex < numCountedChannels) - return toString (busInfo.name); - } - - return {}; - } - - const String getInputChannelName (int channelIndex) const override { return getChannelName (channelIndex, true, true); } - const String getOutputChannelName (int channelIndex) const override { return getChannelName (channelIndex, false, true); } - - bool isInputChannelStereoPair (int channelIndex) const override - { - int busIdx; - return getOffsetInBusBufferForAbsoluteChannelIndex (true, channelIndex, busIdx) >= 0 - && getBusInfo (true, true, busIdx).channelCount == 2; - } - - bool isOutputChannelStereoPair (int channelIndex) const override - { - int busIdx; - return getOffsetInBusBufferForAbsoluteChannelIndex (false, channelIndex, busIdx) >= 0 - && getBusInfo (false, true, busIdx).channelCount == 2; - } - - bool acceptsMidi() const override { return getBusInfo (true, false).channelCount > 0; } - bool producesMidi() const override { return getBusInfo (false, false).channelCount > 0; } - - //============================================================================== - /** May return a negative value as a means of informing us that the plugin has "infinite tail," or 0 for "no tail." */ - double getTailLengthSeconds() const override - { - if (processor != nullptr) - { - auto sampleRate = getSampleRate(); - - if (sampleRate > 0.0) - return jlimit (0, 0x7fffffff, (int) processor->getTailSamples()) / sampleRate; - } - - return 0.0; - } - - //============================================================================== - AudioProcessorEditor* createEditor() override - { - if (auto* view = tryCreatingView()) - return new VST3PluginWindow (this, view); - - return nullptr; - } - - bool hasEditor() const override - { - // (if possible, avoid creating a second instance of the editor, because that crashes some plugins) - if (getActiveEditor() != nullptr) - return true; - - ComSmartPtr view (tryCreatingView(), false); - return view != nullptr; - } - - //============================================================================== - int getNumParameters() override - { - if (editController != nullptr) - return (int) editController->getParameterCount(); - - return 0; - } - - const String getParameterName (int parameterIndex) override - { - return toString (getParameterInfoForIndex (parameterIndex).title); - } - - const String getParameterText (int parameterIndex) override - { - if (editController != nullptr) - { - auto id = getParameterInfoForIndex (parameterIndex).id; - - Vst::String128 result; - warnOnFailure (editController->getParamStringByValue (id, editController->getParamNormalized (id), result)); - - return toString (result); - } - - return {}; - } - - int getParameterNumSteps (int parameterIndex) override - { - if (editController != nullptr) - { - const auto numSteps = getParameterInfoForIndex (parameterIndex).stepCount; - - if (numSteps > 0) - return numSteps; - } - - return AudioProcessor::getDefaultNumParameterSteps(); - } - - bool isParameterDiscrete (int parameterIndex) const override - { - if (editController != nullptr) - { - const auto numSteps = getParameterInfoForIndex (parameterIndex).stepCount; - return numSteps > 0; - } - - return false; - } - - float getParameter (int parameterIndex) override - { - if (editController != nullptr) - { - auto id = getParameterInfoForIndex (parameterIndex).id; - return (float) editController->getParamNormalized (id); - } - - return 0.0f; - } - - void setParameter (int parameterIndex, float newValue) override - { - if (editController != nullptr) - { - auto paramID = getParameterInfoForIndex (parameterIndex).id; - editController->setParamNormalized (paramID, (double) newValue); - - Steinberg::int32 index; - inputParameterChanges->addParameterData (paramID, index)->addPoint (0, newValue, index); - } - } - - //============================================================================== - int getNumPrograms() override { return programNames.size(); } - const String getProgramName (int index) override { return programNames[index]; } - int getCurrentProgram() override { return jmax (0, (int) editController->getParamNormalized (programParameterID) * (programNames.size() - 1)); } - void changeProgramName (int, const String&) override {} - - void setCurrentProgram (int program) override - { - if (programNames.size() > 0 && editController != nullptr) - { - auto value = static_cast (program) / static_cast (programNames.size()); - - editController->setParamNormalized (programParameterID, value); - Steinberg::int32 index; - inputParameterChanges->addParameterData (programParameterID, index)->addPoint (0, value, index); - } - } - - //============================================================================== - void reset() override - { - if (holder->component != nullptr && processor != nullptr) - { - processor->setProcessing (false); - holder->component->setActive (false); - - holder->component->setActive (true); - processor->setProcessing (true); - } - } - - //============================================================================== - void getStateInformation (MemoryBlock& destData) override - { - XmlElement state ("VST3PluginState"); - - appendStateFrom (state, holder->component, "IComponent"); - appendStateFrom (state, editController, "IEditController"); - - AudioProcessor::copyXmlToBinary (state, destData); - } - - void setStateInformation (const void* data, int sizeInBytes) override - { - ScopedPointer head (AudioProcessor::getXmlFromBinary (data, sizeInBytes)); - - if (head != nullptr) - { - ComSmartPtr componentStream (createMemoryStreamForState (*head, "IComponent")); - - if (componentStream != nullptr && holder->component != nullptr) - holder->component->setState (componentStream); - - if (editController != nullptr) - { - if (componentStream != nullptr) - { - int64 result; - componentStream->seek (0, IBStream::kIBSeekSet, &result); - editController->setComponentState (componentStream); - } - - ComSmartPtr controllerStream = createMemoryStreamForState (*head, "IEditController"); - - if (controllerStream != nullptr) - editController->setState (controllerStream); - } - } - } - - //============================================================================== - void fillInPluginDescription (PluginDescription& description) const override - { - holder->fillInPluginDescription (description); - } - - /** @note Not applicable to VST3 */ - void getCurrentProgramStateInformation (MemoryBlock& destData) override - { - destData.setSize (0, true); - } - - /** @note Not applicable to VST3 */ - void setCurrentProgramStateInformation (const void* data, int sizeInBytes) override - { - ignoreUnused (data, sizeInBytes); - } - - //============================================================================== - // NB: this class and its subclasses must be public to avoid problems in - // DLL builds under MSVC. - struct ParamValueQueueList : public Vst::IParameterChanges - { - ParamValueQueueList() {} - virtual ~ParamValueQueueList() {} - - JUCE_DECLARE_VST3_COM_REF_METHODS - JUCE_DECLARE_VST3_COM_QUERY_METHODS - - Steinberg::int32 PLUGIN_API getParameterCount() override { return numQueuesUsed; } - Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32 index) override { return isPositiveAndBelow (static_cast (index), numQueuesUsed) ? queues[(int) index] : nullptr; } - - Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID& id, Steinberg::int32& index) override - { - for (int i = numQueuesUsed; --i >= 0;) - { - if (queues.getUnchecked (i)->getParameterId() == id) - { - index = (Steinberg::int32) i; - return queues.getUnchecked (i); - } - } - - index = numQueuesUsed++; - ParamValueQueue* valueQueue = (index < queues.size() ? queues[index] - : queues.add (new ParamValueQueue())); - - valueQueue->clear(); - valueQueue->setParamID (id); - - return valueQueue; - } - - void clearAllQueues() noexcept - { - numQueuesUsed = 0; - } - - struct ParamValueQueue : public Vst::IParamValueQueue - { - ParamValueQueue() - { - points.ensureStorageAllocated (1024); - } - - virtual ~ParamValueQueue() {} - - void setParamID (Vst::ParamID pID) noexcept { paramID = pID; } - - JUCE_DECLARE_VST3_COM_REF_METHODS - JUCE_DECLARE_VST3_COM_QUERY_METHODS - - Steinberg::Vst::ParamID PLUGIN_API getParameterId() override { return paramID; } - Steinberg::int32 PLUGIN_API getPointCount() override { return (Steinberg::int32) points.size(); } - - Steinberg::tresult PLUGIN_API getPoint (Steinberg::int32 index, - Steinberg::int32& sampleOffset, - Steinberg::Vst::ParamValue& value) override - { - const ScopedLock sl (pointLock); - - if (isPositiveAndBelow ((int) index, points.size())) - { - ParamPoint e (points.getUnchecked ((int) index)); - sampleOffset = e.sampleOffset; - value = e.value; - return kResultTrue; - } - - sampleOffset = -1; - value = 0.0; - return kResultFalse; - } - - Steinberg::tresult PLUGIN_API addPoint (Steinberg::int32 sampleOffset, - Steinberg::Vst::ParamValue value, - Steinberg::int32& index) override - { - ParamPoint p = { sampleOffset, value }; - - const ScopedLock sl (pointLock); - index = (Steinberg::int32) points.size(); - points.add (p); - return kResultTrue; - } - - void clear() noexcept - { - const ScopedLock sl (pointLock); - points.clearQuick(); - } - - private: - struct ParamPoint - { - Steinberg::int32 sampleOffset; - Steinberg::Vst::ParamValue value; - }; - - Atomic refCount; - Vst::ParamID paramID = static_cast (-1); - Array points; - CriticalSection pointLock; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamValueQueue) - }; - - Atomic refCount; - OwnedArray queues; - int numQueuesUsed = 0; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamValueQueueList) - }; - -private: - //============================================================================== - ScopedPointer holder; - - friend VST3HostContext; - - // Information objects: - String company; - ScopedPointer info; - ScopedPointer info2; - ScopedPointer infoW; - - // Rudimentary interfaces: - ComSmartPtr editController; - ComSmartPtr editController2; - ComSmartPtr processor; - ComSmartPtr componentHandler; - ComSmartPtr componentHandler2; - ComSmartPtr unitInfo; - ComSmartPtr unitData; - ComSmartPtr programListData; - ComSmartPtr componentConnection, editControllerConnection; - ComSmartPtr trackInfoListener; - - /** The number of IO buses MUST match that of the plugin, - even if there aren't enough channels to process, - as very poorly specified by the Steinberg SDK - */ - VST3FloatAndDoubleBusMapComposite inputBusMap, outputBusMap; - Array inputBuses, outputBuses; - AudioProcessor::BusesLayout cachedBusLayouts; - - StringArray programNames; - Vst::ParamID programParameterID = (Vst::ParamID) -1; - - //============================================================================== - template - static void appendStateFrom (XmlElement& head, ComSmartPtr& object, const String& identifier) - { - if (object != nullptr) - { - Steinberg::MemoryStream stream; - - if (object->getState (&stream) == kResultTrue) - { - MemoryBlock info (stream.getData(), (size_t) stream.getSize()); - head.createNewChildElement (identifier)->addTextElement (info.toBase64Encoding()); - } - } - } - - static Steinberg::MemoryStream* createMemoryStreamForState (XmlElement& head, StringRef identifier) - { - Steinberg::MemoryStream* stream = nullptr; - - if (auto* state = head.getChildByName (identifier)) - { - MemoryBlock mem; - - if (mem.fromBase64Encoding (state->getAllSubText())) - { - stream = new Steinberg::MemoryStream(); - stream->setSize ((TSize) mem.getSize()); - mem.copyTo (stream->getData(), 0, mem.getSize()); - } - } - - return stream; - } - - ComSmartPtr inputParameterChanges, outputParameterChanges; - ComSmartPtr midiInputs, midiOutputs; - Vst::ProcessContext timingInfo; //< Only use this in processBlock()! - bool isControllerInitialised = false, isActive = false; - - //============================================================================== - /** Some plugins need to be "connected" to intercommunicate between their implemented classes */ - void interconnectComponentAndController() - { - componentConnection.loadFrom (holder->component); - editControllerConnection.loadFrom (editController); - - if (componentConnection != nullptr && editControllerConnection != nullptr) - { - warnOnFailure (componentConnection->connect (editControllerConnection)); - warnOnFailure (editControllerConnection->connect (componentConnection)); - } - } - - void synchroniseStates() - { - Steinberg::MemoryStream stream; - - if (holder->component->getState (&stream) == kResultTrue) - if (stream.seek (0, Steinberg::IBStream::kIBSeekSet, nullptr) == kResultTrue) - warnOnFailure (editController->setComponentState (&stream)); - } - - void grabInformationObjects() - { - processor.loadFrom (holder->component); - unitInfo.loadFrom (holder->component); - programListData.loadFrom (holder->component); - unitData.loadFrom (holder->component); - editController2.loadFrom (holder->component); - componentHandler.loadFrom (holder->component); - componentHandler2.loadFrom (holder->component); - trackInfoListener.loadFrom (holder->component); - - if (processor == nullptr) processor.loadFrom (editController); - if (unitInfo == nullptr) unitInfo.loadFrom (editController); - if (programListData == nullptr) programListData.loadFrom (editController); - if (unitData == nullptr) unitData.loadFrom (editController); - if (editController2 == nullptr) editController2.loadFrom (editController); - if (componentHandler == nullptr) componentHandler.loadFrom (editController); - if (componentHandler2 == nullptr) componentHandler2.loadFrom (editController); - if (trackInfoListener == nullptr) trackInfoListener.loadFrom (editController); - } - - void setStateForAllMidiBuses (bool newState) - { - setStateForAllBusesOfType (holder->component, newState, true, false); // Activate/deactivate MIDI inputs - setStateForAllBusesOfType (holder->component, newState, false, false); // Activate/deactivate MIDI outputs - } - - void setupIO() - { - setStateForAllMidiBuses (true); - - Vst::ProcessSetup setup; - setup.symbolicSampleSize = Vst::kSample32; - setup.maxSamplesPerBlock = 1024; - setup.sampleRate = 44100.0; - setup.processMode = Vst::kRealtime; - - warnOnFailure (processor->setupProcessing (setup)); - - cachedBusLayouts = getBusesLayout(); - setRateAndBufferSizeDetails (setup.sampleRate, (int) setup.maxSamplesPerBlock); - } - - static AudioProcessor::BusesProperties getBusProperties (ComSmartPtr& component) - { - AudioProcessor::BusesProperties busProperties; - ComSmartPtr processor; - processor.loadFrom (component.get()); - - for (int dirIdx = 0; dirIdx < 2; ++dirIdx) - { - const bool isInput = (dirIdx == 0); - const Vst::BusDirection dir = (isInput ? Vst::kInput : Vst::kOutput); - const int numBuses = component->getBusCount (Vst::kAudio, dir); - - for (int i = 0; i < numBuses; ++i) - { - Vst::BusInfo info; - - if (component->getBusInfo (Vst::kAudio, dir, (Steinberg::int32) i, info) != kResultOk) - continue; - - if (info.channelCount == 0) - continue; - - AudioChannelSet layout = AudioChannelSet::discreteChannels (info.channelCount); - - Vst::SpeakerArrangement arr; - if (processor != nullptr && processor->getBusArrangement (dir, i, arr) == kResultOk) - layout = getChannelSetForSpeakerArrangement (arr); - - busProperties.addBus (isInput, toString (info.name), layout, - (info.flags & Vst::BusInfo::kDefaultActive) != 0); - } - } - - return busProperties; - } - - //============================================================================== - Vst::BusInfo getBusInfo (bool forInput, bool forAudio, int index = 0) const - { - Vst::BusInfo busInfo; - busInfo.mediaType = forAudio ? Vst::kAudio : Vst::kEvent; - busInfo.direction = forInput ? Vst::kInput : Vst::kOutput; - busInfo.channelCount = 0; - - holder->component->getBusInfo (busInfo.mediaType, busInfo.direction, - (Steinberg::int32) index, busInfo); - return busInfo; - } - - //============================================================================== - /** @note An IPlugView, when first created, should start with a ref-count of 1! */ - IPlugView* tryCreatingView() const - { - IPlugView* v = editController->createView (Vst::ViewType::kEditor); - - if (v == nullptr) v = editController->createView (nullptr); - if (v == nullptr) editController->queryInterface (IPlugView::iid, (void**) &v); - - return v; - } - - //============================================================================== - template - void associateTo (Vst::ProcessData& destination, AudioBuffer& buffer) - { - VST3BufferExchange::mapBufferToBuses (inputBuses, inputBusMap.get(), cachedBusLayouts.inputBuses, buffer); - VST3BufferExchange::mapBufferToBuses (outputBuses, outputBusMap.get(), cachedBusLayouts.outputBuses, buffer); - - destination.inputs = inputBuses.getRawDataPointer(); - destination.outputs = outputBuses.getRawDataPointer(); - } - - void associateTo (Vst::ProcessData& destination, MidiBuffer& midiBuffer) - { - midiInputs->clear(); - midiOutputs->clear(); - - MidiEventList::toEventList (*midiInputs, midiBuffer); - - destination.inputEvents = midiInputs; - destination.outputEvents = midiOutputs; - } - - void updateTimingInformation (Vst::ProcessData& destination, double processSampleRate) - { - toProcessContext (timingInfo, getPlayHead(), processSampleRate); - destination.processContext = &timingInfo; - } - - Vst::ParameterInfo getParameterInfoForIndex (int index) const - { - Vst::ParameterInfo paramInfo = { 0 }; - - if (processor != nullptr) - editController->getParameterInfo (index, paramInfo); - - return paramInfo; - } - - Vst::ProgramListInfo getProgramListInfo (int index) const - { - Vst::ProgramListInfo paramInfo = { 0 }; - - if (unitInfo != nullptr) - unitInfo->getProgramListInfo (index, paramInfo); - - return paramInfo; - } - - void syncProgramNames() - { - programNames.clear(); - - if (processor == nullptr || editController == nullptr) - return; - - Vst::UnitID programUnitID; - Vst::ParameterInfo paramInfo = { 0 }; - - { - int idx, num = editController->getParameterCount(); - for (idx = 0; idx < num; ++idx) - if (editController->getParameterInfo (idx, paramInfo) == kResultOk - && (paramInfo.flags & Steinberg::Vst::ParameterInfo::kIsProgramChange) != 0) - break; - - if (idx >= num) - return; - - programParameterID = paramInfo.id; - programUnitID = paramInfo.unitId; - } - - if (unitInfo != nullptr) - { - Vst::UnitInfo uInfo = { 0 }; - const int unitCount = unitInfo->getUnitCount(); - - for (int idx = 0; idx < unitCount; ++idx) - { - if (unitInfo->getUnitInfo(idx, uInfo) == kResultOk - && uInfo.id == programUnitID) - { - const int programListCount = unitInfo->getProgramListCount(); - - for (int j = 0; j < programListCount; ++j) - { - Vst::ProgramListInfo programListInfo = { 0 }; - - if (unitInfo->getProgramListInfo (j, programListInfo) == kResultOk - && programListInfo.id == uInfo.programListId) - { - Vst::String128 name; - - for (int k = 0; k < programListInfo.programCount; ++k) - if (unitInfo->getProgramName (programListInfo.id, k, name) == kResultOk) - programNames.add (toString (name)); - - return; - } - } - - break; - } - } - } - - if (editController != nullptr - && paramInfo.stepCount > 0) - { - auto numPrograms = paramInfo.stepCount + 1; - - for (int i = 0; i < numPrograms; ++i) - { - auto valueNormalized = static_cast (i) / static_cast (paramInfo.stepCount); - - Vst::String128 programName; - if (editController->getParamStringByValue (paramInfo.id, valueNormalized, programName) == kResultOk) - programNames.add (toString (programName)); - } - } - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3PluginInstance) -}; - -#if JUCE_MSVC - #pragma warning (pop) -#endif - -}; - -//============================================================================== -AudioPluginInstance* VST3Classes::VST3ComponentHolder::createPluginInstance() -{ - if (! initialise()) - return nullptr; - - auto* plugin = new VST3PluginInstance (this); - host->setPlugin (plugin); - return plugin; -} - - -//============================================================================== -VST3PluginFormat::VST3PluginFormat() {} -VST3PluginFormat::~VST3PluginFormat() {} - -void VST3PluginFormat::findAllTypesForFile (OwnedArray& results, const String& fileOrIdentifier) -{ - if (fileMightContainThisPluginType (fileOrIdentifier)) - VST3Classes::VST3ModuleHandle::getAllDescriptionsForFile (results, fileOrIdentifier); -} - -void VST3PluginFormat::createPluginInstance (const PluginDescription& description, double, int, void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) -{ - ScopedPointer result; - - if (fileMightContainThisPluginType (description.fileOrIdentifier)) - { - File file (description.fileOrIdentifier); - - auto previousWorkingDirectory = File::getCurrentWorkingDirectory(); - file.getParentDirectory().setAsCurrentWorkingDirectory(); - - if (const VST3Classes::VST3ModuleHandle::Ptr module = VST3Classes::VST3ModuleHandle::findOrCreateModule (file, description)) - { - ScopedPointer holder = new VST3Classes::VST3ComponentHolder (module); - - if (holder->initialise()) - { - result = new VST3Classes::VST3PluginInstance (holder.release()); - - if (! result->initialise()) - result = nullptr; - } - } - - previousWorkingDirectory.setAsCurrentWorkingDirectory(); - } - - String errorMsg; - - if (result == nullptr) - errorMsg = String (NEEDS_TRANS ("Unable to load XXX plug-in file")).replace ("XXX", "VST-3"); - - callback (userData, result.release(), errorMsg); -} - -bool VST3PluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept -{ - return false; -} - -bool VST3PluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) -{ - auto f = File::createFileWithoutCheckingPath (fileOrIdentifier); - - return f.hasFileExtension (".vst3") - #if JUCE_MAC - && f.exists(); - #else - && f.existsAsFile(); - #endif -} - -String VST3PluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) -{ - return fileOrIdentifier; //Impossible to tell because every VST3 is a type of shell... -} - -bool VST3PluginFormat::pluginNeedsRescanning (const PluginDescription& description) -{ - return File (description.fileOrIdentifier).getLastModificationTime() != description.lastFileModTime; -} - -bool VST3PluginFormat::doesPluginStillExist (const PluginDescription& description) -{ - return File (description.fileOrIdentifier).exists(); -} - -StringArray VST3PluginFormat::searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive, bool) -{ - StringArray results; - - for (int i = 0; i < directoriesToSearch.getNumPaths(); ++i) - recursiveFileSearch (results, directoriesToSearch[i], recursive); - - return results; -} - -void VST3PluginFormat::recursiveFileSearch (StringArray& results, const File& directory, const bool recursive) -{ - DirectoryIterator iter (directory, false, "*", File::findFilesAndDirectories); - - while (iter.next()) - { - auto f = iter.getFile(); - bool isPlugin = false; - - if (fileMightContainThisPluginType (f.getFullPathName())) - { - isPlugin = true; - results.add (f.getFullPathName()); - } - - if (recursive && (! isPlugin) && f.isDirectory()) - recursiveFileSearch (results, f, true); - } -} - -FileSearchPath VST3PluginFormat::getDefaultLocationsToSearch() -{ - #if JUCE_WINDOWS - auto programFiles = File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName(); - return FileSearchPath (programFiles + "\\Common Files\\VST3"); - #elif JUCE_MAC - return FileSearchPath ("/Library/Audio/Plug-Ins/VST3;~/Library/Audio/Plug-Ins/VST3"); - #else - return FileSearchPath(); - #endif -} - -} // namespace juce - -#endif // JUCE_PLUGINHOST_VST3 diff --git a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h b/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h deleted file mode 100644 index 4c3f140b5..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -#if (JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS)) || DOXYGEN - -/** - Implements a plugin format for VST3s. -*/ -class JUCE_API VST3PluginFormat : public AudioPluginFormat -{ -public: - /** Constructor */ - VST3PluginFormat(); - - /** Destructor */ - ~VST3PluginFormat(); - - //============================================================================== - String getName() const override { return "VST3"; } - void findAllTypesForFile (OwnedArray&, const String& fileOrIdentifier) override; - bool fileMightContainThisPluginType (const String& fileOrIdentifier) override; - String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override; - bool pluginNeedsRescanning (const PluginDescription&) override; - StringArray searchPathsForPlugins (const FileSearchPath&, bool recursive, bool) override; - bool doesPluginStillExist (const PluginDescription&) override; - FileSearchPath getDefaultLocationsToSearch() override; - bool canScanForPlugins() const override { return true; } - -private: - void createPluginInstance (const PluginDescription&, double initialSampleRate, - int initialBufferSize, void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) override; - - bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; - -private: - //============================================================================== - void recursiveFileSearch (StringArray&, const File&, bool recursive); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3PluginFormat) -}; - -#endif // JUCE_PLUGINHOST_VST3 - -} // namespace juce diff --git a/source/modules/juce_audio_processors/format_types/juce_VSTCommon.h b/source/modules/juce_audio_processors/format_types/juce_VSTCommon.h deleted file mode 100644 index 50494a748..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VSTCommon.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -struct SpeakerMappings : private AudioChannelSet // (inheritance only to give easier access to items in the namespace) -{ - struct Mapping - { - int32 vst2; - ChannelType channels[13]; - - bool matches (const Array& chans) const noexcept - { - const int n = sizeof (channels) / sizeof (ChannelType); - - for (int i = 0; i < n; ++i) - { - if (channels[i] == unknown) return (i == chans.size()); - if (i == chans.size()) return (channels[i] == unknown); - - if (channels[i] != chans.getUnchecked(i)) - return false; - } - - return true; - } - }; - - static AudioChannelSet vstArrangementTypeToChannelSet (int32 arr, int fallbackNumChannels) - { - if (arr == vstSpeakerConfigTypeEmpty) return AudioChannelSet::disabled(); - else if (arr == vstSpeakerConfigTypeMono) return AudioChannelSet::mono(); - else if (arr == vstSpeakerConfigTypeLR) return AudioChannelSet::stereo(); - else if (arr == vstSpeakerConfigTypeLRC) return AudioChannelSet::createLCR(); - else if (arr == vstSpeakerConfigTypeLRS) return AudioChannelSet::createLRS(); - else if (arr == vstSpeakerConfigTypeLRCS) return AudioChannelSet::createLCRS(); - else if (arr == vstSpeakerConfigTypeLRCLsRs) return AudioChannelSet::create5point0(); - else if (arr == vstSpeakerConfigTypeLRCLfeLsRs) return AudioChannelSet::create5point1(); - else if (arr == vstSpeakerConfigTypeLRCLsRsCs) return AudioChannelSet::create6point0(); - else if (arr == vstSpeakerConfigTypeLRCLfeLsRsCs) return AudioChannelSet::create6point1(); - else if (arr == vstSpeakerConfigTypeLRLsRsSlSr) return AudioChannelSet::create6point0Music(); - else if (arr == vstSpeakerConfigTypeLRLfeLsRsSlSr) return AudioChannelSet::create6point1Music(); - else if (arr == vstSpeakerConfigTypeLRCLsRsSlSr) return AudioChannelSet::create7point0(); - else if (arr == vstSpeakerConfigTypeLRCLsRsLcRc) return AudioChannelSet::create7point0SDDS(); - else if (arr == vstSpeakerConfigTypeLRCLfeLsRsSlSr) return AudioChannelSet::create7point1(); - else if (arr == vstSpeakerConfigTypeLRCLfeLsRsLcRc) return AudioChannelSet::create7point1SDDS(); - else if (arr == vstSpeakerConfigTypeLRLsRs) return AudioChannelSet::quadraphonic(); - - for (const Mapping* m = getMappings(); m->vst2 != vstSpeakerConfigTypeEmpty; ++m) - { - if (m->vst2 == arr) - { - AudioChannelSet s; - - for (int i = 0; m->channels[i] != 0; ++i) - s.addChannel (m->channels[i]); - - return s; - } - } - - return AudioChannelSet::discreteChannels (fallbackNumChannels); - } - - static AudioChannelSet vstArrangementTypeToChannelSet (const VstSpeakerConfiguration& arr) - { - return vstArrangementTypeToChannelSet (arr.type, arr.numberOfChannels); - } - - static int32 channelSetToVstArrangementType (AudioChannelSet channels) - { - if (channels == AudioChannelSet::disabled()) return vstSpeakerConfigTypeEmpty; - else if (channels == AudioChannelSet::mono()) return vstSpeakerConfigTypeMono; - else if (channels == AudioChannelSet::stereo()) return vstSpeakerConfigTypeLR; - else if (channels == AudioChannelSet::createLCR()) return vstSpeakerConfigTypeLRC; - else if (channels == AudioChannelSet::createLRS()) return vstSpeakerConfigTypeLRS; - else if (channels == AudioChannelSet::createLCRS()) return vstSpeakerConfigTypeLRCS; - else if (channels == AudioChannelSet::create5point0()) return vstSpeakerConfigTypeLRCLsRs; - else if (channels == AudioChannelSet::create5point1()) return vstSpeakerConfigTypeLRCLfeLsRs; - else if (channels == AudioChannelSet::create6point0()) return vstSpeakerConfigTypeLRCLsRsCs; - else if (channels == AudioChannelSet::create6point1()) return vstSpeakerConfigTypeLRCLfeLsRsCs; - else if (channels == AudioChannelSet::create6point0Music()) return vstSpeakerConfigTypeLRLsRsSlSr; - else if (channels == AudioChannelSet::create6point1Music()) return vstSpeakerConfigTypeLRLfeLsRsSlSr; - else if (channels == AudioChannelSet::create7point0()) return vstSpeakerConfigTypeLRCLsRsSlSr; - else if (channels == AudioChannelSet::create7point0SDDS()) return vstSpeakerConfigTypeLRCLsRsLcRc; - else if (channels == AudioChannelSet::create7point1()) return vstSpeakerConfigTypeLRCLfeLsRsSlSr; - else if (channels == AudioChannelSet::create7point1SDDS()) return vstSpeakerConfigTypeLRCLfeLsRsLcRc; - else if (channels == AudioChannelSet::quadraphonic()) return vstSpeakerConfigTypeLRLsRs; - - Array chans (channels.getChannelTypes()); - - if (channels == AudioChannelSet::disabled()) - return vstSpeakerConfigTypeEmpty; - - for (const Mapping* m = getMappings(); m->vst2 != vstSpeakerConfigTypeEmpty; ++m) - if (m->matches (chans)) - return m->vst2; - - return vstSpeakerConfigTypeUser; - } - - class VstSpeakerConfigurationHolder - { - public: - VstSpeakerConfigurationHolder () { clear(); } - VstSpeakerConfigurationHolder (const VstSpeakerConfiguration& vstConfig) { operator= (vstConfig); } - VstSpeakerConfigurationHolder (const VstSpeakerConfigurationHolder& other) { operator= (other.get()); } - VstSpeakerConfigurationHolder (VstSpeakerConfigurationHolder&& other) : storage (static_cast&&> (other.storage)) { other.clear(); } - - VstSpeakerConfigurationHolder (const AudioChannelSet& channels) - { - auto numberOfChannels = channels.size(); - VstSpeakerConfiguration& dst = *allocate (numberOfChannels); - - dst.type = channelSetToVstArrangementType (channels); - dst.numberOfChannels = numberOfChannels; - - for (int i = 0; i < dst.numberOfChannels; ++i) - { - VstIndividualSpeakerInfo& speaker = dst.speakers[i]; - - zeromem (&speaker, sizeof (VstIndividualSpeakerInfo)); - speaker.type = getSpeakerType (channels.getTypeOfChannel (i)); - } - } - - VstSpeakerConfigurationHolder& operator= (const VstSpeakerConfigurationHolder& vstConfig) { return operator=(vstConfig.get()); } - VstSpeakerConfigurationHolder& operator= (const VstSpeakerConfiguration& vstConfig) - { - VstSpeakerConfiguration& dst = *allocate (vstConfig.numberOfChannels); - - dst.type = vstConfig.type; - dst.numberOfChannels = vstConfig.numberOfChannels; - - for (int i = 0; i < dst.numberOfChannels; ++i) - dst.speakers[i] = vstConfig.speakers[i]; - - return *this; - } - - VstSpeakerConfigurationHolder& operator= (VstSpeakerConfigurationHolder && vstConfig) - { - storage = static_cast&&> (vstConfig.storage); - vstConfig.clear(); - - return *this; - } - - const VstSpeakerConfiguration& get() const { return *storage.get(); } - - private: - JUCE_LEAK_DETECTOR (VstSpeakerConfigurationHolder) - - HeapBlock storage; - - VstSpeakerConfiguration* allocate (int numChannels) - { - auto arrangementSize = sizeof (VstSpeakerConfiguration) - + sizeof (VstIndividualSpeakerInfo) * static_cast (jmax (8, numChannels) - 8); - - storage.malloc (1, arrangementSize); - return storage.get(); - } - - void clear() - { - VstSpeakerConfiguration& dst = *allocate (0); - - dst.type = vstSpeakerConfigTypeEmpty; - dst.numberOfChannels = 0; - } - }; - - static const Mapping* getMappings() noexcept - { - static const Mapping mappings[] = - { - { vstSpeakerConfigTypeMono, { centre, unknown } }, - { vstSpeakerConfigTypeLR, { left, right, unknown } }, - { vstSpeakerConfigTypeLsRs, { leftSurround, rightSurround, unknown } }, - { vstSpeakerConfigTypeLcRc, { leftCentre, rightCentre, unknown } }, - { vstSpeakerConfigTypeSlSr, { leftSurroundRear, rightSurroundRear, unknown } }, - { vstSpeakerConfigTypeCLfe, { centre, LFE, unknown } }, - { vstSpeakerConfigTypeLRC, { left, right, centre, unknown } }, - { vstSpeakerConfigTypeLRS, { left, right, surround, unknown } }, - { vstSpeakerConfigTypeLRCLfe, { left, right, centre, LFE, unknown } }, - { vstSpeakerConfigTypeLRLfeS, { left, right, LFE, surround, unknown } }, - { vstSpeakerConfigTypeLRCS, { left, right, centre, surround, unknown } }, - { vstSpeakerConfigTypeLRLsRs, { left, right, leftSurround, rightSurround, unknown } }, - { vstSpeakerConfigTypeLRCLfeS, { left, right, centre, LFE, surround, unknown } }, - { vstSpeakerConfigTypeLRLfeLsRs, { left, right, LFE, leftSurround, rightSurround, unknown } }, - { vstSpeakerConfigTypeLRCLsRs, { left, right, centre, leftSurround, rightSurround, unknown } }, - { vstSpeakerConfigTypeLRCLfeLsRs, { left, right, centre, LFE, leftSurround, rightSurround, unknown } }, - { vstSpeakerConfigTypeLRCLsRsCs, { left, right, centre, leftSurround, rightSurround, surround, unknown } }, - { vstSpeakerConfigTypeLRLsRsSlSr, { left, right, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, unknown } }, - { vstSpeakerConfigTypeLRCLfeLsRsCs, { left, right, centre, LFE, leftSurround, rightSurround, surround, unknown } }, - { vstSpeakerConfigTypeLRLfeLsRsSlSr, { left, right, LFE, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, unknown } }, - { vstSpeakerConfigTypeLRCLsRsLcRc, { left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, unknown } }, - { vstSpeakerConfigTypeLRCLsRsSlSr, { left, right, centre, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, unknown } }, - { vstSpeakerConfigTypeLRCLfeLsRsLcRc, { left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, unknown } }, - { vstSpeakerConfigTypeLRCLfeLsRsSlSr, { left, right, centre, LFE, leftSurround, rightSurround, leftSurroundRear, rightSurroundRear, unknown } }, - { vstSpeakerConfigTypeLRCLsRsLcRcCs, { left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, surround, unknown } }, - { vstSpeakerConfigTypeLRCLsRsCsSlSr, { left, right, centre, leftSurround, rightSurround, surround, leftSurroundRear, rightSurroundRear, unknown } }, - { vstSpeakerConfigTypeLRCLfeLsRsLcRcCs, { left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, surround, unknown } }, - { vstSpeakerConfigTypeLRCLfeLsRsCsSlSr, { left, right, centre, LFE, leftSurround, rightSurround, surround, leftSurroundRear, rightSurroundRear, unknown } }, - { vstSpeakerConfigTypeLRCLfeLsRsTflTfcTfrTrlTrrLfe2, { left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontCentre, topFrontRight, topRearLeft, topRearRight, LFE2, unknown } }, - { vstSpeakerConfigTypeEmpty, { unknown } } - }; - - return mappings; - } - - static inline int32 getSpeakerType (AudioChannelSet::ChannelType type) noexcept - { - switch (type) - { - case AudioChannelSet::left: return vstIndividualSpeakerTypeLeft; - case AudioChannelSet::right: return vstIndividualSpeakerTypeRight; - case AudioChannelSet::centre: return vstIndividualSpeakerTypeCentre; - case AudioChannelSet::LFE: return vstIndividualSpeakerTypeLFE; - case AudioChannelSet::leftSurround: return vstIndividualSpeakerTypeLeftSurround; - case AudioChannelSet::rightSurround: return vstIndividualSpeakerTypeRightSurround; - case AudioChannelSet::leftCentre: return vstIndividualSpeakerTypeLeftCentre; - case AudioChannelSet::rightCentre: return vstIndividualSpeakerTypeRightCentre; - case AudioChannelSet::surround: return vstIndividualSpeakerTypeSurround; - case AudioChannelSet::leftSurroundRear: return vstIndividualSpeakerTypeLeftRearSurround; - case AudioChannelSet::rightSurroundRear: return vstIndividualSpeakerTypeRightRearSurround; - case AudioChannelSet::topMiddle: return vstIndividualSpeakerTypeTopMiddle; - case AudioChannelSet::topFrontLeft: return vstIndividualSpeakerTypeTopFrontLeft; - case AudioChannelSet::topFrontCentre: return vstIndividualSpeakerTypeTopFrontCentre; - case AudioChannelSet::topFrontRight: return vstIndividualSpeakerTypeTopFrontRight; - case AudioChannelSet::topRearLeft: return vstIndividualSpeakerTypeTopRearLeft; - case AudioChannelSet::topRearCentre: return vstIndividualSpeakerTypeTopRearCentre; - case AudioChannelSet::topRearRight: return vstIndividualSpeakerTypeTopRearRight; - case AudioChannelSet::LFE2: return vstIndividualSpeakerTypeLFE2; - default: break; - } - - return 0; - } - - static inline AudioChannelSet::ChannelType getChannelType (int32 type) noexcept - { - switch (type) - { - case vstIndividualSpeakerTypeLeft: return AudioChannelSet::left; - case vstIndividualSpeakerTypeRight: return AudioChannelSet::right; - case vstIndividualSpeakerTypeCentre: return AudioChannelSet::centre; - case vstIndividualSpeakerTypeLFE: return AudioChannelSet::LFE; - case vstIndividualSpeakerTypeLeftSurround: return AudioChannelSet::leftSurround; - case vstIndividualSpeakerTypeRightSurround: return AudioChannelSet::rightSurround; - case vstIndividualSpeakerTypeLeftCentre: return AudioChannelSet::leftCentre; - case vstIndividualSpeakerTypeRightCentre: return AudioChannelSet::rightCentre; - case vstIndividualSpeakerTypeSurround: return AudioChannelSet::surround; - case vstIndividualSpeakerTypeLeftRearSurround: return AudioChannelSet::leftSurroundRear; - case vstIndividualSpeakerTypeRightRearSurround: return AudioChannelSet::rightSurroundRear; - case vstIndividualSpeakerTypeTopMiddle: return AudioChannelSet::topMiddle; - case vstIndividualSpeakerTypeTopFrontLeft: return AudioChannelSet::topFrontLeft; - case vstIndividualSpeakerTypeTopFrontCentre: return AudioChannelSet::topFrontCentre; - case vstIndividualSpeakerTypeTopFrontRight: return AudioChannelSet::topFrontRight; - case vstIndividualSpeakerTypeTopRearLeft: return AudioChannelSet::topRearLeft; - case vstIndividualSpeakerTypeTopRearCentre: return AudioChannelSet::topRearCentre; - case vstIndividualSpeakerTypeTopRearRight: return AudioChannelSet::topRearRight; - case vstIndividualSpeakerTypeLFE2: return AudioChannelSet::LFE2; - default: break; - } - - return AudioChannelSet::unknown; - } -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/format_types/juce_VSTInterface.h b/source/modules/juce_audio_processors/format_types/juce_VSTInterface.h deleted file mode 100644 index 4d31c312a..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VSTInterface.h +++ /dev/null @@ -1,485 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -#define JUCE_VSTINTERFACE_H_INCLUDED - -using namespace juce; - -#if JUCE_MSVC - #define VSTINTERFACECALL __cdecl - #pragma pack(push) - #pragma pack(8) -#elif JUCE_MAC || JUCE_IOS - #define VSTINTERFACECALL - #if JUCE_64BIT - #pragma options align=power - #else - #pragma options align=mac68k - #endif -#else - #define VSTINTERFACECALL - #pragma pack(push, 8) -#endif - -const int32 juceVstInterfaceVersion = 2400; -const int32 juceVstInterfaceIdentifier = 0x56737450; // The "magic" identifier in the SDK is 'VstP'. - -//============================================================================== -struct VstEffectInterface -{ - int32 interfaceIdentifier; - pointer_sized_int (VSTINTERFACECALL* dispatchFunction) (VstEffectInterface*, int32 op, int32 index, pointer_sized_int value, void* ptr, float opt); - void (VSTINTERFACECALL* processAudioFunction) (VstEffectInterface*, float** inputs, float** outputs, int32 numSamples); - void (VSTINTERFACECALL* setParameterValueFunction) (VstEffectInterface*, int32 parameterIndex, float value); - float (VSTINTERFACECALL* getParameterValueFunction) (VstEffectInterface*, int32 parameterIndex); - int32 numPrograms; - int32 numParameters; - int32 numInputChannels; - int32 numOutputChannels; - int32 flags; - pointer_sized_int hostSpace1; - pointer_sized_int hostSpace2; - int32 latency; - int32 deprecated1; - int32 deprecated2; - float deprecated3; - void* effectPointer; - void* userPointer; - int32 plugInIdentifier; - int32 plugInVersion; - void (VSTINTERFACECALL* processAudioInplaceFunction) (VstEffectInterface*, float** inputs, float** outputs, int32 numSamples); - void (VSTINTERFACECALL* processDoubleAudioInplaceFunction) (VstEffectInterface*, double** inputs, double** outputs, int32 numSamples); - char emptySpace[56]; -}; - -typedef pointer_sized_int (VSTINTERFACECALL* VstHostCallback) (VstEffectInterface*, int32 op, int32 index, pointer_sized_int value, void* ptr, float opt); - -enum VstEffectInterfaceFlags -{ - vstEffectFlagHasEditor = 1, - vstEffectFlagInplaceAudio = 16, - vstEffectFlagDataInChunks = 32, - vstEffectFlagIsSynth = 256, - vstEffectFlagInplaceDoubleAudio = 4096 -}; - -//============================================================================== -enum VstHostToPlugInOpcodes -{ - plugInOpcodeOpen, - plugInOpcodeClose, - plugInOpcodeSetCurrentProgram, - plugInOpcodeGetCurrentProgram, - plugInOpcodeSetCurrentProgramName, - plugInOpcodeGetCurrentProgramName, - plugInOpcodeGetParameterLabel, - plugInOpcodeGetParameterText, - plugInOpcodeGetParameterName, - plugInOpcodeSetSampleRate = plugInOpcodeGetParameterName + 2, - plugInOpcodeSetBlockSize, - plugInOpcodeResumeSuspend, - plugInOpcodeGetEditorBounds, - plugInOpcodeOpenEditor, - plugInOpcodeCloseEditor, - plugInOpcodeDrawEditor, - plugInOpcodeGetMouse, - plugInOpcodeEditorIdle = plugInOpcodeGetMouse + 2, - plugInOpcodeeffEditorTop, - plugInOpcodeSleepEditor, - plugInOpcodeIdentify, - plugInOpcodeGetData, - plugInOpcodeSetData, - plugInOpcodePreAudioProcessingEvents, - plugInOpcodeIsParameterAutomatable, - plugInOpcodeParameterValueForText, - plugInOpcodeGetProgramName = plugInOpcodeParameterValueForText + 2, - plugInOpcodeConnectInput = plugInOpcodeGetProgramName + 2, - plugInOpcodeConnectOutput, - plugInOpcodeGetInputPinProperties, - plugInOpcodeGetOutputPinProperties, - plugInOpcodeGetPlugInCategory, - plugInOpcodeSetSpeakerConfiguration = plugInOpcodeGetPlugInCategory + 7, - plugInOpcodeSetBypass = plugInOpcodeSetSpeakerConfiguration + 2, - plugInOpcodeGetPlugInName, - plugInOpcodeGetManufacturerName = plugInOpcodeGetPlugInName + 2, - plugInOpcodeGetManufacturerProductName, - plugInOpcodeGetManufacturerVersion, - plugInOpcodeManufacturerSpecific, - plugInOpcodeCanPlugInDo, - plugInOpcodeGetTailSize, - plugInOpcodeIdle, - plugInOpcodeKeyboardFocusRequired = plugInOpcodeIdle + 4, - plugInOpcodeGetVstInterfaceVersion, - plugInOpcodeGetCurrentMidiProgram = plugInOpcodeGetVstInterfaceVersion + 5, - plugInOpcodeGetSpeakerArrangement = plugInOpcodeGetCurrentMidiProgram + 6, - plugInOpcodeNextPlugInUniqueID, - plugInOpcodeStartProcess, - plugInOpcodeStopProcess, - plugInOpcodeSetNumberOfSamplesToProcess, - plugInOpcodeSetSampleFloatType = plugInOpcodeSetNumberOfSamplesToProcess + 4, - pluginOpcodeGetNumMidiInputChannels, - pluginOpcodeGetNumMidiOutputChannels, - plugInOpcodeMaximum = pluginOpcodeGetNumMidiOutputChannels -}; - - -enum VstPlugInToHostOpcodes -{ - hostOpcodeParameterChanged, - hostOpcodeVstVersion, - hostOpcodeCurrentId, - hostOpcodeIdle, - hostOpcodePinConnected, - hostOpcodePlugInWantsMidi = hostOpcodePinConnected + 2, - hostOpcodeGetTimingInfo, - hostOpcodePreAudioProcessingEvents, - hostOpcodeSetTime, - hostOpcodeTempoAt, - hostOpcodeGetNumberOfAutomatableParameters, - hostOpcodeGetParameterInterval, - hostOpcodeIOModified, - hostOpcodeNeedsIdle, - hostOpcodeWindowSize, - hostOpcodeGetSampleRate, - hostOpcodeGetBlockSize, - hostOpcodeGetInputLatency, - hostOpcodeGetOutputLatency, - hostOpcodeGetPreviousPlugIn, - hostOpcodeGetNextPlugIn, - hostOpcodeWillReplace, - hostOpcodeGetCurrentAudioProcessingLevel, - hostOpcodeGetAutomationState, - hostOpcodeOfflineStart, - hostOpcodeOfflineReadSource, - hostOpcodeOfflineWrite, - hostOpcodeOfflineGetCurrentPass, - hostOpcodeOfflineGetCurrentMetaPass, - hostOpcodeSetOutputSampleRate, - hostOpcodeGetOutputSpeakerConfiguration, - hostOpcodeGetManufacturerName, - hostOpcodeGetProductName, - hostOpcodeGetManufacturerVersion, - hostOpcodeManufacturerSpecific, - hostOpcodeSetIcon, - hostOpcodeCanHostDo, - hostOpcodeGetLanguage, - hostOpcodeOpenEditorWindow, - hostOpcodeCloseEditorWindow, - hostOpcodeGetDirectory, - hostOpcodeUpdateView, - hostOpcodeParameterChangeGestureBegin, - hostOpcodeParameterChangeGestureEnd, -}; - -//============================================================================== -enum VstProcessingSampleType -{ - vstProcessingSampleTypeFloat, - vstProcessingSampleTypeDouble -}; - -//============================================================================== -// These names must be identical to the Steinberg SDK so JUCE users can set -// exactly what they want. -enum VstPlugInCategory -{ - kPlugCategUnknown, - kPlugCategEffect, - kPlugCategSynth, - kPlugCategAnalysis, - kPlugCategMastering, - kPlugCategSpacializer, - kPlugCategRoomFx, - kPlugSurroundFx, - kPlugCategRestoration, - kPlugCategOfflineProcess, - kPlugCategShell, - kPlugCategGenerator -}; - -//============================================================================== -struct VstEditorBounds -{ - int16 upper; - int16 leftmost; - int16 lower; - int16 rightmost; -}; - -//============================================================================== -enum VstMaxStringLengths -{ - vstMaxNameLength = 64, - vstMaxParameterOrPinLabelLength = 64, - vstMaxParameterOrPinShortLabelLength = 8, - vstMaxCategoryLength = 24, - vstMaxManufacturerStringLength = 64, - vstMaxPlugInNameStringLength = 64 -}; - -//============================================================================== -struct VstPinInfo -{ - char text[vstMaxParameterOrPinLabelLength]; - int32 flags; - int32 configurationType; - char shortText[vstMaxParameterOrPinShortLabelLength]; - char unused[48]; -}; - -enum VstPinInfoFlags -{ - vstPinInfoFlagIsActive = 1, - vstPinInfoFlagIsStereo = 2, - vstPinInfoFlagValid = 4 -}; - -//============================================================================== -struct VstEvent -{ - int32 type; - int32 size; - int32 sampleOffset; - int32 flags; - char content[16]; -}; - -enum VstEventTypes -{ - vstMidiEventType = 1, - vstSysExEventType = 6 -}; - -struct VstEventBlock -{ - int32 numberOfEvents; - pointer_sized_int future; - VstEvent* events[2]; -}; - -struct VstMidiEvent -{ - int32 type; - int32 size; - int32 sampleOffset; - int32 flags; - int32 noteSampleLength; - int32 noteSampleOffset; - char midiData[4]; - char tuning; - char noteVelocityOff; - char future1; - char future2; -}; - -enum VstMidiEventFlags -{ - vstMidiEventIsRealtime = 1 -}; - -struct VstSysExEvent -{ - int32 type; - int32 size; - int32 offsetSamples; - int32 flags; - int32 sysExDumpSize; - pointer_sized_int future1; - char* sysExDump; - pointer_sized_int future2; -}; - -//============================================================================== -struct VstTimingInformation -{ - double samplePosition; - double sampleRate; - double systemTimeNanoseconds; - double musicalPosition; - double tempoBPM; - double lastBarPosition; - double loopStartPosition; - double loopEndPosition; - int32 timeSignatureNumerator; - int32 timeSignatureDenominator; - int32 smpteOffset; - int32 smpteRate; - int32 samplesToNearestClock; - int32 flags; -}; - -enum VstTimingInformationFlags -{ - vstTimingInfoFlagTransportChanged = 1, - vstTimingInfoFlagCurrentlyPlaying = 2, - vstTimingInfoFlagLoopActive = 4, - vstTimingInfoFlagCurrentlyRecording = 8, - vstTimingInfoFlagAutomationWriteModeActive = 64, - vstTimingInfoFlagAutomationReadModeActive = 128, - vstTimingInfoFlagNanosecondsValid = 256, - vstTimingInfoFlagMusicalPositionValid = 512, - vstTimingInfoFlagTempoValid = 1024, - vstTimingInfoFlagLastBarPositionValid = 2048, - vstTimingInfoFlagLoopPositionValid = 4096, - vstTimingInfoFlagTimeSignatureValid = 8192, - vstTimingInfoFlagSmpteValid = 16384, - vstTimingInfoFlagNearestClockValid = 32768 -}; - -//============================================================================== -enum VstSmpteRates -{ - vstSmpteRateFps24, - vstSmpteRateFps25, - vstSmpteRateFps2997, - vstSmpteRateFps30, - vstSmpteRateFps2997drop, - vstSmpteRateFps30drop, - - vstSmpteRate16mmFilm, - vstSmpteRate35mmFilm, - - vstSmpteRateFps239 = vstSmpteRate35mmFilm + 3, - vstSmpteRateFps249 , - vstSmpteRateFps599, - vstSmpteRateFps60 -}; - -//============================================================================== -struct VstIndividualSpeakerInfo -{ - float azimuthalAngle; - float elevationAngle; - float radius; - float reserved; - char label[vstMaxNameLength]; - int32 type; - char unused[28]; -}; - -enum VstIndividualSpeakerType -{ - vstIndividualSpeakerTypeUndefined = 0x7fffffff, - vstIndividualSpeakerTypeMono = 0, - vstIndividualSpeakerTypeLeft, - vstIndividualSpeakerTypeRight, - vstIndividualSpeakerTypeCentre, - vstIndividualSpeakerTypeLFE, - vstIndividualSpeakerTypeLeftSurround, - vstIndividualSpeakerTypeRightSurround, - vstIndividualSpeakerTypeLeftCentre, - vstIndividualSpeakerTypeRightCentre, - vstIndividualSpeakerTypeSurround, - vstIndividualSpeakerTypeCentreSurround = vstIndividualSpeakerTypeSurround, - vstIndividualSpeakerTypeLeftRearSurround, - vstIndividualSpeakerTypeRightRearSurround, - vstIndividualSpeakerTypeTopMiddle, - vstIndividualSpeakerTypeTopFrontLeft, - vstIndividualSpeakerTypeTopFrontCentre, - vstIndividualSpeakerTypeTopFrontRight, - vstIndividualSpeakerTypeTopRearLeft, - vstIndividualSpeakerTypeTopRearCentre, - vstIndividualSpeakerTypeTopRearRight, - vstIndividualSpeakerTypeLFE2 -}; - -struct VstSpeakerConfiguration -{ - int32 type; - int32 numberOfChannels; - VstIndividualSpeakerInfo speakers[8]; -}; - -enum VstSpeakerConfigurationType -{ - vstSpeakerConfigTypeUser = -2, - vstSpeakerConfigTypeEmpty = -1, - vstSpeakerConfigTypeMono = 0, - vstSpeakerConfigTypeLR, - vstSpeakerConfigTypeLsRs, - vstSpeakerConfigTypeLcRc, - vstSpeakerConfigTypeSlSr, - vstSpeakerConfigTypeCLfe, - vstSpeakerConfigTypeLRC, - vstSpeakerConfigTypeLRS, - vstSpeakerConfigTypeLRCLfe, - vstSpeakerConfigTypeLRLfeS, - vstSpeakerConfigTypeLRCS, - vstSpeakerConfigTypeLRLsRs, - vstSpeakerConfigTypeLRCLfeS, - vstSpeakerConfigTypeLRLfeLsRs, - vstSpeakerConfigTypeLRCLsRs, - vstSpeakerConfigTypeLRCLfeLsRs, - vstSpeakerConfigTypeLRCLsRsCs, - vstSpeakerConfigTypeLRLsRsSlSr, - vstSpeakerConfigTypeLRCLfeLsRsCs, - vstSpeakerConfigTypeLRLfeLsRsSlSr, - vstSpeakerConfigTypeLRCLsRsLcRc, - vstSpeakerConfigTypeLRCLsRsSlSr, - vstSpeakerConfigTypeLRCLfeLsRsLcRc, - vstSpeakerConfigTypeLRCLfeLsRsSlSr, - vstSpeakerConfigTypeLRCLsRsLcRcCs, - vstSpeakerConfigTypeLRCLsRsCsSlSr, - vstSpeakerConfigTypeLRCLfeLsRsLcRcCs, - vstSpeakerConfigTypeLRCLfeLsRsCsSlSr, - vstSpeakerConfigTypeLRCLfeLsRsTflTfcTfrTrlTrrLfe2 -}; - -#if JUCE_BIG_ENDIAN - #define JUCE_MULTICHAR_CONSTANT(a, b, c, d) (a | (((uint32) b) << 8) | (((uint32) c) << 16) | (((uint32) d) << 24)) -#else - #define JUCE_MULTICHAR_CONSTANT(a, b, c, d) (d | (((uint32) c) << 8) | (((uint32) b) << 16) | (((uint32) a) << 24)) -#endif - -enum PresonusExtensionConstants -{ - presonusVendorID = JUCE_MULTICHAR_CONSTANT ('P', 'r', 'e', 'S'), - presonusSetContentScaleFactor = JUCE_MULTICHAR_CONSTANT ('A', 'e', 'C', 's') -}; - -//============================================================================== -struct vst2FxBank -{ - int32 magic1; - int32 size; - int32 magic2; - int32 version1; - int32 fxID; - int32 version2; - int32 elements; - int32 current; - char shouldBeZero[124]; - int32 chunkSize; - char chunk[1]; -}; - -#if JUCE_MSVC - #pragma pack(pop) -#elif JUCE_MAC || JUCE_IOS - #pragma options align=reset -#else - #pragma pack(pop) -#endif diff --git a/source/modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h b/source/modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h deleted file mode 100644 index 6665cb9ae..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -// NB: this must come first, *before* the header-guard. -#ifdef JUCE_VSTINTERFACE_H_INCLUDED - -namespace juce -{ - -//============================================================================== -/** Holds a set of VSTMidiEvent objects and makes it easy to add - events to the list. - - This is used by both the VST hosting code and the plugin wrapper. -*/ -class VSTMidiEventList -{ -public: - //============================================================================== - VSTMidiEventList() - : numEventsUsed (0), numEventsAllocated (0) - { - } - - ~VSTMidiEventList() - { - freeEvents(); - } - - //============================================================================== - void clear() - { - numEventsUsed = 0; - - if (events != nullptr) - events->numberOfEvents = 0; - } - - void addEvent (const void* const midiData, const int numBytes, const int frameOffset) - { - ensureSize (numEventsUsed + 1); - - VstMidiEvent* const e = (VstMidiEvent*) (events->events [numEventsUsed]); - events->numberOfEvents = ++numEventsUsed; - - if (numBytes <= 4) - { - if (e->type == vstSysExEventType) - { - delete[] (((VstSysExEvent*) e)->sysExDump); - e->type = vstMidiEventType; - e->size = sizeof (VstMidiEvent); - e->noteSampleLength = 0; - e->noteSampleOffset = 0; - e->tuning = 0; - e->noteVelocityOff = 0; - } - - e->sampleOffset = frameOffset; - memcpy (e->midiData, midiData, (size_t) numBytes); - } - else - { - VstSysExEvent* const se = (VstSysExEvent*) e; - - if (se->type == vstSysExEventType) - delete[] se->sysExDump; - - se->sysExDump = new char [(size_t) numBytes]; - memcpy (se->sysExDump, midiData, (size_t) numBytes); - - se->type = vstSysExEventType; - se->size = sizeof (VstSysExEvent); - se->offsetSamples = frameOffset; - se->flags = 0; - se->sysExDumpSize = numBytes; - se->future1 = 0; - se->future2 = 0; - } - } - - //============================================================================== - // Handy method to pull the events out of an event buffer supplied by the host - // or plugin. - static void addEventsToMidiBuffer (const VstEventBlock* events, MidiBuffer& dest) - { - for (int i = 0; i < events->numberOfEvents; ++i) - { - const VstEvent* const e = events->events[i]; - - if (e != nullptr) - { - if (e->type == vstMidiEventType) - { - dest.addEvent ((const juce::uint8*) ((const VstMidiEvent*) e)->midiData, - 4, e->sampleOffset); - } - else if (e->type == vstSysExEventType) - { - dest.addEvent ((const juce::uint8*) ((const VstSysExEvent*) e)->sysExDump, - (int) ((const VstSysExEvent*) e)->sysExDumpSize, - e->sampleOffset); - } - } - } - } - - //============================================================================== - void ensureSize (int numEventsNeeded) - { - if (numEventsNeeded > numEventsAllocated) - { - numEventsNeeded = (numEventsNeeded + 32) & ~31; - - const size_t size = 20 + sizeof (VstEvent*) * (size_t) numEventsNeeded; - - if (events == nullptr) - events.calloc (size, 1); - else - events.realloc (size, 1); - - for (int i = numEventsAllocated; i < numEventsNeeded; ++i) - events->events[i] = allocateVSTEvent(); - - numEventsAllocated = numEventsNeeded; - } - } - - void freeEvents() - { - if (events != nullptr) - { - for (int i = numEventsAllocated; --i >= 0;) - freeVSTEvent (events->events[i]); - - events.free(); - numEventsUsed = 0; - numEventsAllocated = 0; - } - } - - //============================================================================== - HeapBlock events; - -private: - int numEventsUsed, numEventsAllocated; - - static VstEvent* allocateVSTEvent() - { - auto e = (VstEvent*) std::calloc (1, sizeof (VstMidiEvent) > sizeof (VstSysExEvent) ? sizeof (VstMidiEvent) - : sizeof (VstSysExEvent)); - e->type = vstMidiEventType; - e->size = sizeof (VstMidiEvent); - return e; - } - - static void freeVSTEvent (VstEvent* e) - { - if (e->type == vstSysExEventType) - delete[] (((VstSysExEvent*) e)->sysExDump); - - std::free (e); - } -}; - -} // namespace juce - -#endif // JUCE_VSTINTERFACE_H_INCLUDED diff --git a/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp deleted file mode 100644 index ff225ee2a..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ /dev/null @@ -1,2972 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -#if JUCE_PLUGINHOST_VST - -//============================================================================== -#undef PRAGMA_ALIGN_SUPPORTED - -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4996) -#elif ! JUCE_MINGW - #define __cdecl -#endif - -namespace Vst2 -{ - #include "juce_VSTInterface.h" -} - -using namespace Vst2; - -#include "juce_VSTCommon.h" - -#if JUCE_MSVC - #pragma warning (pop) - #pragma warning (disable: 4355) // ("this" used in initialiser list warning) -#endif - -#include "juce_VSTMidiEventList.h" - -#if JUCE_MINGW - #ifndef WM_APPCOMMAND - #define WM_APPCOMMAND 0x0319 - #endif -#elif ! JUCE_WINDOWS - static void _fpreset() {} - static void _clearfp() {} -#endif - -#ifndef JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN - #define JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN -#endif - -#ifndef JUCE_VST_WRAPPER_INVOKE_MAIN - #define JUCE_VST_WRAPPER_INVOKE_MAIN effect = module->moduleMain (&audioMaster); -#endif - -//============================================================================== -namespace juce -{ - -//============================================================================== -namespace -{ - const int fxbVersionNum = 1; - - struct fxProgram - { - int32 chunkMagic; // 'CcnK' - int32 byteSize; // of this chunk, excl. magic + byteSize - int32 fxMagic; // 'FxCk' - int32 version; - int32 fxID; // fx unique id - int32 fxVersion; - int32 numParams; - char prgName[28]; - float params[1]; // variable no. of parameters - }; - - struct fxSet - { - int32 chunkMagic; // 'CcnK' - int32 byteSize; // of this chunk, excl. magic + byteSize - int32 fxMagic; // 'FxBk' - int32 version; - int32 fxID; // fx unique id - int32 fxVersion; - int32 numPrograms; - char future[128]; - fxProgram programs[1]; // variable no. of programs - }; - - struct fxChunkSet - { - int32 chunkMagic; // 'CcnK' - int32 byteSize; // of this chunk, excl. magic + byteSize - int32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' - int32 version; - int32 fxID; // fx unique id - int32 fxVersion; - int32 numPrograms; - char future[128]; - int32 chunkSize; - char chunk[8]; // variable - }; - - struct fxProgramSet - { - int32 chunkMagic; // 'CcnK' - int32 byteSize; // of this chunk, excl. magic + byteSize - int32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' - int32 version; - int32 fxID; // fx unique id - int32 fxVersion; - int32 numPrograms; - char name[28]; - int32 chunkSize; - char chunk[8]; // variable - }; - - // Compares a magic value in either endianness. - static bool compareMagic (int32 magic, const char* name) noexcept - { - return magic == (int32) ByteOrder::littleEndianInt (name) - || magic == (int32) ByteOrder::bigEndianInt (name); - } - - static int32 fxbName (const char* name) noexcept { return (int32) ByteOrder::littleEndianInt (name); } - static int32 fxbSwap (int32 x) noexcept { return (int32) ByteOrder::swapIfLittleEndian ((uint32) x); } - - static float fxbSwapFloat (const float x) noexcept - { - #ifdef JUCE_LITTLE_ENDIAN - union { uint32 asInt; float asFloat; } n; - n.asFloat = x; - n.asInt = ByteOrder::swap (n.asInt); - return n.asFloat; - #else - return x; - #endif - } -} - -//============================================================================== -namespace -{ - static double getVSTHostTimeNanoseconds() noexcept - { - #if JUCE_WINDOWS - return timeGetTime() * 1000000.0; - #elif JUCE_LINUX || JUCE_IOS || JUCE_ANDROID - timeval micro; - gettimeofday (µ, 0); - return micro.tv_usec * 1000.0; - #elif JUCE_MAC - UnsignedWide micro; - Microseconds (µ); - return micro.lo * 1000.0; - #endif - } - - static int shellUIDToCreate = 0; - static int insideVSTCallback = 0; - - struct IdleCallRecursionPreventer - { - IdleCallRecursionPreventer() : isMessageThread (MessageManager::getInstance()->isThisTheMessageThread()) - { - if (isMessageThread) - ++insideVSTCallback; - } - - ~IdleCallRecursionPreventer() - { - if (isMessageThread) - --insideVSTCallback; - } - - const bool isMessageThread; - JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer) - }; - - #if JUCE_MAC - static bool makeFSRefFromPath (FSRef* destFSRef, const String& path) - { - return FSPathMakeRef (reinterpret_cast (path.toRawUTF8()), destFSRef, 0) == noErr; - } - #endif -} - -//============================================================================== -typedef VstEffectInterface* (VSTINTERFACECALL *MainCall) (VstHostCallback); -static pointer_sized_int VSTINTERFACECALL audioMaster (VstEffectInterface*, int32, int32, pointer_sized_int, void*, float); - -//============================================================================== -// Change this to disable logging of various VST activities -#ifndef VST_LOGGING - #define VST_LOGGING 1 -#endif - -#if VST_LOGGING - #define JUCE_VST_LOG(a) Logger::writeToLog(a); -#else - #define JUCE_VST_LOG(a) -#endif - -//============================================================================== -#if JUCE_LINUX - -namespace -{ - typedef void (*EventProcPtr) (XEvent* ev); - - Window getChildWindow (Window windowToCheck) - { - Window rootWindow, parentWindow; - Window* childWindows; - unsigned int numChildren = 0; - - { - ScopedXDisplay xDisplay; - XQueryTree (xDisplay.display, windowToCheck, &rootWindow, &parentWindow, &childWindows, &numChildren); - } - - if (numChildren > 0) - return childWindows [0]; - - return 0; - } -} - -#endif - -//============================================================================== -struct ModuleHandle : public ReferenceCountedObject -{ - File file; - MainCall moduleMain, customMain = {}; - String pluginName; - ScopedPointer vstXml; - - typedef ReferenceCountedObjectPtr Ptr; - - static Array& getActiveModules() - { - static Array activeModules; - return activeModules; - } - - //============================================================================== - static Ptr findOrCreateModule (const File& file) - { - for (auto* module : getActiveModules()) - if (module->file == file) - return module; - - const IdleCallRecursionPreventer icrp; - shellUIDToCreate = 0; - _fpreset(); - - JUCE_VST_LOG ("Attempting to load VST: " + file.getFullPathName()); - - Ptr m = new ModuleHandle (file, nullptr); - - if (m->open()) - { - _fpreset(); - return m; - } - - return {}; - } - - //============================================================================== - ModuleHandle (const File& f, MainCall customMainCall) - : file (f), moduleMain (customMainCall) - { - getActiveModules().add (this); - - #if JUCE_WINDOWS || JUCE_LINUX || JUCE_IOS || JUCE_ANDROID - fullParentDirectoryPathName = f.getParentDirectory().getFullPathName(); - #elif JUCE_MAC - FSRef ref; - makeFSRefFromPath (&ref, f.getParentDirectory().getFullPathName()); - FSGetCatalogInfo (&ref, kFSCatInfoNone, 0, 0, &parentDirFSSpec, 0); - #endif - } - - ~ModuleHandle() - { - getActiveModules().removeFirstMatchingValue (this); - close(); - } - - //============================================================================== - #if ! JUCE_MAC - String fullParentDirectoryPathName; - #endif - - #if JUCE_WINDOWS || JUCE_LINUX || JUCE_ANDROID - DynamicLibrary module; - - bool open() - { - if (moduleMain != nullptr) - return true; - - pluginName = file.getFileNameWithoutExtension(); - - module.open (file.getFullPathName()); - - moduleMain = (MainCall) module.getFunction ("VSTPluginMain"); - - if (moduleMain == nullptr) - moduleMain = (MainCall) module.getFunction ("main"); - - JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN - - if (moduleMain != nullptr) - { - vstXml = XmlDocument::parse (file.withFileExtension ("vstxml")); - - #if JUCE_WINDOWS - if (vstXml == nullptr) - vstXml = XmlDocument::parse (getDLLResource (file, "VSTXML", 1)); - #endif - } - - return moduleMain != nullptr; - } - - void close() - { - _fpreset(); // (doesn't do any harm) - - module.close(); - } - - void closeEffect (VstEffectInterface* eff) - { - eff->dispatchFunction (eff, plugInOpcodeClose, 0, 0, 0, 0); - } - - #if JUCE_WINDOWS - static String getDLLResource (const File& dllFile, const String& type, int resID) - { - DynamicLibrary dll (dllFile.getFullPathName()); - auto dllModule = (HMODULE) dll.getNativeHandle(); - - if (dllModule != INVALID_HANDLE_VALUE) - { - if (auto res = FindResource (dllModule, MAKEINTRESOURCE (resID), type.toWideCharPointer())) - { - if (auto hGlob = LoadResource (dllModule, res)) - { - auto* data = static_cast (LockResource (hGlob)); - return String::fromUTF8 (data, SizeofResource (dllModule, res)); - } - } - } - - return {}; - } - #endif - #else - Handle resHandle = {}; - CFBundleRef bundleRef = {}; - - #if JUCE_MAC - CFBundleRefNum resFileId = {}; - FSSpec parentDirFSSpec; - #endif - - bool open() - { - if (moduleMain != nullptr) - return true; - - bool ok = false; - - if (file.hasFileExtension (".vst")) - { - auto* utf8 = file.getFullPathName().toRawUTF8(); - - if (CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, - (CFIndex) strlen (utf8), file.isDirectory())) - { - bundleRef = CFBundleCreate (kCFAllocatorDefault, url); - CFRelease (url); - - if (bundleRef != 0) - { - if (CFBundleLoadExecutable (bundleRef)) - { - moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef, CFSTR("main_macho")); - - if (moduleMain == nullptr) - moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef, CFSTR("VSTPluginMain")); - - JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN - - if (moduleMain != nullptr) - { - if (CFTypeRef name = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleName"))) - { - if (CFGetTypeID (name) == CFStringGetTypeID()) - { - char buffer[1024]; - - if (CFStringGetCString ((CFStringRef) name, buffer, sizeof (buffer), CFStringGetSystemEncoding())) - pluginName = buffer; - } - } - - if (pluginName.isEmpty()) - pluginName = file.getFileNameWithoutExtension(); - - #if JUCE_MAC - resFileId = CFBundleOpenBundleResourceMap (bundleRef); - #endif - - ok = true; - - Array vstXmlFiles; - file - #if JUCE_MAC - .getChildFile ("Contents") - .getChildFile ("Resources") - #endif - .findChildFiles (vstXmlFiles, File::findFiles, false, "*.vstxml"); - - if (vstXmlFiles.size() > 0) - vstXml = XmlDocument::parse (vstXmlFiles.getReference(0)); - } - } - - if (! ok) - { - CFBundleUnloadExecutable (bundleRef); - CFRelease (bundleRef); - bundleRef = 0; - } - } - } - } - - return ok; - } - - void close() - { - if (bundleRef != 0) - { - #if JUCE_MAC - CFBundleCloseBundleResourceMap (bundleRef, resFileId); - #endif - - if (CFGetRetainCount (bundleRef) == 1) - CFBundleUnloadExecutable (bundleRef); - - if (CFGetRetainCount (bundleRef) > 0) - CFRelease (bundleRef); - } - } - - void closeEffect (VstEffectInterface* eff) - { - eff->dispatchFunction (eff, plugInOpcodeClose, 0, 0, 0, 0); - } - - #endif - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModuleHandle) -}; - -static const int defaultVSTSampleRateValue = 44100; -static const int defaultVSTBlockSizeValue = 512; - -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4996) // warning about overriding deprecated methods -#endif - -//============================================================================== -//============================================================================== -struct VSTPluginInstance : public AudioPluginInstance, - private Timer, - private AsyncUpdater -{ - VSTPluginInstance (const ModuleHandle::Ptr& mh, const BusesProperties& ioConfig, VstEffectInterface* effect, - double sampleRateToUse, int blockSizeToUse) - : AudioPluginInstance (ioConfig), - vstEffect (effect), - vstModule (mh), - name (mh->pluginName) - { - setRateAndBufferSizeDetails (sampleRateToUse, blockSizeToUse); - } - - ~VSTPluginInstance() - { - if (vstEffect != nullptr && vstEffect->interfaceIdentifier == juceVstInterfaceIdentifier) - { - struct VSTDeleter : public CallbackMessage - { - VSTDeleter (VSTPluginInstance& inInstance, WaitableEvent& inEvent) - : vstInstance (inInstance), completionSignal (inEvent) - {} - - void messageCallback() override - { - vstInstance.cleanup(); - completionSignal.signal(); - } - - VSTPluginInstance& vstInstance; - WaitableEvent& completionSignal; - }; - - if (MessageManager::getInstance()->isThisTheMessageThread()) - { - cleanup(); - } - else - { - WaitableEvent completionEvent; - (new VSTDeleter (*this, completionEvent))->post(); - completionEvent.wait(); - } - } - } - - void cleanup() - { - if (vstEffect != nullptr && vstEffect->interfaceIdentifier == juceVstInterfaceIdentifier) - { - #if JUCE_MAC - if (vstModule->resFileId != 0) - UseResFile (vstModule->resFileId); - #endif - - // Must delete any editors before deleting the plugin instance! - jassert (getActiveEditor() == 0); - - _fpreset(); // some dodgy plugs fuck around with this - - vstModule->closeEffect (vstEffect); - } - - vstModule = nullptr; - vstEffect = nullptr; - } - - static VSTPluginInstance* create (const ModuleHandle::Ptr& newModule, - double initialSampleRate, - int initialBlockSize) - { - if (auto* newEffect = constructEffect (newModule)) - { - newEffect->hostSpace2 = 0; - - newEffect->dispatchFunction (newEffect, plugInOpcodeIdentify, 0, 0, 0, 0); - - auto blockSize = jmax (32, initialBlockSize); - - newEffect->dispatchFunction (newEffect, plugInOpcodeSetSampleRate, 0, 0, 0, static_cast (initialSampleRate)); - newEffect->dispatchFunction (newEffect, plugInOpcodeSetBlockSize, 0, blockSize, 0, 0); - - newEffect->dispatchFunction (newEffect, plugInOpcodeOpen, 0, 0, 0, 0); - BusesProperties ioConfig = queryBusIO (newEffect); - - return new VSTPluginInstance (newModule, ioConfig, newEffect, initialSampleRate, blockSize); - } - - return nullptr; - } - - //============================================================================== - void fillInPluginDescription (PluginDescription& desc) const override - { - desc.name = name; - - { - char buffer[512] = { 0 }; - dispatch (plugInOpcodeGetPlugInName, 0, 0, buffer, 0); - - desc.descriptiveName = String::createStringFromData (buffer, (int) sizeof (buffer)).trim(); - - if (desc.descriptiveName.isEmpty()) - desc.descriptiveName = name; - } - - desc.fileOrIdentifier = vstModule->file.getFullPathName(); - desc.uid = getUID(); - desc.lastFileModTime = vstModule->file.getLastModificationTime(); - desc.lastInfoUpdateTime = Time::getCurrentTime(); - desc.pluginFormatName = "VST"; - desc.category = getCategory(); - - { - char buffer[512] = { 0 }; - dispatch (plugInOpcodeGetManufacturerName, 0, 0, buffer, 0); - desc.manufacturerName = String::createStringFromData (buffer, (int) sizeof (buffer)).trim(); - } - - desc.version = getVersion(); - desc.numInputChannels = getTotalNumInputChannels(); - desc.numOutputChannels = getTotalNumOutputChannels(); - desc.isInstrument = (vstEffect != nullptr && (vstEffect->flags & vstEffectFlagIsSynth) != 0); - } - - bool initialiseEffect (double initialSampleRate, int initialBlockSize) - { - if (vstEffect != nullptr) - { - vstEffect->hostSpace2 = (pointer_sized_int) (pointer_sized_int) this; - initialise (initialSampleRate, initialBlockSize); - return true; - } - - return false; - } - - void initialise (double initialSampleRate, int initialBlockSize) - { - if (initialised || vstEffect == nullptr) - return; - - #if JUCE_WINDOWS - // On Windows it's highly advisable to create your plugins using the message thread, - // because many plugins need a chance to create HWNDs that will get their - // messages delivered by the main message thread, and that's not possible from - // a background thread. - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - #endif - - JUCE_VST_LOG ("Initialising VST: " + vstModule->pluginName + " (" + getVersion() + ")"); - initialised = true; - - setRateAndBufferSizeDetails (initialSampleRate, initialBlockSize); - - dispatch (plugInOpcodeIdentify, 0, 0, 0, 0); - - if (getSampleRate() > 0) - dispatch (plugInOpcodeSetSampleRate, 0, 0, 0, (float) getSampleRate()); - - if (getBlockSize() > 0) - dispatch (plugInOpcodeSetBlockSize, 0, jmax (32, getBlockSize()), 0, 0); - - dispatch (plugInOpcodeOpen, 0, 0, 0, 0); - - setRateAndBufferSizeDetails (getSampleRate(), getBlockSize()); - - if (getNumPrograms() > 1) - setCurrentProgram (0); - else - dispatch (plugInOpcodeSetCurrentProgram, 0, 0, 0, 0); - - for (int i = vstEffect->numInputChannels; --i >= 0;) dispatch (plugInOpcodeConnectInput, i, 1, 0, 0); - for (int i = vstEffect->numOutputChannels; --i >= 0;) dispatch (plugInOpcodeConnectOutput, i, 1, 0, 0); - - if (getVstCategory() != kPlugCategShell) // (workaround for Waves 5 plugins which crash during this call) - updateStoredProgramNames(); - - wantsMidiMessages = pluginCanDo ("receiveVstMidiEvent") > 0; - - #if JUCE_MAC && JUCE_SUPPORT_CARBON - usesCocoaNSView = ((unsigned int) pluginCanDo ("hasCockosViewAsConfig") & 0xffff0000ul) == 0xbeef0000ul; - #endif - - setLatencySamples (vstEffect->latency); - } - - void* getPlatformSpecificData() override { return vstEffect; } - - const String getName() const override - { - if (vstEffect != nullptr) - { - char buffer[512] = { 0 }; - - if (dispatch (plugInOpcodeGetManufacturerProductName, 0, 0, buffer, 0) != 0) - { - String productName = String::createStringFromData (buffer, (int) sizeof (buffer)); - - if (productName.isNotEmpty()) - return productName; - } - } - - return name; - } - - int getUID() const - { - int uid = vstEffect != nullptr ? vstEffect->plugInIdentifier : 0; - - if (uid == 0) - uid = vstModule->file.hashCode(); - - return uid; - } - - double getTailLengthSeconds() const override - { - if (vstEffect == nullptr) - return 0.0; - - auto sampleRate = getSampleRate(); - - if (sampleRate <= 0) - return 0.0; - - return dispatch (plugInOpcodeGetTailSize, 0, 0, 0, 0) / sampleRate; - } - - bool acceptsMidi() const override { return wantsMidiMessages; } - bool producesMidi() const override { return pluginCanDo ("sendVstMidiEvent") > 0; } - bool supportsMPE() const override { return pluginCanDo ("MPE") > 0; } - - VstPlugInCategory getVstCategory() const noexcept { return (VstPlugInCategory) dispatch (plugInOpcodeGetPlugInCategory, 0, 0, 0, 0); } - - int pluginCanDo (const char* text) const { return (int) dispatch (plugInOpcodeCanPlugInDo, 0, 0, (void*) text, 0); } - - //============================================================================== - void prepareToPlay (double rate, int samplesPerBlockExpected) override - { - setRateAndBufferSizeDetails (rate, samplesPerBlockExpected); - - SpeakerMappings::VstSpeakerConfigurationHolder inArr (getChannelLayoutOfBus (true, 0)); - SpeakerMappings::VstSpeakerConfigurationHolder outArr (getChannelLayoutOfBus (false, 0)); - - dispatch (plugInOpcodeSetSpeakerConfiguration, 0, (pointer_sized_int) &inArr.get(), (void*) &outArr.get(), 0.0f); - - vstHostTime.tempoBPM = 120.0; - vstHostTime.timeSignatureNumerator = 4; - vstHostTime.timeSignatureDenominator = 4; - vstHostTime.sampleRate = rate; - vstHostTime.samplePosition = 0; - vstHostTime.flags = vstTimingInfoFlagNanosecondsValid - | vstTimingInfoFlagAutomationWriteModeActive - | vstTimingInfoFlagAutomationReadModeActive; - - initialise (rate, samplesPerBlockExpected); - - if (initialised) - { - wantsMidiMessages = wantsMidiMessages || (pluginCanDo ("receiveVstMidiEvent") > 0); - - if (wantsMidiMessages) - midiEventsToSend.ensureSize (256); - else - midiEventsToSend.freeEvents(); - - incomingMidi.clear(); - - dispatch (plugInOpcodeSetSampleRate, 0, 0, 0, (float) rate); - dispatch (plugInOpcodeSetBlockSize, 0, jmax (16, samplesPerBlockExpected), 0, 0); - - if (supportsDoublePrecisionProcessing()) - { - int32 vstPrecision = isUsingDoublePrecision() ? vstProcessingSampleTypeDouble - : vstProcessingSampleTypeFloat; - - dispatch (plugInOpcodeSetSampleFloatType, 0, (pointer_sized_int) vstPrecision, 0, 0); - } - - auto maxChannels = jmax (1, jmax (vstEffect->numInputChannels, vstEffect->numOutputChannels)); - - tmpBufferFloat .setSize (maxChannels, samplesPerBlockExpected); - tmpBufferDouble.setSize (maxChannels, samplesPerBlockExpected); - - channelBufferFloat .calloc (static_cast (maxChannels)); - channelBufferDouble.calloc (static_cast (maxChannels)); - - outOfPlaceBuffer.setSize (jmax (1, vstEffect->numOutputChannels), samplesPerBlockExpected); - - if (! isPowerOn) - setPower (true); - - // dodgy hack to force some plugins to initialise the sample rate.. - if ((! hasEditor()) && getNumParameters() > 0) - { - auto old = getParameter (0); - setParameter (0, (old < 0.5f) ? 1.0f : 0.0f); - setParameter (0, old); - } - - dispatch (plugInOpcodeStartProcess, 0, 0, 0, 0); - - setLatencySamples (vstEffect->latency); - } - } - - void releaseResources() override - { - if (initialised) - { - dispatch (plugInOpcodeStopProcess, 0, 0, 0, 0); - setPower (false); - } - - channelBufferFloat.free(); - tmpBufferFloat.setSize (0, 0); - - channelBufferDouble.free(); - tmpBufferDouble.setSize (0, 0); - - outOfPlaceBuffer.setSize (1, 1); - incomingMidi.clear(); - - midiEventsToSend.freeEvents(); - } - - void reset() override - { - if (isPowerOn) - { - setPower (false); - setPower (true); - } - } - - void processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) override - { - jassert (! isUsingDoublePrecision()); - processAudio (buffer, midiMessages, tmpBufferFloat, channelBufferFloat); - } - - void processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) override - { - jassert (isUsingDoublePrecision()); - processAudio (buffer, midiMessages, tmpBufferDouble, channelBufferDouble); - } - - bool supportsDoublePrecisionProcessing() const override - { - return ((vstEffect->flags & vstEffectFlagInplaceAudio) != 0 - && (vstEffect->flags & vstEffectFlagInplaceDoubleAudio) != 0); - } - - //============================================================================== - bool canAddBus (bool) const override { return false; } - bool canRemoveBus (bool) const override { return false; } - - bool isBusesLayoutSupported (const BusesLayout& layouts) const override - { - auto numInputBuses = getBusCount (true); - auto numOutputBuses = getBusCount (false); - - // it's not possible to change layout if there are sidechains/aux buses - if (numInputBuses > 1 || numOutputBuses > 1) - return (layouts == getBusesLayout()); - - return (layouts.getNumChannels (true, 0) <= vstEffect->numInputChannels - && layouts.getNumChannels (false, 0) <= vstEffect->numOutputChannels); - } - - //============================================================================== - #if JUCE_IOS || JUCE_ANDROID - bool hasEditor() const override { return false; } - #else - bool hasEditor() const override { return vstEffect != nullptr && (vstEffect->flags & vstEffectFlagHasEditor) != 0; } - #endif - - AudioProcessorEditor* createEditor() override; - - //============================================================================== - const String getInputChannelName (int index) const override - { - if (isValidChannel (index, true)) - { - VstPinInfo pinProps; - if (dispatch (plugInOpcodeGetInputPinProperties, index, 0, &pinProps, 0.0f) != 0) - return String (pinProps.text, sizeof (pinProps.text)); - } - - return {}; - } - - bool isInputChannelStereoPair (int index) const override - { - if (! isValidChannel (index, true)) - return false; - - VstPinInfo pinProps; - if (dispatch (plugInOpcodeGetInputPinProperties, index, 0, &pinProps, 0.0f) != 0) - return (pinProps.flags & vstPinInfoFlagIsStereo) != 0; - - return true; - } - - const String getOutputChannelName (int index) const override - { - if (isValidChannel (index, false)) - { - VstPinInfo pinProps; - if (dispatch (plugInOpcodeGetOutputPinProperties, index, 0, &pinProps, 0.0f) != 0) - return String (pinProps.text, sizeof (pinProps.text)); - } - - return {}; - } - - bool isOutputChannelStereoPair (int index) const override - { - if (! isValidChannel (index, false)) - return false; - - VstPinInfo pinProps; - if (dispatch (plugInOpcodeGetOutputPinProperties, index, 0, &pinProps, 0.0f) != 0) - return (pinProps.flags & vstPinInfoFlagIsStereo) != 0; - - return true; - } - - bool isValidChannel (int index, bool isInput) const noexcept - { - return isPositiveAndBelow (index, isInput ? getTotalNumInputChannels() - : getTotalNumOutputChannels()); - } - - //============================================================================== - int getNumParameters() override { return vstEffect != nullptr ? vstEffect->numParameters : 0; } - - float getParameter (int index) override - { - if (vstEffect != nullptr && isPositiveAndBelow (index, vstEffect->numParameters)) - { - const ScopedLock sl (lock); - return vstEffect->getParameterValueFunction (vstEffect, index); - } - - return 0.0f; - } - - void setParameter (int index, float newValue) override - { - if (vstEffect != nullptr && isPositiveAndBelow (index, vstEffect->numParameters)) - { - const ScopedLock sl (lock); - - if (vstEffect->getParameterValueFunction (vstEffect, index) != newValue) - vstEffect->setParameterValueFunction (vstEffect, index, newValue); - } - } - - const String getParameterName (int index) override { return getTextForOpcode (index, plugInOpcodeGetParameterName); } - const String getParameterText (int index) override { return getTextForOpcode (index, plugInOpcodeGetParameterText); } - String getParameterLabel (int index) const override { return getTextForOpcode (index, plugInOpcodeGetParameterLabel); } - - bool isParameterAutomatable (int index) const override - { - if (vstEffect != nullptr) - { - jassert (index >= 0 && index < vstEffect->numParameters); - return dispatch (plugInOpcodeIsParameterAutomatable, index, 0, 0, 0) != 0; - } - - return false; - } - - //============================================================================== - int getNumPrograms() override { return vstEffect != nullptr ? jmax (0, vstEffect->numPrograms) : 0; } - - // NB: some plugs return negative numbers from this function. - int getCurrentProgram() override { return (int) dispatch (plugInOpcodeGetCurrentProgram, 0, 0, 0, 0); } - - void setCurrentProgram (int newIndex) override - { - if (getNumPrograms() > 0 && newIndex != getCurrentProgram()) - dispatch (plugInOpcodeSetCurrentProgram, 0, jlimit (0, getNumPrograms() - 1, newIndex), 0, 0); - } - - const String getProgramName (int index) override - { - if (index >= 0) - { - if (index == getCurrentProgram()) - return getCurrentProgramName(); - - if (vstEffect != nullptr) - { - char nm[264] = { 0 }; - - if (dispatch (plugInOpcodeGetProgramName, jlimit (0, getNumPrograms(), index), -1, nm, 0) != 0) - return String::fromUTF8 (nm).trim(); - } - } - - return programNames [index]; - } - - void changeProgramName (int index, const String& newName) override - { - if (index >= 0 && index == getCurrentProgram()) - { - if (getNumPrograms() > 0 && newName != getCurrentProgramName()) - dispatch (plugInOpcodeSetCurrentProgramName, 0, 0, (void*) newName.substring (0, 24).toRawUTF8(), 0.0f); - } - else - { - jassertfalse; // xxx not implemented! - } - } - - //============================================================================== - void getStateInformation (MemoryBlock& mb) override { saveToFXBFile (mb, true); } - void getCurrentProgramStateInformation (MemoryBlock& mb) override { saveToFXBFile (mb, false); } - - void setStateInformation (const void* data, int size) override { loadFromFXBFile (data, (size_t) size); } - void setCurrentProgramStateInformation (const void* data, int size) override { loadFromFXBFile (data, (size_t) size); } - - //============================================================================== - void timerCallback() override - { - if (dispatch (plugInOpcodeIdle, 0, 0, 0, 0) == 0) - stopTimer(); - } - - void handleAsyncUpdate() override - { - // indicates that something about the plugin has changed.. - updateHostDisplay(); - } - - pointer_sized_int handleCallback (int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt) - { - switch (opcode) - { - case hostOpcodeParameterChanged: sendParamChangeMessageToListeners (index, opt); break; - case hostOpcodePreAudioProcessingEvents: handleMidiFromPlugin ((const VstEventBlock*) ptr); break; - case hostOpcodeGetTimingInfo: return getVSTTime(); - case hostOpcodeIdle: handleIdle(); break; - case hostOpcodeWindowSize: setWindowSize (index, (int) value); return 1; - case hostOpcodeUpdateView: triggerAsyncUpdate(); break; - case hostOpcodeIOModified: setLatencySamples (vstEffect->latency); break; - case hostOpcodeNeedsIdle: startTimer (50); break; - - case hostOpcodeGetSampleRate: return (pointer_sized_int) (getSampleRate() > 0 ? getSampleRate() : defaultVSTSampleRateValue); - case hostOpcodeGetBlockSize: return (pointer_sized_int) (getBlockSize() > 0 ? getBlockSize() : defaultVSTBlockSizeValue); - case hostOpcodePlugInWantsMidi: wantsMidiMessages = true; break; - case hostOpcodeGetDirectory: return getVstDirectory(); - - case hostOpcodeTempoAt: return (pointer_sized_int) (extraFunctions != nullptr ? extraFunctions->getTempoAt ((int64) value) : 0); - case hostOpcodeGetAutomationState: return (pointer_sized_int) (extraFunctions != nullptr ? extraFunctions->getAutomationState() : 0); - - case hostOpcodeParameterChangeGestureBegin: beginParameterChangeGesture (index); break; - case hostOpcodeParameterChangeGestureEnd: endParameterChangeGesture (index); break; - - case hostOpcodePinConnected: return isValidChannel (index, value == 0) ? 0 : 1; // (yes, 0 = true) - case hostOpcodeGetCurrentAudioProcessingLevel: return isNonRealtime() ? 4 : 0; - - // none of these are handled (yet)... - case hostOpcodeSetTime: - case hostOpcodeGetParameterInterval: - case hostOpcodeGetInputLatency: - case hostOpcodeGetOutputLatency: - case hostOpcodeGetPreviousPlugIn: - case hostOpcodeGetNextPlugIn: - case hostOpcodeWillReplace: - case hostOpcodeOfflineStart: - case hostOpcodeOfflineReadSource: - case hostOpcodeOfflineWrite: - case hostOpcodeOfflineGetCurrentPass: - case hostOpcodeOfflineGetCurrentMetaPass: - case hostOpcodeGetOutputSpeakerConfiguration: - case hostOpcodeManufacturerSpecific: - case hostOpcodeSetIcon: - case hostOpcodeGetLanguage: - case hostOpcodeOpenEditorWindow: - case hostOpcodeCloseEditorWindow: - break; - - default: - return handleGeneralCallback (opcode, index, value, ptr, opt); - } - - return 0; - } - - // handles non plugin-specific callbacks.. - static pointer_sized_int handleGeneralCallback (int32 opcode, int32 /*index*/, pointer_sized_int /*value*/, void* ptr, float /*opt*/) - { - switch (opcode) - { - case hostOpcodeCanHostDo: return handleCanDo ((const char*) ptr); - case hostOpcodeVstVersion: return 2400; - case hostOpcodeCurrentId: return shellUIDToCreate; - case hostOpcodeGetNumberOfAutomatableParameters: return 0; - case hostOpcodeGetAutomationState: return 1; - case hostOpcodeGetManufacturerVersion: return 0x0101; - - case hostOpcodeGetManufacturerName: - case hostOpcodeGetProductName: return getHostName ((char*) ptr); - - case hostOpcodeGetSampleRate: return (pointer_sized_int) defaultVSTSampleRateValue; - case hostOpcodeGetBlockSize: return (pointer_sized_int) defaultVSTBlockSizeValue; - case hostOpcodeSetOutputSampleRate: return 0; - - default: - DBG ("*** Unhandled VST Callback: " + String ((int) opcode)); - break; - } - - return 0; - } - - //============================================================================== - pointer_sized_int dispatch (int opcode, int index, pointer_sized_int value, void* const ptr, float opt) const - { - pointer_sized_int result = 0; - - if (vstEffect != nullptr) - { - const ScopedLock sl (lock); - const IdleCallRecursionPreventer icrp; - - try - { - #if JUCE_MAC - auto oldResFile = CurResFile(); - - if (vstModule->resFileId != 0) - UseResFile (vstModule->resFileId); - #endif - - result = vstEffect->dispatchFunction (vstEffect, opcode, index, value, ptr, opt); - - #if JUCE_MAC - auto newResFile = CurResFile(); - - if (newResFile != oldResFile) // avoid confusing the parent app's resource file with the plug-in's - { - vstModule->resFileId = newResFile; - UseResFile (oldResFile); - } - #endif - } - catch (...) - {} - } - - return result; - } - - bool loadFromFXBFile (const void* const data, const size_t dataSize) - { - if (dataSize < 28) - return false; - - auto set = (const fxSet*) data; - - if ((! compareMagic (set->chunkMagic, "CcnK")) || fxbSwap (set->version) > fxbVersionNum) - return false; - - if (compareMagic (set->fxMagic, "FxBk")) - { - // bank of programs - if (fxbSwap (set->numPrograms) >= 0) - { - auto oldProg = getCurrentProgram(); - auto numParams = fxbSwap (((const fxProgram*) (set->programs))->numParams); - auto progLen = (int) sizeof (fxProgram) + (numParams - 1) * (int) sizeof (float); - - for (int i = 0; i < fxbSwap (set->numPrograms); ++i) - { - if (i != oldProg) - { - auto prog = (const fxProgram*) (((const char*) (set->programs)) + i * progLen); - - if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize) - return false; - - if (fxbSwap (set->numPrograms) > 0) - setCurrentProgram (i); - - if (! restoreProgramSettings (prog)) - return false; - } - } - - if (fxbSwap (set->numPrograms) > 0) - setCurrentProgram (oldProg); - - auto prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen); - - if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize) - return false; - - if (! restoreProgramSettings (prog)) - return false; - } - } - else if (compareMagic (set->fxMagic, "FxCk")) - { - // single program - auto prog = (const fxProgram*) data; - - if (! compareMagic (prog->chunkMagic, "CcnK")) - return false; - - changeProgramName (getCurrentProgram(), prog->prgName); - - for (int i = 0; i < fxbSwap (prog->numParams); ++i) - setParameter (i, fxbSwapFloat (prog->params[i])); - } - else if (compareMagic (set->fxMagic, "FBCh")) - { - // non-preset chunk - auto cset = (const fxChunkSet*) data; - - if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (size_t) dataSize) - return false; - - setChunkData (cset->chunk, fxbSwap (cset->chunkSize), false); - } - else if (compareMagic (set->fxMagic, "FPCh")) - { - // preset chunk - auto cset = (const fxProgramSet*) data; - - if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (size_t) dataSize) - return false; - - setChunkData (cset->chunk, fxbSwap (cset->chunkSize), true); - - changeProgramName (getCurrentProgram(), cset->name); - } - else - { - return false; - } - - return true; - } - - bool saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSizeMB = 128) - { - auto numPrograms = getNumPrograms(); - auto numParams = getNumParameters(); - - if (usesChunks()) - { - MemoryBlock chunk; - getChunkData (chunk, ! isFXB, maxSizeMB); - - if (isFXB) - { - auto totalLen = sizeof (fxChunkSet) + chunk.getSize() - 8; - dest.setSize (totalLen, true); - - auto set = (fxChunkSet*) dest.getData(); - set->chunkMagic = fxbName ("CcnK"); - set->byteSize = 0; - set->fxMagic = fxbName ("FBCh"); - set->version = fxbSwap (fxbVersionNum); - set->fxID = fxbSwap (getUID()); - set->fxVersion = fxbSwap (getVersionNumber()); - set->numPrograms = fxbSwap (numPrograms); - set->chunkSize = fxbSwap ((int32) chunk.getSize()); - - chunk.copyTo (set->chunk, 0, chunk.getSize()); - } - else - { - auto totalLen = sizeof (fxProgramSet) + chunk.getSize() - 8; - dest.setSize (totalLen, true); - - auto set = (fxProgramSet*) dest.getData(); - set->chunkMagic = fxbName ("CcnK"); - set->byteSize = 0; - set->fxMagic = fxbName ("FPCh"); - set->version = fxbSwap (fxbVersionNum); - set->fxID = fxbSwap (getUID()); - set->fxVersion = fxbSwap (getVersionNumber()); - set->numPrograms = fxbSwap (numPrograms); - set->chunkSize = fxbSwap ((int32) chunk.getSize()); - - getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1); - chunk.copyTo (set->chunk, 0, chunk.getSize()); - } - } - else - { - if (isFXB) - { - auto progLen = (int) sizeof (fxProgram) + (numParams - 1) * (int) sizeof (float); - auto len = (sizeof (fxSet) - sizeof (fxProgram)) + (size_t) (progLen * jmax (1, numPrograms)); - dest.setSize (len, true); - - auto set = (fxSet*) dest.getData(); - set->chunkMagic = fxbName ("CcnK"); - set->byteSize = 0; - set->fxMagic = fxbName ("FxBk"); - set->version = fxbSwap (fxbVersionNum); - set->fxID = fxbSwap (getUID()); - set->fxVersion = fxbSwap (getVersionNumber()); - set->numPrograms = fxbSwap (numPrograms); - - MemoryBlock oldSettings; - createTempParameterStore (oldSettings); - - auto oldProgram = getCurrentProgram(); - - if (oldProgram >= 0) - setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + oldProgram * progLen)); - - for (int i = 0; i < numPrograms; ++i) - { - if (i != oldProgram) - { - setCurrentProgram (i); - setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + i * progLen)); - } - } - - if (oldProgram >= 0) - setCurrentProgram (oldProgram); - - restoreFromTempParameterStore (oldSettings); - } - else - { - dest.setSize (sizeof (fxProgram) + (size_t) ((numParams - 1) * (int) sizeof (float)), true); - setParamsInProgramBlock ((fxProgram*) dest.getData()); - } - } - - return true; - } - - bool usesChunks() const noexcept { return vstEffect != nullptr && (vstEffect->flags & vstEffectFlagDataInChunks) != 0; } - - bool getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const - { - if (usesChunks()) - { - void* data = nullptr; - auto bytes = (size_t) dispatch (plugInOpcodeGetData, isPreset ? 1 : 0, 0, &data, 0.0f); - - if (data != nullptr && bytes <= (size_t) maxSizeMB * 1024 * 1024) - { - mb.setSize (bytes); - mb.copyFrom (data, 0, bytes); - - return true; - } - } - - return false; - } - - bool setChunkData (const void* data, const int size, bool isPreset) - { - if (size > 0 && usesChunks()) - { - dispatch (plugInOpcodeSetData, isPreset ? 1 : 0, size, (void*) data, 0.0f); - - if (! isPreset) - updateStoredProgramNames(); - - return true; - } - - return false; - } - - VstEffectInterface* vstEffect; - ModuleHandle::Ptr vstModule; - - ScopedPointer extraFunctions; - bool usesCocoaNSView = false; - -private: - String name; - CriticalSection lock; - bool wantsMidiMessages = false, initialised = false, isPowerOn = false; - mutable StringArray programNames; - AudioBuffer outOfPlaceBuffer; - - CriticalSection midiInLock; - MidiBuffer incomingMidi; - VSTMidiEventList midiEventsToSend; - VstTimingInformation vstHostTime; - - AudioBuffer tmpBufferFloat; - HeapBlock channelBufferFloat; - - AudioBuffer tmpBufferDouble; - HeapBlock channelBufferDouble; - - static pointer_sized_int handleCanDo (const char* name) - { - static const char* canDos[] = { "supplyIdle", - "sendVstEvents", - "sendVstMidiEvent", - "sendVstTimeInfo", - "receiveVstEvents", - "receiveVstMidiEvent", - "supportShell", - "sizeWindow", - "shellCategory" }; - - for (int i = 0; i < numElementsInArray (canDos); ++i) - if (strcmp (canDos[i], name) == 0) - return 1; - - return 0; - } - - static pointer_sized_int getHostName (char* name) - { - String hostName ("Carla Plugin Host"); - - if (auto* app = JUCEApplicationBase::getInstance()) - hostName = app->getApplicationName(); - - hostName.copyToUTF8 (name, (size_t) jmin (vstMaxManufacturerStringLength, vstMaxPlugInNameStringLength) - 1); - return 1; - } - - pointer_sized_int getVSTTime() noexcept - { - #if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4311) - #endif - - return (pointer_sized_int) &vstHostTime; - - #if JUCE_MSVC - #pragma warning (pop) - #endif - } - - void handleIdle() - { - if (insideVSTCallback == 0 && MessageManager::getInstance()->isThisTheMessageThread()) - { - const IdleCallRecursionPreventer icrp; - - #if JUCE_MAC - if (getActiveEditor() != nullptr) - dispatch (plugInOpcodeEditorIdle, 0, 0, 0, 0); - #endif - - Timer::callPendingTimersSynchronously(); - handleUpdateNowIfNeeded(); - - for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - if (auto* p = ComponentPeer::getPeer(i)) - p->performAnyPendingRepaintsNow(); - } - } - - void setWindowSize (int width, int height) - { - if (auto* ed = getActiveEditor()) - { - #if JUCE_LINUX - const MessageManagerLock mmLock; - #endif - ed->setSize (width, height); - } - } - - //============================================================================== - static VstEffectInterface* constructEffect (const ModuleHandle::Ptr& module) - { - VstEffectInterface* effect = nullptr; - try - { - const IdleCallRecursionPreventer icrp; - _fpreset(); - - JUCE_VST_LOG ("Creating VST instance: " + module->pluginName); - - #if JUCE_MAC - if (module->resFileId != 0) - UseResFile (module->resFileId); - #endif - - { - JUCE_VST_WRAPPER_INVOKE_MAIN - } - - if (effect != nullptr && effect->interfaceIdentifier == juceVstInterfaceIdentifier) - { - jassert (effect->hostSpace2 == 0); - jassert (effect->effectPointer != 0); - - _fpreset(); // some dodgy plugs mess around with this - } - else - { - effect = nullptr; - } - } - catch (...) - {} - - return effect; - } - - static BusesProperties queryBusIO (VstEffectInterface* effect) - { - BusesProperties returnValue; - - if (effect->numInputChannels == 0 && effect->numOutputChannels == 0) - return returnValue; - - // Workaround for old broken JUCE plug-ins which would return an invalid - // speaker arrangement if the host didn't ask for a specific arrangement - // beforehand. - // Check if the plug-in reports any default layouts. If it doesn't, then - // try setting a default layout compatible with the number of pins this - // plug-in is reporting. - if (! pluginHasDefaultChannelLayouts (effect)) - { - SpeakerMappings::VstSpeakerConfigurationHolder canonicalIn (AudioChannelSet::canonicalChannelSet (effect->numInputChannels)); - SpeakerMappings::VstSpeakerConfigurationHolder canonicalOut (AudioChannelSet::canonicalChannelSet (effect->numOutputChannels)); - - effect->dispatchFunction (effect, plugInOpcodeSetSpeakerConfiguration, 0, - (pointer_sized_int) &canonicalIn.get(), (void*) &canonicalOut.get(), 0.0f); - } - - HeapBlock inArrBlock (1, true), outArrBlock (1, true); - - auto* inArr = inArrBlock.get(); - auto* outArr = outArrBlock.get(); - - if (! getSpeakerArrangementWrapper (effect, inArr, outArr)) - inArr = outArr = nullptr; - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const int opcode = (isInput ? plugInOpcodeGetInputPinProperties : plugInOpcodeGetOutputPinProperties); - const int maxChannels = (isInput ? effect->numInputChannels : effect->numOutputChannels); - const VstSpeakerConfiguration* arr = (isInput ? inArr : outArr); - bool busAdded = false; - - VstPinInfo pinProps; - AudioChannelSet layout; - - for (int ch = 0; ch < maxChannels; ch += layout.size()) - { - if (effect->dispatchFunction (effect, opcode, ch, 0, &pinProps, 0.0f) == 0) - break; - - if ((pinProps.flags & vstPinInfoFlagValid) != 0) - { - layout = SpeakerMappings::vstArrangementTypeToChannelSet (pinProps.configurationType, 0); - - if (layout.isDisabled()) - break; - } - else if (arr == nullptr) - { - layout = ((pinProps.flags & vstPinInfoFlagIsStereo) != 0 ? AudioChannelSet::stereo() : AudioChannelSet::mono()); - } - else - break; - - busAdded = true; - returnValue.addBus (isInput, pinProps.text, layout, true); - } - - // no buses? - if (! busAdded && maxChannels > 0) - { - String busName = (isInput ? "Input" : "Output"); - - if (effect->dispatchFunction (effect, opcode, 0, 0, &pinProps, 0.0f) != 0) - busName = pinProps.text; - - if (arr != nullptr) - layout = SpeakerMappings::vstArrangementTypeToChannelSet (*arr); - else - layout = AudioChannelSet::canonicalChannelSet (maxChannels); - - returnValue.addBus (isInput, busName, layout, true); - } - } - - return returnValue; - } - - static bool pluginHasDefaultChannelLayouts (VstEffectInterface* effect) - { - HeapBlock inArrBlock (1, true), outArrBlock (1, true); - - auto* inArr = inArrBlock.get(); - auto* outArr = outArrBlock.get(); - - if (getSpeakerArrangementWrapper (effect, inArr, outArr)) - return true; - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const int opcode = (isInput ? plugInOpcodeGetInputPinProperties : plugInOpcodeGetOutputPinProperties); - const int maxChannels = (isInput ? effect->numInputChannels : effect->numOutputChannels); - - int channels = 1; - - for (int ch = 0; ch < maxChannels; ch += channels) - { - VstPinInfo pinProps; - - if (effect->dispatchFunction (effect, opcode, ch, 0, &pinProps, 0.0f) == 0) - return false; - - if ((pinProps.flags & vstPinInfoFlagValid) != 0) - return true; - - channels = (pinProps.flags & vstPinInfoFlagIsStereo) != 0 ? 2 : 1; - } - } - - return false; - } - - static bool getSpeakerArrangementWrapper (VstEffectInterface* effect, - VstSpeakerConfiguration* inArr, - VstSpeakerConfiguration* outArr) - { - // Workaround: unfortunately old JUCE VST-2 plug-ins had a bug and would crash if - // you try to get the speaker arrangement when there are no input channels present. - // Hopefully, one day (when there are no more old JUCE plug-ins around), we can - // commment out the next two lines. - if (effect->numInputChannels == 0) - return false; - - return (effect->dispatchFunction (effect, plugInOpcodeGetSpeakerArrangement, 0, - reinterpret_cast (&inArr), &outArr, 0.0f) != 0); - } - - //============================================================================== - template - void processAudio (AudioBuffer& buffer, MidiBuffer& midiMessages, - AudioBuffer& tmpBuffer, - HeapBlock& channelBuffer) - { - auto numSamples = buffer.getNumSamples(); - auto numChannels = buffer.getNumChannels(); - - if (initialised) - { - if (auto* currentPlayHead = getPlayHead()) - { - AudioPlayHead::CurrentPositionInfo position; - - if (currentPlayHead->getCurrentPosition (position)) - { - - vstHostTime.samplePosition = (double) position.timeInSamples; - vstHostTime.tempoBPM = position.bpm; - vstHostTime.timeSignatureNumerator = position.timeSigNumerator; - vstHostTime.timeSignatureDenominator = position.timeSigDenominator; - vstHostTime.musicalPosition = position.ppqPosition; - vstHostTime.lastBarPosition = position.ppqPositionOfLastBarStart; - vstHostTime.flags |= vstTimingInfoFlagTempoValid - | vstTimingInfoFlagTimeSignatureValid - | vstTimingInfoFlagMusicalPositionValid - | vstTimingInfoFlagLastBarPositionValid; - - int32 newTransportFlags = 0; - if (position.isPlaying) newTransportFlags |= vstTimingInfoFlagCurrentlyPlaying; - if (position.isRecording) newTransportFlags |= vstTimingInfoFlagCurrentlyRecording; - - if (newTransportFlags != (vstHostTime.flags & (vstTimingInfoFlagCurrentlyPlaying - | vstTimingInfoFlagCurrentlyRecording))) - vstHostTime.flags = (vstHostTime.flags & ~(vstTimingInfoFlagCurrentlyPlaying | vstTimingInfoFlagCurrentlyRecording)) | newTransportFlags | vstTimingInfoFlagTransportChanged; - else - vstHostTime.flags &= ~vstTimingInfoFlagTransportChanged; - - switch (position.frameRate) - { - case AudioPlayHead::fps24: setHostTimeFrameRate (vstSmpteRateFps24, 24.0, position.timeInSeconds); break; - case AudioPlayHead::fps25: setHostTimeFrameRate (vstSmpteRateFps25, 25.0, position.timeInSeconds); break; - case AudioPlayHead::fps30: setHostTimeFrameRate (vstSmpteRateFps30, 30.0, position.timeInSeconds); break; - case AudioPlayHead::fps60: setHostTimeFrameRate (vstSmpteRateFps60, 60.0, position.timeInSeconds); break; - - case AudioPlayHead::fps23976: setHostTimeFrameRateDrop (vstSmpteRateFps239, 24.0, position.timeInSeconds); break; - case AudioPlayHead::fps2997: setHostTimeFrameRateDrop (vstSmpteRateFps2997, 30.0, position.timeInSeconds); break; - case AudioPlayHead::fps2997drop: setHostTimeFrameRateDrop (vstSmpteRateFps2997drop, 30.0, position.timeInSeconds); break; - case AudioPlayHead::fps30drop: setHostTimeFrameRateDrop (vstSmpteRateFps30drop, 30.0, position.timeInSeconds); break; - case AudioPlayHead::fps60drop: setHostTimeFrameRateDrop (vstSmpteRateFps599, 60.0, position.timeInSeconds); break; - default: break; - } - - if (position.isLooping) - { - vstHostTime.loopStartPosition = position.ppqLoopStart; - vstHostTime.loopEndPosition = position.ppqLoopEnd; - vstHostTime.flags |= (vstTimingInfoFlagLoopPositionValid | vstTimingInfoFlagLoopActive); - } - else - { - vstHostTime.flags &= ~(vstTimingInfoFlagLoopPositionValid | vstTimingInfoFlagLoopActive); - } - } - } - - vstHostTime.systemTimeNanoseconds = getVSTHostTimeNanoseconds(); - - if (wantsMidiMessages) - { - midiEventsToSend.clear(); - midiEventsToSend.ensureSize (1); - - MidiBuffer::Iterator iter (midiMessages); - const uint8* midiData; - int numBytesOfMidiData, samplePosition; - - while (iter.getNextEvent (midiData, numBytesOfMidiData, samplePosition)) - midiEventsToSend.addEvent (midiData, numBytesOfMidiData, - jlimit (0, numSamples - 1, samplePosition)); - - vstEffect->dispatchFunction (vstEffect, plugInOpcodePreAudioProcessingEvents, 0, 0, midiEventsToSend.events, 0); - } - - _clearfp(); - - // always ensure that the buffer is at least as large as the maximum number of channels - auto maxChannels = jmax (vstEffect->numInputChannels, vstEffect->numOutputChannels); - auto channels = channelBuffer.get(); - - if (numChannels < maxChannels) - { - if (numSamples > tmpBuffer.getNumSamples()) - tmpBuffer.setSize (tmpBuffer.getNumChannels(), numSamples); - - tmpBuffer.clear(); - } - - for (int ch = 0; ch < maxChannels; ++ch) - channels[ch] = (ch < numChannels ? buffer.getWritePointer (ch) : tmpBuffer.getWritePointer (ch)); - - { - AudioBuffer processBuffer (channels, maxChannels, numSamples); - - invokeProcessFunction (processBuffer, numSamples); - } - } - else - { - // Not initialised, so just bypass.. - for (int i = getTotalNumOutputChannels(); --i >= 0;) - buffer.clear (i, 0, buffer.getNumSamples()); - } - - { - // copy any incoming midi.. - const ScopedLock sl (midiInLock); - - midiMessages.swapWith (incomingMidi); - incomingMidi.clear(); - } - } - - //============================================================================== - inline void invokeProcessFunction (AudioBuffer& buffer, int32 sampleFrames) - { - if ((vstEffect->flags & vstEffectFlagInplaceAudio) != 0) - { - vstEffect->processAudioInplaceFunction (vstEffect, buffer.getArrayOfWritePointers(), - buffer.getArrayOfWritePointers(), sampleFrames); - } - else - { - outOfPlaceBuffer.setSize (vstEffect->numOutputChannels, sampleFrames); - outOfPlaceBuffer.clear(); - - vstEffect->processAudioFunction (vstEffect, buffer.getArrayOfWritePointers(), - outOfPlaceBuffer.getArrayOfWritePointers(), sampleFrames); - - for (int i = vstEffect->numOutputChannels; --i >= 0;) - buffer.copyFrom (i, 0, outOfPlaceBuffer.getReadPointer (i), sampleFrames); - } - } - - inline void invokeProcessFunction (AudioBuffer& buffer, int32 sampleFrames) - { - vstEffect->processDoubleAudioInplaceFunction (vstEffect, buffer.getArrayOfWritePointers(), - buffer.getArrayOfWritePointers(), sampleFrames); - } - - //============================================================================== - void setHostTimeFrameRate (long frameRateIndex, double frameRate, double currentTime) noexcept - { - vstHostTime.flags |= vstTimingInfoFlagSmpteValid; - vstHostTime.smpteRate = (int32) frameRateIndex; - vstHostTime.smpteOffset = (int32) (currentTime * 80.0 * frameRate + 0.5); - } - - void setHostTimeFrameRateDrop (long frameRateIndex, double frameRate, double currentTime) noexcept - { - setHostTimeFrameRate (frameRateIndex, frameRate * 1000.0 / 1001.0, currentTime); - } - - bool restoreProgramSettings (const fxProgram* const prog) - { - if (compareMagic (prog->chunkMagic, "CcnK") - && compareMagic (prog->fxMagic, "FxCk")) - { - changeProgramName (getCurrentProgram(), prog->prgName); - - for (int i = 0; i < fxbSwap (prog->numParams); ++i) - setParameter (i, fxbSwapFloat (prog->params[i])); - - return true; - } - - return false; - } - - String getTextForOpcode (const int index, const VstHostToPlugInOpcodes opcode) const - { - if (vstEffect == nullptr) - return {}; - - jassert (index >= 0 && index < vstEffect->numParameters); - char nm[256] = { 0 }; - dispatch (opcode, index, 0, nm, 0); - return String::createStringFromData (nm, (int) sizeof (nm)).trim(); - } - - String getCurrentProgramName() - { - String progName; - - if (vstEffect != nullptr) - { - { - char nm[256] = { 0 }; - dispatch (plugInOpcodeGetCurrentProgramName, 0, 0, nm, 0); - progName = String::createStringFromData (nm, (int) sizeof (nm)).trim(); - } - - const int index = getCurrentProgram(); - - if (index >= 0 && programNames[index].isEmpty()) - { - while (programNames.size() < index) - programNames.add (String()); - - programNames.set (index, progName); - } - } - - return progName; - } - - void setParamsInProgramBlock (fxProgram* prog) - { - auto numParams = getNumParameters(); - - prog->chunkMagic = fxbName ("CcnK"); - prog->byteSize = 0; - prog->fxMagic = fxbName ("FxCk"); - prog->version = fxbSwap (fxbVersionNum); - prog->fxID = fxbSwap (getUID()); - prog->fxVersion = fxbSwap (getVersionNumber()); - prog->numParams = fxbSwap (numParams); - - getCurrentProgramName().copyToUTF8 (prog->prgName, sizeof (prog->prgName) - 1); - - for (int i = 0; i < numParams; ++i) - prog->params[i] = fxbSwapFloat (getParameter (i)); - } - - void updateStoredProgramNames() - { - if (vstEffect != nullptr && getNumPrograms() > 0) - { - char nm[256] = { 0 }; - - // only do this if the plugin can't use indexed names.. - if (dispatch (plugInOpcodeGetProgramName, 0, -1, nm, 0) == 0) - { - auto oldProgram = getCurrentProgram(); - MemoryBlock oldSettings; - createTempParameterStore (oldSettings); - - for (int i = 0; i < getNumPrograms(); ++i) - { - setCurrentProgram (i); - getCurrentProgramName(); // (this updates the list) - } - - setCurrentProgram (oldProgram); - restoreFromTempParameterStore (oldSettings); - } - } - } - - void handleMidiFromPlugin (const VstEventBlock* events) - { - if (events != nullptr) - { - const ScopedLock sl (midiInLock); - VSTMidiEventList::addEventsToMidiBuffer (events, incomingMidi); - } - } - - //============================================================================== - void createTempParameterStore (MemoryBlock& dest) - { - dest.setSize (64 + 4 * (size_t) getNumParameters()); - dest.fillWith (0); - - getCurrentProgramName().copyToUTF8 ((char*) dest.getData(), 63); - - auto p = (float*) (((char*) dest.getData()) + 64); - - for (int i = 0; i < getNumParameters(); ++i) - p[i] = getParameter(i); - } - - void restoreFromTempParameterStore (const MemoryBlock& m) - { - changeProgramName (getCurrentProgram(), (const char*) m.getData()); - - auto p = (float*) (((char*) m.getData()) + 64); - - for (int i = 0; i < getNumParameters(); ++i) - setParameter (i, p[i]); - } - - pointer_sized_int getVstDirectory() const - { - #if JUCE_MAC - return (pointer_sized_int) (void*) &vstModule->parentDirFSSpec; - #else - return (pointer_sized_int) (pointer_sized_uint) vstModule->fullParentDirectoryPathName.toRawUTF8(); - #endif - } - - //============================================================================== - int getVersionNumber() const noexcept { return vstEffect != nullptr ? vstEffect->plugInVersion : 0; } - - String getVersion() const - { - auto v = (unsigned int) dispatch (plugInOpcodeGetManufacturerVersion, 0, 0, 0, 0); - - String s; - - if (v == 0 || (int) v == -1) - v = (unsigned int) getVersionNumber(); - - if (v != 0) - { - int versionBits[32]; - int n = 0; - - for (auto vv = v; vv != 0; vv /= 10) - versionBits [n++] = vv % 10; - - if (n > 4) // if the number ends up silly, it's probably encoded as hex instead of decimal.. - { - n = 0; - - for (auto vv = v; vv != 0; vv >>= 8) - versionBits [n++] = vv & 255; - } - - while (n > 1 && versionBits [n - 1] == 0) - --n; - - s << 'V'; - - while (n > 0) - { - s << versionBits [--n]; - - if (n > 0) - s << '.'; - } - } - - return s; - } - - const char* getCategory() const - { - switch (getVstCategory()) - { - case kPlugCategEffect: return "Effect"; - case kPlugCategSynth: return "Synth"; - case kPlugCategAnalysis: return "Analysis"; - case kPlugCategMastering: return "Mastering"; - case kPlugCategSpacializer: return "Spacial"; - case kPlugCategRoomFx: return "Reverb"; - case kPlugSurroundFx: return "Surround"; - case kPlugCategRestoration: return "Restoration"; - case kPlugCategGenerator: return "Tone generation"; - default: break; - } - - return nullptr; - } - - void setPower (const bool on) - { - dispatch (plugInOpcodeResumeSuspend, 0, on ? 1 : 0, 0, 0); - isPowerOn = on; - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VSTPluginInstance) -}; - -//============================================================================== -#if ! (JUCE_IOS || JUCE_ANDROID) -struct VSTPluginWindow; -static Array activeVSTWindows; - -//============================================================================== -struct VSTPluginWindow : public AudioProcessorEditor, - #if ! JUCE_MAC - private ComponentMovementWatcher, - #endif - private Timer -{ -public: - VSTPluginWindow (VSTPluginInstance& plug) - : AudioProcessorEditor (&plug), - #if ! JUCE_MAC - ComponentMovementWatcher (this), - #endif - plugin (plug) - { - #if JUCE_LINUX - pluginWindow = None; - display = XWindowSystem::getInstance()->displayRef(); - - #elif JUCE_MAC - ignoreUnused (recursiveResize, pluginRefusesToResize, alreadyInside); - - #if JUCE_SUPPORT_CARBON - if (! plug.usesCocoaNSView) - addAndMakeVisible (carbonWrapper = new CarbonWrapperComponent (*this)); - else - #endif - addAndMakeVisible (cocoaWrapper = new AutoResizingNSViewComponentWithParent()); - #endif - - activeVSTWindows.add (this); - - setSize (1, 1); - setOpaque (true); - setVisible (true); - } - - ~VSTPluginWindow() - { - closePluginWindow(); - - #if JUCE_MAC - #if JUCE_SUPPORT_CARBON - carbonWrapper = nullptr; - #endif - cocoaWrapper = nullptr; - #elif JUCE_LINUX - display = XWindowSystem::getInstance()->displayUnref(); - #endif - - activeVSTWindows.removeFirstMatchingValue (this); - plugin.editorBeingDeleted (this); - } - - //============================================================================== - #if ! JUCE_MAC - void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override - { - if (recursiveResize) - return; - - auto* topComp = getTopLevelComponent(); - - if (topComp->getPeer() != nullptr) - { - auto pos = topComp->getLocalPoint (this, Point()); - - recursiveResize = true; - - #if JUCE_WINDOWS - if (pluginHWND != 0) - MoveWindow (pluginHWND, pos.getX(), pos.getY(), getWidth(), getHeight(), TRUE); - #elif JUCE_LINUX - if (pluginWindow != 0) - { - XMoveResizeWindow (display, pluginWindow, - pos.getX(), pos.getY(), - (unsigned int) getWidth(), - (unsigned int) getHeight()); - - XMapRaised (display, pluginWindow); - XFlush (display); - } - #endif - - recursiveResize = false; - } - } - - void componentVisibilityChanged() override - { - if (isShowing()) - openPluginWindow(); - else if (! shouldAvoidDeletingWindow()) - closePluginWindow(); - - componentMovedOrResized (true, true); - } - - void componentPeerChanged() override - { - closePluginWindow(); - openPluginWindow(); - - #if JUCE_LINUX - componentMovedOrResized (true, true); - #endif - } - #endif - - #if JUCE_MAC - void visibilityChanged() override - { - if (cocoaWrapper != nullptr) - { - if (isVisible()) - openPluginWindow ((NSView*) cocoaWrapper->getView()); - else - closePluginWindow(); - } - } - - void childBoundsChanged (Component*) override - { - if (cocoaWrapper != nullptr) - { - auto w = cocoaWrapper->getWidth(); - auto h = cocoaWrapper->getHeight(); - - if (w != getWidth() || h != getHeight()) - setSize (w, h); - } - } - #endif - - //============================================================================== - bool keyStateChanged (bool) override { return pluginWantsKeys; } - bool keyPressed (const juce::KeyPress&) override { return pluginWantsKeys; } - - //============================================================================== - #if JUCE_MAC - void paint (Graphics& g) override - { - g.fillAll (Colours::black); - } - #else - void paint (Graphics& g) override - { - if (isOpen) - { - #if JUCE_LINUX - if (pluginWindow != 0) - { - auto clip = g.getClipBounds(); - - XClearArea (display, pluginWindow, - clip.getX(), clip.getY(), - static_cast (clip.getWidth()), - static_cast (clip.getHeight()), - True); - } - #endif - } - else - { - g.fillAll (Colours::black); - } - } - #endif - - //============================================================================== - void timerCallback() override - { - if (isShowing()) - { - #if JUCE_WINDOWS - if (--sizeCheckCount <= 0) - { - sizeCheckCount = 10; - checkPluginWindowSize(); - } - #endif - - static bool reentrantGuard = false; - - if (! reentrantGuard) - { - reentrantGuard = true; - plugin.dispatch (plugInOpcodeEditorIdle, 0, 0, 0, 0); - reentrantGuard = false; - } - - #if JUCE_LINUX - if (pluginWindow == 0) - { - updatePluginWindowHandle(); - - if (pluginWindow != 0) - componentMovedOrResized (true, true); - } - #endif - } - } - - //============================================================================== - void mouseDown (const MouseEvent& e) override - { - ignoreUnused (e); - - #if JUCE_WINDOWS || JUCE_LINUX - toFront (true); - #endif - } - - void broughtToFront() override - { - activeVSTWindows.removeFirstMatchingValue (this); - activeVSTWindows.add (this); - - #if JUCE_MAC - dispatch (plugInOpcodeeffEditorTop, 0, 0, 0, 0); - #endif - } - - void setScaleFactor (float newScale) override - { - scaleFactor = newScale; - dispatch (plugInOpcodeManufacturerSpecific, presonusVendorID, - presonusSetContentScaleFactor, nullptr, newScale); - } - - void sendScaleFactorIfNotUnity() - { - if (scaleFactor != 1.0f) - setScaleFactor (scaleFactor); - } - - //============================================================================== -private: - VSTPluginInstance& plugin; - float scaleFactor = 1.0f; - bool isOpen = false, recursiveResize = false; - bool pluginWantsKeys = false, pluginRefusesToResize = false, alreadyInside = false; - - #if JUCE_WINDOWS - HWND pluginHWND = {}; - void* originalWndProc = {}; - int sizeCheckCount = 0; - #elif JUCE_LINUX - ::Display* display; - Window pluginWindow; - #endif - - // This is a workaround for old Mackie plugins that crash if their - // window is deleted more than once. - bool shouldAvoidDeletingWindow() const - { - return plugin.getPluginDescription() - .manufacturerName.containsIgnoreCase ("Loud Technologies"); - } - - // This is an old workaround for some plugins that need a repaint when their - // windows are first created, but it breaks some Izotope plugins.. - bool shouldRepaintCarbonWindowWhenCreated() - { - return ! plugin.getName().containsIgnoreCase ("izotope"); - } - - //============================================================================== -#if JUCE_MAC - void openPluginWindow (void* parentWindow) - { - if (isOpen || parentWindow == 0) - return; - - isOpen = true; - - VstEditorBounds* rect = nullptr; - dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); - dispatch (plugInOpcodeOpenEditor, 0, 0, parentWindow, 0); - sendScaleFactorIfNotUnity(); - - // do this before and after like in the steinberg example - dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); - dispatch (plugInOpcodeGetCurrentProgram, 0, 0, 0, 0); // also in steinberg code - - // Install keyboard hooks - pluginWantsKeys = (dispatch (plugInOpcodeKeyboardFocusRequired, 0, 0, 0, 0) == 0); - - // double-check it's not too tiny - int w = 250, h = 150; - - if (rect != nullptr) - { - w = rect->rightmost - rect->leftmost; - h = rect->lower - rect->upper; - - if (w == 0 || h == 0) - { - w = 250; - h = 150; - } - } - - w = jmax (w, 32); - h = jmax (h, 32); - - setSize (w, h); - - startTimer (18 + juce::Random::getSystemRandom().nextInt (5)); - repaint(); - } - -#else - void openPluginWindow() - { - if (isOpen || getWindowHandle() == 0) - return; - - JUCE_VST_LOG ("Opening VST UI: " + plugin.getName()); - isOpen = true; - - VstEditorBounds* rect = nullptr; - dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); - dispatch (plugInOpcodeOpenEditor, 0, 0, getWindowHandle(), 0); - sendScaleFactorIfNotUnity(); - - // do this before and after like in the steinberg example - dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); - dispatch (plugInOpcodeGetCurrentProgram, 0, 0, 0, 0); // also in steinberg code - - // Install keyboard hooks - pluginWantsKeys = (dispatch (plugInOpcodeKeyboardFocusRequired, 0, 0, 0, 0) == 0); - - #if JUCE_WINDOWS - originalWndProc = 0; - pluginHWND = GetWindow ((HWND) getWindowHandle(), GW_CHILD); - - if (pluginHWND == 0) - { - isOpen = false; - setSize (300, 150); - return; - } - - #pragma warning (push) - #pragma warning (disable: 4244) - - if (! pluginWantsKeys) - { - originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC); - SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc); - } - - #pragma warning (pop) - - RECT r; - GetWindowRect (pluginHWND, &r); - int w = r.right - r.left; - int h = r.bottom - r.top; - - if (rect != nullptr) - { - const int rw = rect->rightmost - rect->leftmost; - const int rh = rect->lower - rect->upper; - - if ((rw > 50 && rh > 50 && rw < 2000 && rh < 2000 && rw != w && rh != h) - || ((w == 0 && rw > 0) || (h == 0 && rh > 0))) - { - // very dodgy logic to decide which size is right. - if (abs (rw - w) > 350 || abs (rh - h) > 350) - { - SetWindowPos (pluginHWND, 0, - 0, 0, rw, rh, - SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); - - GetWindowRect (pluginHWND, &r); - - w = r.right - r.left; - h = r.bottom - r.top; - - pluginRefusesToResize = (w != rw) || (h != rh); - - w = rw; - h = rh; - } - } - } - - #elif JUCE_LINUX - updatePluginWindowHandle(); - - int w = 250, h = 150; - - if (rect != nullptr) - { - w = rect->rightmost - rect->leftmost; - h = rect->lower - rect->upper; - - if (w == 0 || h == 0) - { - w = 250; - h = 150; - } - } - - if (pluginWindow != 0) - XMapRaised (display, pluginWindow); - #endif - - // double-check it's not too tiny - w = jmax (w, 32); - h = jmax (h, 32); - - setSize (w, h); - - #if JUCE_WINDOWS - checkPluginWindowSize(); - #endif - - startTimer (18 + juce::Random::getSystemRandom().nextInt (5)); - repaint(); - } -#endif - - //============================================================================== - void closePluginWindow() - { - if (isOpen) - { - // You shouldn't end up hitting this assertion unless the host is trying to do GUI - // cleanup on a non-GUI thread.. If it does that, bad things could happen in here.. - jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); - - JUCE_VST_LOG ("Closing VST UI: " + plugin.getName()); - isOpen = false; - dispatch (plugInOpcodeCloseEditor, 0, 0, 0, 0); - stopTimer(); - - #if JUCE_WINDOWS - #pragma warning (push) - #pragma warning (disable: 4244) - if (originalWndProc != 0 && pluginHWND != 0 && IsWindow (pluginHWND)) - SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc); - #pragma warning (pop) - - originalWndProc = 0; - pluginHWND = 0; - #elif JUCE_LINUX - pluginWindow = 0; - #endif - } - } - - //============================================================================== - pointer_sized_int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) - { - return plugin.dispatch (opcode, index, value, ptr, opt); - } - - //============================================================================== - #if JUCE_WINDOWS - void checkPluginWindowSize() - { - RECT r; - GetWindowRect (pluginHWND, &r); - auto w = r.right - r.left; - auto h = r.bottom - r.top; - - if (isShowing() && w > 0 && h > 0 - && (w != getWidth() || h != getHeight()) - && ! pluginRefusesToResize) - { - setSize (w, h); - sizeCheckCount = 0; - } - } - - // hooks to get keyboard events from VST windows.. - static LRESULT CALLBACK vstHookWndProc (HWND hW, UINT message, WPARAM wParam, LPARAM lParam) - { - for (int i = activeVSTWindows.size(); --i >= 0;) - { - Component::SafePointer w (activeVSTWindows[i]); - - if (w != nullptr && w->pluginHWND == hW) - { - if (message == WM_CHAR - || message == WM_KEYDOWN - || message == WM_SYSKEYDOWN - || message == WM_KEYUP - || message == WM_SYSKEYUP - || message == WM_APPCOMMAND) - { - SendMessage ((HWND) w->getTopLevelComponent()->getWindowHandle(), - message, wParam, lParam); - } - - if (w != nullptr) // (may have been deleted in SendMessage callback) - return CallWindowProc ((WNDPROC) w->originalWndProc, - (HWND) w->pluginHWND, - message, wParam, lParam); - } - } - - return DefWindowProc (hW, message, wParam, lParam); - } - #endif - - #if JUCE_LINUX - void updatePluginWindowHandle() - { - pluginWindow = getChildWindow ((Window) getWindowHandle()); - } - #endif - - //============================================================================== -#if JUCE_MAC - #if JUCE_SUPPORT_CARBON - struct CarbonWrapperComponent : public CarbonViewWrapperComponent - { - CarbonWrapperComponent (VSTPluginWindow& w) : owner (w) - { - keepPluginWindowWhenHidden = w.shouldAvoidDeletingWindow(); - setRepaintsChildHIViewWhenCreated (w.shouldRepaintCarbonWindowWhenCreated()); - } - - ~CarbonWrapperComponent() - { - deleteWindow(); - } - - HIViewRef attachView (WindowRef windowRef, HIViewRef /*rootView*/) override - { - owner.openPluginWindow (windowRef); - return {}; - } - - void removeView (HIViewRef) override - { - if (owner.isOpen) - { - owner.isOpen = false; - owner.dispatch (plugInOpcodeCloseEditor, 0, 0, 0, 0); - owner.dispatch (plugInOpcodeSleepEditor, 0, 0, 0, 0); - } - } - - bool getEmbeddedViewSize (int& w, int& h) override - { - VstEditorBounds* rect = nullptr; - owner.dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); - w = rect->rightmost - rect->leftmost; - h = rect->lower - rect->upper; - return true; - } - - void handleMouseDown (int x, int y) override - { - if (! alreadyInside) - { - alreadyInside = true; - getTopLevelComponent()->toFront (true); - owner.dispatch (plugInOpcodeGetMouse, x, y, 0, 0); - alreadyInside = false; - } - else - { - PostEvent (::mouseDown, 0); - } - } - - void handlePaint() override - { - if (auto* peer = getPeer()) - { - auto pos = peer->globalToLocal (getScreenPosition()); - VstEditorBounds r; - r.leftmost = (int16) pos.getX(); - r.upper = (int16) pos.getY(); - r.rightmost = (int16) (r.leftmost + getWidth()); - r.lower = (int16) (r.upper + getHeight()); - - owner.dispatch (plugInOpcodeDrawEditor, 0, 0, &r, 0); - } - } - - private: - VSTPluginWindow& owner; - bool alreadyInside = false; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CarbonWrapperComponent) - }; - - friend struct CarbonWrapperComponent; - ScopedPointer carbonWrapper; - #endif - - ScopedPointer cocoaWrapper; - - void resized() override - { - #if JUCE_SUPPORT_CARBON - if (carbonWrapper != nullptr) - carbonWrapper->setSize (getWidth(), getHeight()); - #endif - - if (cocoaWrapper != nullptr) - cocoaWrapper->setSize (getWidth(), getHeight()); - } -#endif - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VSTPluginWindow) -}; -#endif -#if JUCE_MSVC - #pragma warning (pop) -#endif - -//============================================================================== -AudioProcessorEditor* VSTPluginInstance::createEditor() -{ - #if JUCE_IOS || JUCE_ANDROID - return nullptr; - #else - return hasEditor() ? new VSTPluginWindow (*this) - : nullptr; - #endif -} - -//============================================================================== -// entry point for all callbacks from the plugin -static pointer_sized_int VSTINTERFACECALL audioMaster (VstEffectInterface* effect, int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt) -{ - if (effect != nullptr) - if (auto* instance = (VSTPluginInstance*) (effect->hostSpace2)) - return instance->handleCallback (opcode, index, value, ptr, opt); - - return VSTPluginInstance::handleGeneralCallback (opcode, index, value, ptr, opt); -} - -//============================================================================== -VSTPluginFormat::VSTPluginFormat() {} -VSTPluginFormat::~VSTPluginFormat() {} - -static VSTPluginInstance* createAndUpdateDesc (VSTPluginFormat& format, PluginDescription& desc) -{ - if (auto* p = format.createInstanceFromDescription (desc, 44100.0, 512)) - { - if (auto* instance = dynamic_cast (p)) - { - #if JUCE_MAC - if (instance->vstModule->resFileId != 0) - UseResFile (instance->vstModule->resFileId); - #endif - - instance->fillInPluginDescription (desc); - return instance; - } - - jassertfalse; - } - - return nullptr; -} - -void VSTPluginFormat::findAllTypesForFile (OwnedArray& results, - const String& fileOrIdentifier) -{ - if (! fileMightContainThisPluginType (fileOrIdentifier)) - return; - - PluginDescription desc; - desc.fileOrIdentifier = fileOrIdentifier; - desc.uid = 0; - - ScopedPointer instance (createAndUpdateDesc (*this, desc)); - - if (instance == nullptr) - return; - - if (instance->getVstCategory() != kPlugCategShell) - { - // Normal plugin... - results.add (new PluginDescription (desc)); - - instance->dispatch (plugInOpcodeOpen, 0, 0, 0, 0); - } - else - { - // It's a shell plugin, so iterate all the subtypes... - for (;;) - { - char shellEffectName [256] = { 0 }; - auto uid = (int) instance->dispatch (plugInOpcodeNextPlugInUniqueID, 0, 0, shellEffectName, 0); - - if (uid == 0) - break; - - desc.uid = uid; - desc.name = shellEffectName; - - aboutToScanVSTShellPlugin (desc); - - ScopedPointer shellInstance (createAndUpdateDesc (*this, desc)); - - if (shellInstance != nullptr) - { - jassert (desc.uid == uid); - desc.hasSharedContainer = true; - desc.name = shellEffectName; - - if (! arrayContainsPlugin (results, desc)) - results.add (new PluginDescription (desc)); - } - } - } -} - -void VSTPluginFormat::createPluginInstance (const PluginDescription& desc, - double sampleRate, - int blockSize, - void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) -{ - ScopedPointer result; - - if (fileMightContainThisPluginType (desc.fileOrIdentifier)) - { - File file (desc.fileOrIdentifier); - - auto previousWorkingDirectory = File::getCurrentWorkingDirectory(); - file.getParentDirectory().setAsCurrentWorkingDirectory(); - - if (auto module = ModuleHandle::findOrCreateModule (file)) - { - shellUIDToCreate = desc.uid; - - result = VSTPluginInstance::create (module, sampleRate, blockSize); - - if (result != nullptr && ! result->initialiseEffect (sampleRate, blockSize)) - result = nullptr; - } - - previousWorkingDirectory.setAsCurrentWorkingDirectory(); - } - - String errorMsg; - - if (result == nullptr) - errorMsg = String (NEEDS_TRANS ("Unable to load XXX plug-in file")).replace ("XXX", "VST-2"); - - callback (userData, result.release(), errorMsg); -} - -bool VSTPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept -{ - return false; -} - -bool VSTPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) -{ - auto f = File::createFileWithoutCheckingPath (fileOrIdentifier); - - #if JUCE_MAC || JUCE_IOS - return f.isDirectory() && f.hasFileExtension (".vst"); - #elif JUCE_WINDOWS - return f.existsAsFile() && f.hasFileExtension (".dll"); - #elif JUCE_LINUX || JUCE_ANDROID - return f.existsAsFile() && f.hasFileExtension (".so"); - #endif -} - -String VSTPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) -{ - return fileOrIdentifier; -} - -bool VSTPluginFormat::pluginNeedsRescanning (const PluginDescription& desc) -{ - return File (desc.fileOrIdentifier).getLastModificationTime() != desc.lastFileModTime; -} - -bool VSTPluginFormat::doesPluginStillExist (const PluginDescription& desc) -{ - return File (desc.fileOrIdentifier).exists(); -} - -StringArray VSTPluginFormat::searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive, bool) -{ - StringArray results; - - for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j) - recursiveFileSearch (results, directoriesToSearch [j], recursive); - - return results; -} - -void VSTPluginFormat::recursiveFileSearch (StringArray& results, const File& dir, const bool recursive) -{ - // avoid allowing the dir iterator to be recursive, because we want to avoid letting it delve inside - // .component or .vst directories. - DirectoryIterator iter (dir, false, "*", File::findFilesAndDirectories); - - while (iter.next()) - { - auto f = iter.getFile(); - bool isPlugin = false; - - if (fileMightContainThisPluginType (f.getFullPathName())) - { - isPlugin = true; - results.add (f.getFullPathName()); - } - - if (recursive && (! isPlugin) && f.isDirectory()) - recursiveFileSearch (results, f, true); - } -} - -FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() -{ - #if JUCE_MAC - return FileSearchPath ("~/Library/Audio/Plug-Ins/VST;/Library/Audio/Plug-Ins/VST"); - #elif JUCE_LINUX || JUCE_ANDROID - return FileSearchPath (SystemStats::getEnvironmentVariable ("VST_PATH", - "/usr/lib/vst;/usr/local/lib/vst;~/.vst") - .replace (":", ";")); - #elif JUCE_WINDOWS - auto programFiles = File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName(); - - FileSearchPath paths; - paths.add (WindowsRegistry::getValue ("HKEY_LOCAL_MACHINE\\Software\\VST\\VSTPluginsPath")); - paths.addIfNotAlreadyThere (programFiles + "\\Steinberg\\VstPlugins"); - paths.removeNonExistentPaths(); - paths.addIfNotAlreadyThere (programFiles + "\\VstPlugins"); - paths.removeRedundantPaths(); - return paths; - #elif JUCE_IOS - // on iOS you can only load plug-ins inside the hosts bundle folder - CFURLRef relativePluginDir = CFBundleCopyBuiltInPlugInsURL (CFBundleGetMainBundle()); - CFURLRef pluginDir = CFURLCopyAbsoluteURL (relativePluginDir); - CFRelease (relativePluginDir); - - CFStringRef path = CFURLCopyFileSystemPath (pluginDir, kCFURLPOSIXPathStyle); - CFRelease (pluginDir); - - FileSearchPath retval (String (CFStringGetCStringPtr (path, kCFStringEncodingUTF8))); - CFRelease (path); - - return retval; - #endif -} - -const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin) -{ - if (auto* vst = dynamic_cast (plugin)) - if (vst->vstModule != nullptr) - return vst->vstModule->vstXml.get(); - - return nullptr; -} - -bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin, const void* data, size_t dataSize) -{ - if (auto* vst = dynamic_cast (plugin)) - return vst->loadFromFXBFile (data, dataSize); - - return false; -} - -bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& dest, bool asFXB) -{ - if (auto* vst = dynamic_cast (plugin)) - return vst->saveToFXBFile (dest, asFXB); - - return false; -} - -bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& result, bool isPreset) -{ - if (auto* vst = dynamic_cast (plugin)) - return vst->getChunkData (result, isPreset, 128); - - return false; -} - -bool VSTPluginFormat::setChunkData (AudioPluginInstance* plugin, const void* data, int size, bool isPreset) -{ - if (auto* vst = dynamic_cast (plugin)) - return vst->setChunkData (data, size, isPreset); - - return false; -} - -AudioPluginInstance* VSTPluginFormat::createCustomVSTFromMainCall (void* entryPointFunction, - double initialSampleRate, int initialBufferSize) -{ - ModuleHandle::Ptr module = new ModuleHandle (File(), (MainCall) entryPointFunction); - - if (module->open()) - if (ScopedPointer result = VSTPluginInstance::create (module, initialSampleRate, initialBufferSize)) - if (result->initialiseEffect (initialSampleRate, initialBufferSize)) - return result.release(); - - return nullptr; -} - -void VSTPluginFormat::setExtraFunctions (AudioPluginInstance* plugin, ExtraFunctions* functions) -{ - ScopedPointer f (functions); - - if (auto* vst = dynamic_cast (plugin)) - vst->extraFunctions = f; -} - -AudioPluginInstance* VSTPluginFormat::getPluginInstanceFromVstEffectInterface (void* aEffect) -{ - if (auto* vstAEffect = reinterpret_cast (aEffect)) - if (auto* instanceVST = reinterpret_cast (vstAEffect->hostSpace2)) - return dynamic_cast (instanceVST); - - return nullptr; -} - -pointer_sized_int JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPluginInstance* plugin, int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt) -{ - if (auto* vst = dynamic_cast (plugin)) - return vst->dispatch (opcode, index, value, ptr, opt); - - return {}; -} - -void VSTPluginFormat::aboutToScanVSTShellPlugin (const PluginDescription&) {} - -} // namespace juce - -#endif diff --git a/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h b/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h deleted file mode 100644 index 1edeb83e1..000000000 --- a/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -#if (JUCE_PLUGINHOST_VST || DOXYGEN) - -namespace juce -{ - -//============================================================================== -/** - Implements a plugin format manager for VSTs. -*/ -class JUCE_API VSTPluginFormat : public AudioPluginFormat -{ -public: - //============================================================================== - VSTPluginFormat(); - ~VSTPluginFormat(); - - //============================================================================== - /** Attempts to retrieve the VSTXML data from a plugin. - Will return nullptr if the plugin isn't a VST, or if it doesn't have any VSTXML. - */ - static const XmlElement* getVSTXML (AudioPluginInstance* plugin); - - /** Attempts to reload a VST plugin's state from some FXB or FXP data. */ - static bool loadFromFXBFile (AudioPluginInstance* plugin, const void* data, size_t dataSize); - - /** Attempts to save a VST's state to some FXP or FXB data. */ - static bool saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& result, bool asFXB); - - /** Attempts to get a VST's state as a chunk of memory. */ - static bool getChunkData (AudioPluginInstance* plugin, MemoryBlock& result, bool isPreset); - - /** Attempts to set a VST's state from a chunk of memory. */ - static bool setChunkData (AudioPluginInstance* plugin, const void* data, int size, bool isPreset); - - /** Given a suitable function pointer to a VSTPluginMain function, this will attempt to - instantiate and return a plugin for it. - */ - static AudioPluginInstance* createCustomVSTFromMainCall (void* entryPointFunction, - double initialSampleRate, - int initialBufferSize); - - //============================================================================== - /** Base class for some extra functions that can be attached to a VST plugin instance. */ - class ExtraFunctions - { - public: - virtual ~ExtraFunctions() {} - - /** This should return 10000 * the BPM at this position in the current edit. */ - virtual int64 getTempoAt (int64 samplePos) = 0; - - /** This should return the host's automation state. - @returns 0 = not supported, 1 = off, 2 = read, 3 = write, 4 = read/write - */ - virtual int getAutomationState() = 0; - }; - - /** Provides an ExtraFunctions callback object for a plugin to use. - The plugin will take ownership of the object and will delete it automatically. - */ - static void setExtraFunctions (AudioPluginInstance* plugin, ExtraFunctions* functions); - - //============================================================================== - /** This simply calls directly to the VST's AEffect::dispatcher() function. */ - static pointer_sized_int JUCE_CALLTYPE dispatcher (AudioPluginInstance*, int32, int32, pointer_sized_int, void*, float); - - /** Given a VstEffectInterface* (aka vst::AEffect*), this will return the juce AudioPluginInstance - that is being used to wrap it - */ - static AudioPluginInstance* getPluginInstanceFromVstEffectInterface (void* aEffect); - - //============================================================================== - String getName() const override { return "VST"; } - void findAllTypesForFile (OwnedArray&, const String& fileOrIdentifier) override; - bool fileMightContainThisPluginType (const String& fileOrIdentifier) override; - String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override; - bool pluginNeedsRescanning (const PluginDescription&) override; - StringArray searchPathsForPlugins (const FileSearchPath&, bool recursive, bool) override; - bool doesPluginStillExist (const PluginDescription&) override; - FileSearchPath getDefaultLocationsToSearch() override; - bool canScanForPlugins() const override { return true; } - - /** Can be overridden to receive a callback when each member of a shell plugin is about to be - tested during a call to findAllTypesForFile(). - Only the name and uid members of the PluginDescription are guaranteed to be valid when - this is called. - */ - virtual void aboutToScanVSTShellPlugin (const PluginDescription&); - -private: - //============================================================================== - void createPluginInstance (const PluginDescription&, double initialSampleRate, - int initialBufferSize, void* userData, - void (*callback) (void*, AudioPluginInstance*, const String&)) override; - - bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; - -private: - void recursiveFileSearch (StringArray&, const File&, bool recursive); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VSTPluginFormat) -}; - -} // namespace juce - -#endif diff --git a/source/modules/juce_audio_processors/juce_audio_processors.cpp b/source/modules/juce_audio_processors/juce_audio_processors.cpp deleted file mode 100644 index 675784f1c..000000000 --- a/source/modules/juce_audio_processors/juce_audio_processors.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -#ifdef JUCE_AUDIO_PROCESSORS_H_INCLUDED - /* When you add this cpp file to your project, you mustn't include it in a file where you've - already included any other headers - just put it inside a file on its own, possibly with your config - flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix - header files that the compiler may be using. - */ - #error "Incorrect use of JUCE cpp file" -#endif - -#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 -#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 - -#include "juce_audio_processors.h" -#include - -//============================================================================== -#if JUCE_MAC - #if JUCE_SUPPORT_CARBON \ - && ((JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_AU) \ - || ! (defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)) - #include - #include "../juce_gui_extra/native/juce_mac_CarbonViewWrapperComponent.h" - #endif -#endif - -#if JUCE_PLUGINHOST_VST && JUCE_LINUX && ! JUCE_AUDIOPROCESSOR_NO_GUI - #include - #include - #undef KeyPress -#endif - -#if ! JUCE_WINDOWS && ! JUCE_MAC - #undef JUCE_PLUGINHOST_VST3 - #define JUCE_PLUGINHOST_VST3 0 -#endif - -#if JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS) - #include -#endif - -//============================================================================== -namespace juce -{ - -static inline bool arrayContainsPlugin (const OwnedArray& list, - const PluginDescription& desc) -{ - for (auto* p : list) - if (p->isDuplicateOf (desc)) - return true; - - return false; -} - -#if JUCE_MAC || JUCE_IOS - -#if JUCE_IOS - #define JUCE_IOS_MAC_VIEW UIView - typedef UIViewComponent ViewComponentBaseClass; -#else - #define JUCE_IOS_MAC_VIEW NSView - typedef NSViewComponent ViewComponentBaseClass; -#endif - -//============================================================================== -struct AutoResizingNSViewComponent : public ViewComponentBaseClass, - private AsyncUpdater -{ - AutoResizingNSViewComponent(); - void childBoundsChanged (Component*) override; - void handleAsyncUpdate() override; - bool recursive; -}; - -//============================================================================== -struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewComponent, - private Timer -{ - AutoResizingNSViewComponentWithParent(); - JUCE_IOS_MAC_VIEW* getChildView() const; - void timerCallback() override; -}; - -//============================================================================== -AutoResizingNSViewComponent::AutoResizingNSViewComponent() - : recursive (false) {} - -void AutoResizingNSViewComponent::childBoundsChanged (Component*) override -{ - if (recursive) - { - triggerAsyncUpdate(); - } - else - { - recursive = true; - resizeToFitView(); - recursive = true; - } -} - -void AutoResizingNSViewComponent::handleAsyncUpdate() override -{ - resizeToFitView(); -} - -//============================================================================== -AutoResizingNSViewComponentWithParent::AutoResizingNSViewComponentWithParent() -{ - JUCE_IOS_MAC_VIEW* v = [[JUCE_IOS_MAC_VIEW alloc] init]; - setView (v); - [v release]; - - startTimer (30); -} - -JUCE_IOS_MAC_VIEW* AutoResizingNSViewComponentWithParent::getChildView() const -{ - if (JUCE_IOS_MAC_VIEW* parent = (JUCE_IOS_MAC_VIEW*) getView()) - if ([[parent subviews] count] > 0) - return [[parent subviews] objectAtIndex: 0]; - - return nil; -} - -void AutoResizingNSViewComponentWithParent::timerCallback() override -{ - if (JUCE_IOS_MAC_VIEW* child = getChildView()) - { - stopTimer(); - setView (child); - } -} -#endif - -} // namespace juce - -#if JUCE_CLANG - #pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - -#include "format/juce_AudioPluginFormat.cpp" -#include "format/juce_AudioPluginFormatManager.cpp" -#include "processors/juce_AudioProcessor.cpp" -#include "processors/juce_AudioProcessorGraph.cpp" -#if ! JUCE_AUDIOPROCESSOR_NO_GUI - #include "processors/juce_AudioProcessorEditor.cpp" - #include "processors/juce_GenericAudioProcessorEditor.cpp" -#endif -#include "processors/juce_PluginDescription.cpp" -#include "format_types/juce_LADSPAPluginFormat.cpp" -#include "format_types/juce_VSTPluginFormat.cpp" -#include "format_types/juce_VST3PluginFormat.cpp" -#include "format_types/juce_AudioUnitPluginFormat.mm" -#include "scanning/juce_KnownPluginList.cpp" -#include "scanning/juce_PluginDirectoryScanner.cpp" -#include "scanning/juce_PluginListComponent.cpp" -#include "utilities/juce_AudioProcessorParameters.cpp" -#include "utilities/juce_AudioProcessorValueTreeState.cpp" diff --git a/source/modules/juce_audio_processors/juce_audio_processors.h b/source/modules/juce_audio_processors/juce_audio_processors.h deleted file mode 100644 index ff0b4f730..000000000 --- a/source/modules/juce_audio_processors/juce_audio_processors.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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. - - ============================================================================== -*/ - -/******************************************************************************* - The block below describes the properties of this module, and is read by - the Projucer to automatically generate project code that uses it. - For details about the syntax and how to create or use a module, see the - JUCE Module Format.txt file. - - - BEGIN_JUCE_MODULE_DECLARATION - - ID: juce_audio_processors - vendor: juce - version: 5.1.2 - name: JUCE audio processor classes - description: Classes for loading and playing VST, AU, or internally-generated audio processors. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_gui_extra, juce_audio_basics - OSXFrameworks: CoreAudio CoreMIDI AudioToolbox - iOSFrameworks: AudioToolbox - - END_JUCE_MODULE_DECLARATION - -*******************************************************************************/ - - -#pragma once -#define JUCE_AUDIO_PROCESSORS_H_INCLUDED - -#include -#include - -//============================================================================== -/** Config: JUCE_PLUGINHOST_VST - Enables the VST audio plugin hosting classes. - - @see VSTPluginFormat, VST3PluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_AU, JUCE_PLUGINHOST_VST3 -*/ -#ifndef JUCE_PLUGINHOST_VST - #define JUCE_PLUGINHOST_VST 0 -#endif - -/** Config: JUCE_PLUGINHOST_VST3 - Enables the VST3 audio plugin hosting classes. This requires the Steinberg VST3 SDK to be - installed on your machine. - - @see VSTPluginFormat, VST3PluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST, JUCE_PLUGINHOST_AU -*/ -#ifndef JUCE_PLUGINHOST_VST3 - #define JUCE_PLUGINHOST_VST3 0 -#endif - -/** Config: JUCE_PLUGINHOST_AU - Enables the AudioUnit plugin hosting classes. This is Mac-only, of course. - - @see AudioUnitPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST, JUCE_PLUGINHOST_VST3 -*/ -#ifndef JUCE_PLUGINHOST_AU - #define JUCE_PLUGINHOST_AU 0 -#endif - -#if ! (JUCE_PLUGINHOST_AU || JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_VST3) -// #error "You need to set either the JUCE_PLUGINHOST_AU and/or JUCE_PLUGINHOST_VST and/or JUCE_PLUGINHOST_VST3 flags if you're using this module!" -#endif - -#if ! (defined (JUCE_SUPPORT_CARBON) || JUCE_64BIT || JUCE_IOS) - #define JUCE_SUPPORT_CARBON 1 -#endif - -#ifndef JUCE_SUPPORT_LEGACY_AUDIOPROCESSOR - #define JUCE_SUPPORT_LEGACY_AUDIOPROCESSOR 1 -#endif - -//============================================================================== -#include "processors/juce_AudioProcessorEditor.h" -#include "processors/juce_AudioProcessorListener.h" -#include "processors/juce_AudioProcessorParameter.h" -#include "processors/juce_AudioProcessor.h" -#include "processors/juce_PluginDescription.h" -#include "processors/juce_AudioPluginInstance.h" -#include "processors/juce_AudioProcessorGraph.h" -#include "processors/juce_GenericAudioProcessorEditor.h" -#include "format/juce_AudioPluginFormat.h" -#include "format/juce_AudioPluginFormatManager.h" -#include "scanning/juce_KnownPluginList.h" -#include "format_types/juce_AudioUnitPluginFormat.h" -#include "format_types/juce_LADSPAPluginFormat.h" -#include "format_types/juce_VSTMidiEventList.h" -#include "format_types/juce_VSTPluginFormat.h" -#include "format_types/juce_VST3PluginFormat.h" -#include "scanning/juce_PluginDirectoryScanner.h" -#include "scanning/juce_PluginListComponent.h" -#include "utilities/juce_AudioProcessorParameterWithID.h" -#include "utilities/juce_AudioParameterFloat.h" -#include "utilities/juce_AudioParameterInt.h" -#include "utilities/juce_AudioParameterBool.h" -#include "utilities/juce_AudioParameterChoice.h" -#include "utilities/juce_AudioProcessorValueTreeState.h" diff --git a/source/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h b/source/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h deleted file mode 100644 index 5e5c21c50..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - Base class for an active instance of a plugin. - - This derives from the AudioProcessor class, and adds some extra functionality - that helps when wrapping dynamically loaded plugins. - - This class is not needed when writing plugins, and you should never need to derive - your own sub-classes from it. The plugin hosting classes use it internally and will - return AudioPluginInstance objects which wrap external plugins. - - @see AudioProcessor, AudioPluginFormat -*/ -class JUCE_API AudioPluginInstance : public AudioProcessor -{ -public: - //============================================================================== - /** Destructor. - - Make sure that you delete any UI components that belong to this plugin before - deleting the plugin. - */ - virtual ~AudioPluginInstance() {} - - //============================================================================== - /** Fills-in the appropriate parts of this plugin description object. */ - virtual void fillInPluginDescription (PluginDescription& description) const = 0; - - /** Returns a PluginDescription for this plugin. - This is just a convenience method to avoid calling fillInPluginDescription. - */ - PluginDescription getPluginDescription() const - { - PluginDescription desc; - fillInPluginDescription (desc); - return desc; - } - - /** 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() { return nullptr; } - - /** For some formats (currently AudioUnit), this forces a reload of the list of - available parameters. - */ - virtual void refreshParameterList() {} - -protected: - //============================================================================== - AudioPluginInstance() {} - AudioPluginInstance (const BusesProperties& ioLayouts) : AudioProcessor (ioLayouts) {} - template - AudioPluginInstance (const short channelLayoutList[numLayouts][2]) : AudioProcessor (channelLayoutList) {} - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginInstance) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp b/source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp deleted file mode 100644 index bf0c76b3e..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp +++ /dev/null @@ -1,1464 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -static ThreadLocalValue wrapperTypeBeingCreated; - -void JUCE_CALLTYPE AudioProcessor::setTypeOfNextNewPlugin (AudioProcessor::WrapperType type) -{ - wrapperTypeBeingCreated = type; -} - -AudioProcessor::AudioProcessor() -{ - initialise (BusesProperties().withInput ("Input", AudioChannelSet::stereo(), false) - .withOutput ("Output", AudioChannelSet::stereo(), false)); -} - -AudioProcessor::AudioProcessor(const BusesProperties& ioConfig) -{ - initialise (ioConfig); -} - -void AudioProcessor::initialise (const BusesProperties& ioConfig) -{ - cachedTotalIns = 0; - cachedTotalOuts = 0; - - wrapperType = wrapperTypeBeingCreated.get(); - playHead = nullptr; - currentSampleRate = 0; - blockSize = 0; - latencySamples = 0; - - #if JUCE_DEBUG - textRecursionCheck = false; - #endif - - suspended = false; - nonRealtime = false; - - processingPrecision = singlePrecision; - - const int numInputBuses = ioConfig.inputLayouts.size(); - const int numOutputBuses = ioConfig.outputLayouts.size(); - - for (int i = 0; i < numInputBuses; ++i) - createBus (true, ioConfig.inputLayouts. getReference (i)); - - for (int i = 0; i < numOutputBuses; ++i) - createBus (false, ioConfig.outputLayouts.getReference (i)); - - updateSpeakerFormatStrings(); -} - -AudioProcessor::~AudioProcessor() -{ - #if ! JUCE_AUDIOPROCESSOR_NO_GUI - // ooh, nasty - the editor should have been deleted before the filter - // that it refers to is deleted.. - jassert (activeEditor == nullptr); - #endif - - #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING - // This will fail if you've called beginParameterChangeGesture() for one - // or more parameters without having made a corresponding call to endParameterChangeGesture... - jassert (changingParams.countNumberOfSetBits() == 0); - #endif -} - -//============================================================================== -StringArray AudioProcessor::getAlternateDisplayNames() const { return StringArray (getName()); } - -//============================================================================== -bool AudioProcessor::addBus (bool isInput) -{ - if (! canAddBus (isInput)) - return false; - - BusProperties busesProps; - if (! canApplyBusCountChange (isInput, true, busesProps)) - return false; - - createBus (isInput, busesProps); - return true; -} - -bool AudioProcessor::removeBus (bool inputBus) -{ - const int numBuses = getBusCount (inputBus); - if (numBuses == 0) - return false; - - if (! canRemoveBus (inputBus)) - return false; - - BusProperties busesProps; - if (! canApplyBusCountChange (inputBus, false, busesProps)) - return false; - - const int busIdx = numBuses - 1; - const int numChannels = getChannelCountOfBus (inputBus, busIdx); - (inputBus ? inputBuses : outputBuses).remove (busIdx); - - audioIOChanged (true, numChannels > 0); - - return true; -} - - -//============================================================================== -bool AudioProcessor::setBusesLayout (const BusesLayout& arr) -{ - jassert (arr.inputBuses. size() == getBusCount (true) - && arr.outputBuses.size() == getBusCount (false)); - - if (arr == getBusesLayout()) - return true; - - BusesLayout copy = arr; - if (! canApplyBusesLayout (copy)) - return false; - - return applyBusLayouts (copy); -} - -bool AudioProcessor::setBusesLayoutWithoutEnabling (const BusesLayout& arr) -{ - const int numIns = getBusCount (true); - const int numOuts = getBusCount (false); - - jassert (arr.inputBuses. size() == numIns - && arr.outputBuses.size() == numOuts); - - BusesLayout request = arr; - const BusesLayout current = getBusesLayout(); - - for (int i = 0; i < numIns; ++i) - if (request.getNumChannels (true, i) == 0) - request.getChannelSet (true, i) = current.getChannelSet (true, i); - - for (int i = 0; i < numOuts; ++i) - if (request.getNumChannels (false, i) == 0) - request.getChannelSet (false, i) = current.getChannelSet (false, i); - - if (! checkBusesLayoutSupported(request)) - return false; - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir != 0); - - for (int i = 0; i < (isInput ? numIns : numOuts); ++i) - { - Bus& bus = *getBus (isInput, i); - AudioChannelSet& set = request.getChannelSet (isInput, i); - - if (! bus.isEnabled()) - { - if (! set.isDisabled()) - bus.lastLayout = set; - - set = AudioChannelSet::disabled(); - } - } - } - - return setBusesLayout (request); -} - -AudioProcessor::BusesLayout AudioProcessor::getBusesLayout() const -{ - BusesLayout layouts; - const int numInputs = getBusCount (true); - const int numOutputs = getBusCount (false); - - for (int i = 0; i < numInputs; ++i) - layouts.inputBuses. add (getBus (true, i)->getCurrentLayout()); - - for (int i = 0; i < numOutputs; ++i) - layouts.outputBuses.add (getBus (false, i)->getCurrentLayout()); - - return layouts; -} - -AudioChannelSet AudioProcessor::getChannelLayoutOfBus (bool isInput, int busIdx) const noexcept -{ - const OwnedArray& buses = (isInput ? inputBuses : outputBuses); - if (Bus* bus = buses[busIdx]) - return bus->getCurrentLayout(); - - return AudioChannelSet(); -} - -bool AudioProcessor::setChannelLayoutOfBus (bool isInputBus, int busIdx, const AudioChannelSet& layout) -{ - if (Bus* bus = getBus (isInputBus, busIdx)) - { - BusesLayout layouts = bus->getBusesLayoutForLayoutChangeOfBus (layout); - - if (layouts.getChannelSet (isInputBus, busIdx) == layout) - return applyBusLayouts (layouts); - - return false; - } - - // busIdx parameter is invalid - jassertfalse; - - return false; -} - -bool AudioProcessor::enableAllBuses() -{ - BusesLayout layouts; - const int numInputs = getBusCount (true); - const int numOutputs = getBusCount (false); - - for (int i = 0; i < numInputs; ++i) - layouts.inputBuses. add (getBus (true, i)->lastLayout); - - for (int i = 0; i < numOutputs; ++i) - layouts.outputBuses.add (getBus (false, i)->lastLayout); - - return setBusesLayout (layouts); -} - -bool AudioProcessor::checkBusesLayoutSupported (const BusesLayout& layouts) const -{ - const int numInputBuses = getBusCount (true); - const int numOutputBuses = getBusCount (false); - - if (layouts.inputBuses. size() == numInputBuses - && layouts.outputBuses.size() == numOutputBuses) - return isBusesLayoutSupported (layouts); - - return false; -} - -void AudioProcessor::getNextBestLayout (const BusesLayout& desiredLayout, BusesLayout& actualLayouts) const -{ - // if you are hitting this assertion then you are requesting a next - // best layout which does not have the same number of buses as the - // audio processor. - jassert (desiredLayout.inputBuses. size() == getBusCount (true) - && desiredLayout.outputBuses.size() == getBusCount (false)); - - if (checkBusesLayoutSupported (desiredLayout)) - { - actualLayouts = desiredLayout; - return; - } - - BusesLayout originalState = actualLayouts; - BusesLayout currentState = originalState; - BusesLayout bestSupported = currentState; - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir > 0); - - Array& currentLayouts = (isInput ? currentState.inputBuses : currentState.outputBuses); - const Array& bestLayouts = (isInput ? bestSupported.inputBuses : bestSupported.outputBuses); - const Array& requestedLayouts = (isInput ? desiredLayout.inputBuses : desiredLayout.outputBuses); - const Array& originalLayouts = (isInput ? originalState.inputBuses : originalState.outputBuses); - - for (int busIdx = 0; busIdx < requestedLayouts.size(); ++busIdx) - { - AudioChannelSet& best = bestLayouts .getReference (busIdx); - const AudioChannelSet& requested = requestedLayouts.getReference (busIdx); - const AudioChannelSet& original = originalLayouts .getReference (busIdx); - - // do we need to do anything - if (original == requested) - continue; - - currentState = bestSupported; - AudioChannelSet& current = currentLayouts .getReference (busIdx); - - // already supported? - current = requested; - if (checkBusesLayoutSupported (currentState)) - { - bestSupported = currentState; - continue; - } - - // try setting the opposite bus to the identical layout - const bool oppositeDirection = ! isInput; - if (getBusCount (oppositeDirection) > busIdx) - { - AudioChannelSet& oppositeLayout = (oppositeDirection ? currentState.inputBuses : currentState.outputBuses).getReference (busIdx); - oppositeLayout = requested; - - if (checkBusesLayoutSupported (currentState)) - { - bestSupported = currentState; - continue; - } - - // try setting the default layout - oppositeLayout = getBus (oppositeDirection, busIdx)->getDefaultLayout(); - if (checkBusesLayoutSupported (currentState)) - { - bestSupported = currentState; - continue; - } - } - - // try setting all other buses to the identical layout - BusesLayout allTheSame; - for (int oDir = 0; oDir < 2; ++oDir) - { - const bool oIsInput = (oDir == 0); - const int oBusNum = getBusCount (oIsInput); - - for (int oBusIdx = 0; oBusIdx < oBusNum; ++oBusIdx) - (oIsInput ? allTheSame.inputBuses : allTheSame.outputBuses).add (requested); - } - - if (checkBusesLayoutSupported (allTheSame)) - { - bestSupported = allTheSame; - continue; - } - - // what is closer the default or the current layout? - int distance = abs (best.size() - requested.size()); - const AudioChannelSet& defaultLayout = getBus (isInput, busIdx)->getDefaultLayout(); - - if (abs (defaultLayout.size() - requested.size()) < distance) - { - current = defaultLayout; - if (checkBusesLayoutSupported (currentState)) - bestSupported = currentState; - } - } - } - - actualLayouts = bestSupported; -} - -//============================================================================== -void AudioProcessor::setPlayHead (AudioPlayHead* const newPlayHead) -{ - playHead = newPlayHead; -} - -void AudioProcessor::addListener (AudioProcessorListener* const newListener) -{ - const ScopedLock sl (listenerLock); - listeners.addIfNotAlreadyThere (newListener); -} - -void AudioProcessor::removeListener (AudioProcessorListener* const listenerToRemove) -{ - const ScopedLock sl (listenerLock); - listeners.removeFirstMatchingValue (listenerToRemove); -} - -void AudioProcessor::setPlayConfigDetails (const int newNumIns, - const int newNumOuts, - const double newSampleRate, - const int newBlockSize) -{ - bool success = true; - - if (getTotalNumInputChannels() != newNumIns) - success &= setChannelLayoutOfBus (true, 0, AudioChannelSet::canonicalChannelSet (newNumIns)); - - if (getTotalNumOutputChannels() != newNumOuts) - success &= setChannelLayoutOfBus (false, 0, AudioChannelSet::canonicalChannelSet (newNumOuts)); - - // if the user is using this method then they do not want any side-buses or aux outputs - success &= disableNonMainBuses(); - jassert (success); - - // the processor may not support this arrangement at all - jassert (success && newNumIns == getTotalNumInputChannels() && newNumOuts == getTotalNumOutputChannels()); - - setRateAndBufferSizeDetails (newSampleRate, newBlockSize); -} - -void AudioProcessor::setRateAndBufferSizeDetails (double newSampleRate, int newBlockSize) noexcept -{ - currentSampleRate = newSampleRate; - blockSize = newBlockSize; -} - -//============================================================================== -static int countTotalChannels (const OwnedArray& buses) noexcept -{ - int n = 0; - - for (int i = 0; i < buses.size(); ++i) - n += buses[i]->getNumberOfChannels(); - - return n; -} - -void AudioProcessor::numChannelsChanged() {} -void AudioProcessor::numBusesChanged() {} -void AudioProcessor::processorLayoutsChanged() {} - -int AudioProcessor::getChannelIndexInProcessBlockBuffer (bool isInput, int busIndex, int channelIndex) const noexcept -{ - const OwnedArray& ioBus = isInput ? inputBuses : outputBuses; - jassert (isPositiveAndBelow(busIndex, ioBus.size())); - - for (int i = 0; i < ioBus.size() && i < busIndex; ++i) - channelIndex += getChannelCountOfBus (isInput, i); - - return channelIndex; -} - -int AudioProcessor::getOffsetInBusBufferForAbsoluteChannelIndex (bool isInput, int absoluteChannelIndex, /*out*/ int& busIdx) const noexcept -{ - const int n = getBusCount (isInput); - int numChannels = 0; - - for (busIdx = 0; busIdx < n && absoluteChannelIndex >= (numChannels = getChannelLayoutOfBus (isInput, busIdx).size()); ++busIdx) - absoluteChannelIndex -= numChannels; - - return busIdx >= n ? -1 : absoluteChannelIndex; -} - -//============================================================================== -void AudioProcessor::setNonRealtime (const bool newNonRealtime) noexcept -{ - nonRealtime = newNonRealtime; -} - -void AudioProcessor::setLatencySamples (const int newLatency) -{ - if (latencySamples != newLatency) - { - latencySamples = newLatency; - updateHostDisplay(); - } -} - -void AudioProcessor::setParameterNotifyingHost (const int parameterIndex, - const float newValue) -{ - setParameter (parameterIndex, newValue); - sendParamChangeMessageToListeners (parameterIndex, newValue); -} - -AudioProcessorListener* AudioProcessor::getListenerLocked (const int index) const noexcept -{ - const ScopedLock sl (listenerLock); - return listeners [index]; -} - -void AudioProcessor::sendParamChangeMessageToListeners (const int parameterIndex, const float newValue) -{ - if (isPositiveAndBelow (parameterIndex, getNumParameters())) - { - for (int i = listeners.size(); --i >= 0;) - if (auto* l = getListenerLocked (i)) - l->audioProcessorParameterChanged (this, parameterIndex, newValue); - } - else - { - jassertfalse; // called with an out-of-range parameter index! - } -} - -void AudioProcessor::beginParameterChangeGesture (int parameterIndex) -{ - if (isPositiveAndBelow (parameterIndex, getNumParameters())) - { - #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING - // This means you've called beginParameterChangeGesture twice in succession without a matching - // call to endParameterChangeGesture. That might be fine in most hosts, but better to avoid doing it. - jassert (! changingParams [parameterIndex]); - changingParams.setBit (parameterIndex); - #endif - - for (int i = listeners.size(); --i >= 0;) - if (auto* l = getListenerLocked (i)) - l->audioProcessorParameterChangeGestureBegin (this, parameterIndex); - } - else - { - jassertfalse; // called with an out-of-range parameter index! - } -} - -void AudioProcessor::endParameterChangeGesture (int parameterIndex) -{ - if (isPositiveAndBelow (parameterIndex, getNumParameters())) - { - #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING - // This means you've called endParameterChangeGesture without having previously called - // beginParameterChangeGesture. That might be fine in most hosts, but better to keep the - // calls matched correctly. - jassert (changingParams [parameterIndex]); - changingParams.clearBit (parameterIndex); - #endif - - for (int i = listeners.size(); --i >= 0;) - if (AudioProcessorListener* l = getListenerLocked (i)) - l->audioProcessorParameterChangeGestureEnd (this, parameterIndex); - } - else - { - jassertfalse; // called with an out-of-range parameter index! - } -} - -void AudioProcessor::updateHostDisplay() -{ - for (int i = listeners.size(); --i >= 0;) - if (AudioProcessorListener* l = getListenerLocked (i)) - l->audioProcessorChanged (this); -} - -const OwnedArray& AudioProcessor::getParameters() const noexcept -{ - return managedParameters; -} - -int AudioProcessor::getNumParameters() -{ - return managedParameters.size(); -} - -float AudioProcessor::getParameter (int index) -{ - if (auto* p = getParamChecked (index)) - return p->getValue(); - - return 0; -} - -void AudioProcessor::setParameter (int index, float newValue) -{ - if (auto* p = getParamChecked (index)) - p->setValue (newValue); -} - -float AudioProcessor::getParameterDefaultValue (int index) -{ - if (auto* p = managedParameters[index]) - return p->getDefaultValue(); - - return 0; -} - -const String AudioProcessor::getParameterName (int index) -{ - if (auto* p = getParamChecked (index)) - return p->getName (512); - - return {}; -} - -String AudioProcessor::getParameterID (int index) -{ - // Don't use getParamChecked here, as this must also work for legacy plug-ins - if (auto* p = dynamic_cast (managedParameters[index])) - return p->paramID; - - return String (index); -} - -String AudioProcessor::getParameterName (int index, int maximumStringLength) -{ - if (auto* p = managedParameters[index]) - return p->getName (maximumStringLength); - - return getParameterName (index).substring (0, maximumStringLength); -} - -const String AudioProcessor::getParameterText (int index) -{ - #if JUCE_DEBUG - // if you hit this, then you're probably using the old parameter control methods, - // but have forgotten to implement either of the getParameterText() methods. - jassert (! textRecursionCheck); - ScopedValueSetter sv (textRecursionCheck, true, false); - #endif - - return getParameterText (index, 1024); -} - -String AudioProcessor::getParameterText (int index, int maximumStringLength) -{ - if (auto* p = managedParameters[index]) - return p->getText (p->getValue(), maximumStringLength); - - return getParameterText (index).substring (0, maximumStringLength); -} - -int AudioProcessor::getParameterNumSteps (int index) -{ - if (auto* p = managedParameters[index]) - return p->getNumSteps(); - - return AudioProcessor::getDefaultNumParameterSteps(); -} - -int AudioProcessor::getDefaultNumParameterSteps() noexcept -{ - return 0x7fffffff; -} - -bool AudioProcessor::isParameterDiscrete (int index) const -{ - if (auto* p = managedParameters[index]) - return p->isDiscrete(); - - return false; -} - -String AudioProcessor::getParameterLabel (int index) const -{ - if (auto* p = managedParameters[index]) - return p->getLabel(); - - return {}; -} - -bool AudioProcessor::isParameterAutomatable (int index) const -{ - if (auto* p = managedParameters[index]) - return p->isAutomatable(); - - return true; -} - -bool AudioProcessor::isParameterOrientationInverted (int index) const -{ - if (auto* p = managedParameters[index]) - return p->isOrientationInverted(); - - return false; -} - -bool AudioProcessor::isMetaParameter (int index) const -{ - if (auto* p = managedParameters[index]) - return p->isMetaParameter(); - - return false; -} - -AudioProcessorParameter::Category AudioProcessor::getParameterCategory (int index) const -{ - if (auto* p = managedParameters[index]) - return p->getCategory(); - - return AudioProcessorParameter::genericParameter; -} - -AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const noexcept -{ - AudioProcessorParameter* p = managedParameters[index]; - - // If you hit this, then you're either trying to access parameters that are out-of-range, - // or you're not using addParameter and the managed parameter list, but have failed - // to override some essential virtual methods and implement them appropriately. - jassert (p != nullptr); - return p; -} - -void AudioProcessor::addParameter (AudioProcessorParameter* p) -{ - p->processor = this; - p->parameterIndex = managedParameters.size(); - managedParameters.add (p); - - // if you're using parameter objects, then you must not override the - // deprecated getNumParameters() method! - jassert (getNumParameters() == AudioProcessor::getNumParameters()); - - // check that no two parameters have the same id - #ifdef JUCE_DEBUG - auto paramId = getParameterID (p->parameterIndex); - - for (auto q : managedParameters) - { - jassert (q == nullptr || q == p || paramId != getParameterID (q->parameterIndex)); - } - #endif -} - -void AudioProcessor::suspendProcessing (const bool shouldBeSuspended) -{ - const ScopedLock sl (callbackLock); - suspended = shouldBeSuspended; -} - -void AudioProcessor::reset() {} - -template -void AudioProcessor::processBypassed (AudioBuffer& buffer, MidiBuffer&) -{ - for (int ch = getMainBusNumInputChannels(); ch < getTotalNumOutputChannels(); ++ch) - buffer.clear (ch, 0, buffer.getNumSamples()); -} - -void AudioProcessor::processBlockBypassed (AudioBuffer& buffer, MidiBuffer& midi) { processBypassed (buffer, midi); } -void AudioProcessor::processBlockBypassed (AudioBuffer& buffer, MidiBuffer& midi) { processBypassed (buffer, midi); } - -void AudioProcessor::processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) -{ - ignoreUnused (buffer, midiMessages); - - // If you hit this assertion then either the caller called the double - // precision version of processBlock on a processor which does not support it - // (i.e. supportsDoublePrecisionProcessing() returns false), or the implementation - // of the AudioProcessor forgot to override the double precision version of this method - jassertfalse; -} - -bool AudioProcessor::supportsDoublePrecisionProcessing() const -{ - return false; -} - -void AudioProcessor::setProcessingPrecision (ProcessingPrecision precision) noexcept -{ - // If you hit this assertion then you're trying to use double precision - // processing on a processor which does not support it! - jassert (precision != doublePrecision || supportsDoublePrecisionProcessing()); - - processingPrecision = precision; -} - -//============================================================================== -static String getChannelName (const OwnedArray& buses, int index) -{ - return buses.size() > 0 ? AudioChannelSet::getChannelTypeName (buses[0]->getCurrentLayout().getTypeOfChannel (index)) : String(); -} - -const String AudioProcessor::getInputChannelName (int index) const { return getChannelName (inputBuses, index); } -const String AudioProcessor::getOutputChannelName (int index) const { return getChannelName (outputBuses, index); } - -static bool isStereoPair (const OwnedArray& buses, int index) -{ - return index < 2 - && buses.size() > 0 - && buses[0]->getCurrentLayout() == AudioChannelSet::stereo(); -} - -bool AudioProcessor::isInputChannelStereoPair (int index) const { return isStereoPair (inputBuses, index); } -bool AudioProcessor::isOutputChannelStereoPair (int index) const { return isStereoPair (outputBuses, index); } - -//============================================================================== -void AudioProcessor::createBus (bool inputBus, const BusProperties& ioConfig) -{ - (inputBus ? inputBuses : outputBuses).add (new Bus (*this, ioConfig.busName, ioConfig.defaultLayout, ioConfig.isActivatedByDefault)); - - audioIOChanged (true, ioConfig.isActivatedByDefault); -} - -//============================================================================== -AudioProcessor::BusesProperties AudioProcessor::busesPropertiesFromLayoutArray (const Array& config) -{ - BusesProperties ioProps; - - if (config[0].inChannels > 0) - ioProps.addBus (true, String ("Input"), AudioChannelSet::canonicalChannelSet (config[0].inChannels)); - - if (config[0].outChannels > 0) - ioProps.addBus (false, String ("Output"), AudioChannelSet::canonicalChannelSet (config[0].outChannels)); - - return ioProps; -} - -AudioProcessor::BusesLayout AudioProcessor::getNextBestLayoutInList (const BusesLayout& layouts, - const Array& legacyLayouts) const -{ - const int numChannelConfigs = legacyLayouts.size(); - jassert (numChannelConfigs > 0); - - bool hasInputs = false, hasOutputs = false; - - for (int i = 0; i < numChannelConfigs; ++i) - { - if (legacyLayouts[i].inChannels > 0) - { - hasInputs = true; - break; - } - } - - for (int i = 0; i < numChannelConfigs; ++i) - { - if (legacyLayouts[i].outChannels > 0) - { - hasOutputs = true; - break; - } - } - - BusesLayout nearest = layouts; - nearest.inputBuses .resize (hasInputs ? 1 : 0); - nearest.outputBuses.resize (hasOutputs ? 1 : 0); - - AudioChannelSet* inBus = (hasInputs ? &nearest.inputBuses. getReference (0) : nullptr); - AudioChannelSet* outBus = (hasOutputs ? &nearest.outputBuses.getReference (0) : nullptr); - - const int16 inNumChannelsRequested = static_cast (inBus != nullptr ? inBus->size() : 0); - const int16 outNumChannelsRequested = static_cast (outBus != nullptr ? outBus->size() : 0); - - int32 distance = std::numeric_limits::max(); - int bestConfiguration = 0; - - for (int i = 0; i < numChannelConfigs; ++i) - { - const int16 inChannels = legacyLayouts.getReference (i).inChannels; - const int16 outChannels = legacyLayouts.getReference (i).outChannels; - - const int32 channelDifference = ((std::abs (inChannels - inNumChannelsRequested) & 0xffff) << 16) | - ((std::abs (outChannels - outNumChannelsRequested) & 0xffff) << 0); - - if (channelDifference < distance) - { - distance = channelDifference; - bestConfiguration = i; - - // we can exit if we found a perfect match - if (distance == 0) return nearest; - } - } - - const int16 inChannels = legacyLayouts.getReference (bestConfiguration).inChannels; - const int16 outChannels = legacyLayouts.getReference (bestConfiguration).outChannels; - - BusesLayout currentState = getBusesLayout(); - AudioChannelSet currentInLayout = (getBusCount (true) > 0 ? currentState.inputBuses .getReference(0) : AudioChannelSet()); - AudioChannelSet currentOutLayout = (getBusCount (false) > 0 ? currentState.outputBuses.getReference(0) : AudioChannelSet()); - - - if (inBus != nullptr) - { - if (inChannels == 0) *inBus = AudioChannelSet::disabled(); - else if (inChannels == currentInLayout. size()) *inBus = currentInLayout; - else if (inChannels == currentOutLayout.size()) *inBus = currentOutLayout; - else *inBus = AudioChannelSet::canonicalChannelSet (inChannels); - } - - if (outBus != nullptr) - { - if (outChannels == 0) *outBus = AudioChannelSet::disabled(); - else if (outChannels == currentOutLayout.size()) *outBus = currentOutLayout; - else if (outChannels == currentInLayout .size()) *outBus = currentInLayout; - else *outBus = AudioChannelSet::canonicalChannelSet (outChannels); - } - - return nearest; -} - -bool AudioProcessor::containsLayout (const BusesLayout& layouts, const Array& channelLayouts) -{ - if (layouts.inputBuses.size() > 1 || layouts.outputBuses.size() > 1) - return false; - - const InOutChannelPair mainLayout (static_cast (layouts.getNumChannels (true, 0)), - static_cast (layouts.getNumChannels (false, 0))); - - return channelLayouts.contains (mainLayout); -} - -//============================================================================== -bool AudioProcessor::disableNonMainBuses() -{ - BusesLayout layouts = getBusesLayout(); - - for (int busIdx = 1; busIdx < layouts.inputBuses.size(); ++busIdx) - layouts.inputBuses.getReference (busIdx) = AudioChannelSet::disabled(); - - for (int busIdx = 1; busIdx < layouts.outputBuses.size(); ++busIdx) - layouts.outputBuses.getReference (busIdx) = AudioChannelSet::disabled(); - - return setBusesLayout (layouts); -} - -// Unfortunately the deprecated getInputSpeakerArrangement/getOutputSpeakerArrangement return -// references to strings. Therefore we need to keep a copy. Once getInputSpeakerArrangement is -// removed, we can also remove this function -void AudioProcessor::updateSpeakerFormatStrings() -{ - cachedInputSpeakerArrString.clear(); - cachedOutputSpeakerArrString.clear(); - - if (getBusCount (true) > 0) - cachedInputSpeakerArrString = getBus (true, 0)->getCurrentLayout().getSpeakerArrangementAsString(); - - if (getBusCount (false) > 0) - cachedOutputSpeakerArrString = getBus (false, 0)->getCurrentLayout().getSpeakerArrangementAsString(); -} - -bool AudioProcessor::applyBusLayouts (const BusesLayout& layouts) -{ - if (layouts == getBusesLayout()) - return true; - - const int numInputBuses = getBusCount (true); - const int numOutputBuses = getBusCount (false); - - const int oldNumberOfIns = getTotalNumInputChannels(); - const int oldNumberOfOuts = getTotalNumOutputChannels(); - - if (layouts.inputBuses. size() != numInputBuses - || layouts.outputBuses.size() != numOutputBuses) - return false; - - int newNumberOfIns = 0, newNumberOfOuts = 0; - - for (int busIdx = 0; busIdx < numInputBuses; ++busIdx) - { - Bus& bus = *getBus (true, busIdx); - const AudioChannelSet& set = layouts.getChannelSet (true, busIdx); - - bus.layout = set; - if (! set.isDisabled()) - bus.lastLayout = set; - - newNumberOfIns += set.size(); - } - - for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx) - { - Bus& bus = *getBus (false, busIdx); - const AudioChannelSet& set = layouts.getChannelSet (false, busIdx); - - bus.layout = set; - if (! set.isDisabled()) - bus.lastLayout = set; - - newNumberOfOuts += set.size(); - } - - const bool channelNumChanged = (oldNumberOfIns != newNumberOfIns || oldNumberOfOuts != newNumberOfOuts); - audioIOChanged (false, channelNumChanged); - - return true; -} - -void AudioProcessor::audioIOChanged (bool busNumberChanged, bool channelNumChanged) -{ - const int numInputBuses = getBusCount (true); - const int numOutputBuses = getBusCount (false); - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const int n = (isInput ? numInputBuses : numOutputBuses); - - for (int i = 0; i < n; ++i) - { - if (Bus* bus = getBus (isInput, i)) - bus->updateChannelCount(); - } - } - - cachedTotalIns = countTotalChannels (inputBuses); - cachedTotalOuts = countTotalChannels (outputBuses); - - updateSpeakerFormatStrings(); - - if (busNumberChanged) - numBusesChanged(); - - if (channelNumChanged) - numChannelsChanged(); - - processorLayoutsChanged(); -} - -#if ! JUCE_AUDIOPROCESSOR_NO_GUI -//============================================================================== -void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) noexcept -{ - const ScopedLock sl (callbackLock); - - if (activeEditor == editor) - activeEditor = nullptr; -} - -AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() -{ - if (activeEditor != nullptr) - return activeEditor; - - AudioProcessorEditor* const ed = createEditor(); - - if (ed != nullptr) - { - // you must give your editor comp a size before returning it.. - jassert (ed->getWidth() > 0 && ed->getHeight() > 0); - - const ScopedLock sl (callbackLock); - activeEditor = ed; - } - - // You must make your hasEditor() method return a consistent result! - jassert (hasEditor() == (ed != nullptr)); - - return ed; -} -#endif - -//============================================================================== -void AudioProcessor::getCurrentProgramStateInformation (juce::MemoryBlock& destData) -{ - getStateInformation (destData); -} - -void AudioProcessor::setCurrentProgramStateInformation (const void* data, int sizeInBytes) -{ - setStateInformation (data, sizeInBytes); -} - -//============================================================================== -void AudioProcessor::updateTrackProperties (const AudioProcessor::TrackProperties&) {} - -//============================================================================== -// magic number to identify memory blocks that we've stored as XML -const uint32 magicXmlNumber = 0x21324356; - -void AudioProcessor::copyXmlToBinary (const XmlElement& xml, juce::MemoryBlock& destData) -{ - { - MemoryOutputStream out (destData, false); - out.writeInt (magicXmlNumber); - out.writeInt (0); - xml.writeToStream (out, String(), true, false); - out.writeByte (0); - } - - // go back and write the string length.. - static_cast (destData.getData())[1] - = ByteOrder::swapIfBigEndian ((uint32) destData.getSize() - 9); -} - -XmlElement* AudioProcessor::getXmlFromBinary (const void* data, const int sizeInBytes) -{ - if (sizeInBytes > 8 - && ByteOrder::littleEndianInt (data) == magicXmlNumber) - { - const int stringLength = (int) ByteOrder::littleEndianInt (addBytesToPointer (data, 4)); - - if (stringLength > 0) - return XmlDocument::parse (String::fromUTF8 (static_cast (data) + 8, - jmin ((sizeInBytes - 8), stringLength))); - } - - return nullptr; -} - -bool AudioProcessor::canApplyBusCountChange (bool isInput, bool isAdding, - AudioProcessor::BusProperties& outProperties) -{ - if ( isAdding && ! canAddBus (isInput)) return false; - if (! isAdding && ! canRemoveBus (isInput)) return false; - - const int num = getBusCount (isInput); - - // No way for me to find out the default layout if there are no other busses!! - if (num == 0) return false; - - if (isAdding) - { - outProperties.busName = String (isInput ? "Input #" : "Output #") + String (getBusCount (isInput)); - outProperties.defaultLayout = (num > 0 ? getBus (isInput, num - 1)->getDefaultLayout() : AudioChannelSet()); - outProperties.isActivatedByDefault = true; - } - - return true; -} - -//============================================================================== -AudioProcessor::Bus::Bus (AudioProcessor& processor, const String& busName, - const AudioChannelSet& defaultLayout, bool isDfltEnabled) - : owner (processor), name (busName), - layout (isDfltEnabled ? defaultLayout : AudioChannelSet()), - dfltLayout (defaultLayout), lastLayout (defaultLayout), - enabledByDefault (isDfltEnabled) -{ - // Your default layout cannot be disabled - jassert (! dfltLayout.isDisabled()); -} - -bool AudioProcessor::Bus::isInput() const -{ - return owner.inputBuses.contains (this); -} - -int AudioProcessor::Bus::getBusIndex() const -{ - bool ignore; - int idx; - busDirAndIndex (ignore, idx); - - return idx; -} - -void AudioProcessor::Bus::busDirAndIndex (bool& input, int& idx) const noexcept -{ - idx = owner.inputBuses.indexOf (this); - input = (idx >= 0); - - if (! input) - idx = owner.outputBuses.indexOf (this); -} - -bool AudioProcessor::Bus::setCurrentLayout (const AudioChannelSet& busLayout) -{ - bool isInput; - int idx; - busDirAndIndex (isInput, idx); - - return owner.setChannelLayoutOfBus (isInput, idx, busLayout); -} - -bool AudioProcessor::Bus::setCurrentLayoutWithoutEnabling (const AudioChannelSet& set) -{ - if (! set.isDisabled()) - { - if (isEnabled()) - return setCurrentLayout (set); - - if (isLayoutSupported (set)) - { - lastLayout = set; - return true; - } - - return false; - } - - return isLayoutSupported (set); -} - -bool AudioProcessor::Bus::setNumberOfChannels (int channels) -{ - bool isInputBus; - int busIdx; - busDirAndIndex (isInputBus, busIdx); - - if (owner.setChannelLayoutOfBus (isInputBus, busIdx, AudioChannelSet::canonicalChannelSet (channels))) - return true; - - if (channels == 0) - return false; - - AudioChannelSet namedSet = AudioChannelSet::namedChannelSet (channels); - if (! namedSet.isDisabled() && owner.setChannelLayoutOfBus (isInputBus, busIdx, namedSet)) - return true; - - return owner.setChannelLayoutOfBus (isInputBus, busIdx, AudioChannelSet::discreteChannels (channels)); -} - -bool AudioProcessor::Bus::enable (bool shouldEnable) -{ - if (isEnabled() == shouldEnable) - return true; - - return setCurrentLayout (shouldEnable ? lastLayout : AudioChannelSet::disabled()); -} - -int AudioProcessor::Bus::getMaxSupportedChannels (int limit) const -{ - for (int ch = limit; ch > 0; --ch) - if (isNumberOfChannelsSupported (ch)) - return ch; - - return (isMain() && isLayoutSupported (AudioChannelSet::disabled())) ? 0 : -1; -} - -bool AudioProcessor::Bus::isLayoutSupported (const AudioChannelSet& set, BusesLayout* ioLayout) const -{ - bool isInputBus; - int busIdx; - busDirAndIndex (isInputBus, busIdx); - - // check that supplied ioLayout is actually valid - if (ioLayout != nullptr) - { - bool suppliedCurrentSupported = owner.checkBusesLayoutSupported (*ioLayout); - - if (! suppliedCurrentSupported) - { - *ioLayout = owner.getBusesLayout(); - - // the current layout you supplied is not a valid layout - jassertfalse; - } - } - - BusesLayout currentLayout = (ioLayout != nullptr ? *ioLayout : owner.getBusesLayout()); - const Array& actualBuses = - (isInputBus ? currentLayout.inputBuses : currentLayout.outputBuses); - - if (actualBuses.getReference (busIdx) == set) - return true; - - BusesLayout desiredLayout = currentLayout; - { - Array& desiredBuses = - (isInputBus ? desiredLayout.inputBuses : desiredLayout.outputBuses); - - desiredBuses.getReference (busIdx) = set; - } - - owner.getNextBestLayout (desiredLayout, currentLayout); - - if (ioLayout != nullptr) - *ioLayout = currentLayout; - - // Nearest layout has a different number of buses. JUCE plug-ins MUST - // have fixed number of buses. - jassert (currentLayout.inputBuses. size() == owner.getBusCount (true) - && currentLayout.outputBuses.size() == owner.getBusCount (false)); - - return (actualBuses.getReference (busIdx) == set); -} - -bool AudioProcessor::Bus::isNumberOfChannelsSupported (int channels) const -{ - if (channels == 0) return isLayoutSupported(AudioChannelSet::disabled()); - - const AudioChannelSet set = supportedLayoutWithChannels (channels); - return (! set.isDisabled()) && isLayoutSupported (set); -} - -AudioChannelSet AudioProcessor::Bus::supportedLayoutWithChannels (int channels) const -{ - if (channels == 0) return AudioChannelSet::disabled(); - - { - AudioChannelSet set; - if (! (set = AudioChannelSet::namedChannelSet (channels)).isDisabled() && isLayoutSupported (set)) - return set; - - if (! (set = AudioChannelSet::discreteChannels (channels)).isDisabled() && isLayoutSupported (set)) - return set; - } - - Array sets = AudioChannelSet::channelSetsWithNumberOfChannels (channels); - const int n = sets.size(); - - for (int i = 0; i < n; ++i) - { - const AudioChannelSet set = sets.getReference (i); - - if (isLayoutSupported (set)) - return set; - } - - return AudioChannelSet::disabled(); -} - -AudioProcessor::BusesLayout AudioProcessor::Bus::getBusesLayoutForLayoutChangeOfBus (const AudioChannelSet& set) const -{ - bool isInputBus; - int busIdx; - busDirAndIndex (isInputBus, busIdx); - - BusesLayout layouts = owner.getBusesLayout(); - isLayoutSupported (set, &layouts); - - return layouts; -} - -int AudioProcessor::Bus::getChannelIndexInProcessBlockBuffer (int channelIndex) const noexcept -{ - bool isInputBus; - int busIdx; - busDirAndIndex (isInputBus, busIdx); - - return owner.getChannelIndexInProcessBlockBuffer (isInputBus, busIdx, channelIndex); -} - -void AudioProcessor::Bus::updateChannelCount() noexcept -{ - cachedChannelCount = layout.size(); -} - -//============================================================================== -void AudioProcessor::BusesProperties::addBus (bool isInput, const String& name, - const AudioChannelSet& dfltLayout, bool isActivatedByDefault) -{ - jassert (dfltLayout.size() != 0); - - BusProperties props; - - props.busName = name; - props.defaultLayout = dfltLayout; - props.isActivatedByDefault = isActivatedByDefault; - - (isInput ? inputLayouts : outputLayouts).add (props); -} - -AudioProcessor::BusesProperties AudioProcessor::BusesProperties::withInput (const String& name, - const AudioChannelSet& dfltLayout, - bool isActivatedByDefault) const -{ - BusesProperties retval (*this); - retval.addBus (true, name, dfltLayout, isActivatedByDefault); - - return retval; -} - -AudioProcessor::BusesProperties AudioProcessor::BusesProperties::withOutput (const String& name, - const AudioChannelSet& dfltLayout, - bool isActivatedByDefault) const -{ - BusesProperties retval (*this); - retval.addBus (false, name, dfltLayout, isActivatedByDefault); - - return retval; -} - -//============================================================================== -int32 AudioProcessor::getAAXPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout, - const AudioChannelSet& mainOutputLayout, - const bool idForAudioSuite) const -{ - int uniqueFormatId = 0; - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const AudioChannelSet& set = (isInput ? mainInputLayout : mainOutputLayout); - int aaxFormatIndex = 0; - - if (set == AudioChannelSet::disabled()) aaxFormatIndex = 0; - else if (set == AudioChannelSet::mono()) aaxFormatIndex = 1; - else if (set == AudioChannelSet::stereo()) aaxFormatIndex = 2; - else if (set == AudioChannelSet::createLCR()) aaxFormatIndex = 3; - else if (set == AudioChannelSet::createLCRS()) aaxFormatIndex = 4; - else if (set == AudioChannelSet::quadraphonic()) aaxFormatIndex = 5; - else if (set == AudioChannelSet::create5point0()) aaxFormatIndex = 6; - else if (set == AudioChannelSet::create5point1()) aaxFormatIndex = 7; - else if (set == AudioChannelSet::create6point0()) aaxFormatIndex = 8; - else if (set == AudioChannelSet::create6point1()) aaxFormatIndex = 9; - else if (set == AudioChannelSet::create7point0()) aaxFormatIndex = 10; - else if (set == AudioChannelSet::create7point1()) aaxFormatIndex = 11; - else if (set == AudioChannelSet::create7point0SDDS()) aaxFormatIndex = 12; - else if (set == AudioChannelSet::create7point1SDDS()) aaxFormatIndex = 13; - else if (set == AudioChannelSet::create7point0point2()) aaxFormatIndex = 14; - else if (set == AudioChannelSet::create7point1point2()) aaxFormatIndex = 15; - else - { - // AAX does not support this format and the wrapper should not have - // called this method with this layout - jassertfalse; - } - - uniqueFormatId = (uniqueFormatId << 8) | aaxFormatIndex; - } - - return (idForAudioSuite ? 0x6a796161 /* 'jyaa' */ : 0x6a636161 /* 'jcaa' */) + uniqueFormatId; -} - - -//============================================================================== -void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {} -void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {} - -//============================================================================== -AudioProcessorParameter::AudioProcessorParameter() noexcept - : processor (nullptr), parameterIndex (-1) -{} - -AudioProcessorParameter::~AudioProcessorParameter() {} - -void AudioProcessorParameter::setValueNotifyingHost (float newValue) -{ - // This method can't be used until the parameter has been attached to a processor! - jassert (processor != nullptr && parameterIndex >= 0); - - return processor->setParameterNotifyingHost (parameterIndex, newValue); -} - -void AudioProcessorParameter::beginChangeGesture() -{ - // This method can't be used until the parameter has been attached to a processor! - jassert (processor != nullptr && parameterIndex >= 0); - - processor->beginParameterChangeGesture (parameterIndex); -} - -void AudioProcessorParameter::endChangeGesture() -{ - // This method can't be used until the parameter has been attached to a processor! - jassert (processor != nullptr && parameterIndex >= 0); - - processor->endParameterChangeGesture (parameterIndex); -} - -bool AudioProcessorParameter::isOrientationInverted() const { return false; } -bool AudioProcessorParameter::isAutomatable() const { return true; } -bool AudioProcessorParameter::isMetaParameter() const { return false; } -AudioProcessorParameter::Category AudioProcessorParameter::getCategory() const { return genericParameter; } -int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); } -bool AudioProcessorParameter::isDiscrete() const { return false; } - -String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const -{ - return String (value, 2); -} - -//============================================================================== -bool AudioPlayHead::CurrentPositionInfo::operator== (const CurrentPositionInfo& other) const noexcept -{ - return timeInSamples == other.timeInSamples - && ppqPosition == other.ppqPosition - && editOriginTime == other.editOriginTime - && ppqPositionOfLastBarStart == other.ppqPositionOfLastBarStart - && frameRate == other.frameRate - && isPlaying == other.isPlaying - && isRecording == other.isRecording - && bpm == other.bpm - && timeSigNumerator == other.timeSigNumerator - && timeSigDenominator == other.timeSigDenominator - && ppqLoopStart == other.ppqLoopStart - && ppqLoopEnd == other.ppqLoopEnd - && isLooping == other.isLooping; -} - -bool AudioPlayHead::CurrentPositionInfo::operator!= (const CurrentPositionInfo& other) const noexcept -{ - return ! operator== (other); -} - -void AudioPlayHead::CurrentPositionInfo::resetToDefault() -{ - zerostruct (*this); - timeSigNumerator = 4; - timeSigDenominator = 4; - bpm = 120; -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h deleted file mode 100644 index 3a9bdd1fe..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ /dev/null @@ -1,1641 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -struct PluginBusUtilities; - -//============================================================================== -/** - Base class for audio processing filters or plugins. - - This is intended to act as a base class of audio filter that is general enough to - be wrapped as a VST, AU, RTAS, etc, or used internally. - - It is also used by the plugin hosting code as the wrapper around an instance - of a loaded plugin. - - Derive your filter class from this base class, and if you're building a plugin, - you should implement a global function called createPluginFilter() which creates - and returns a new instance of your subclass. -*/ -class JUCE_API AudioProcessor -{ -protected: - struct BusesProperties; - - //============================================================================== - /** Constructor. - - This constructor will create a main input and output bus which are diabled - by default. If you need more fine grain control then use the other - constructors. - */ - AudioProcessor(); - - /** Constructor for multibus AudioProcessors - - If your AudioProcessor supports multiple buses than use this constructor - to initialise the bus layouts and bus names of your plug-in. - */ - AudioProcessor (const BusesProperties& ioLayouts); - - /** Constructor for AudioProcessors which use layout maps - - If your AudioProcessor uses layout maps then use this constructor. - */ - #if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS - AudioProcessor (const std::initializer_list& channelLayoutList) - { - initialise (busesPropertiesFromLayoutArray (layoutListToArray (channelLayoutList))); - } - #else - template - AudioProcessor (const short (&channelLayoutList) [numLayouts][2]) - { - initialise (busesPropertiesFromLayoutArray (layoutListToArray (channelLayoutList))); - } - #endif - -public: - //============================================================================== - enum ProcessingPrecision - { - singlePrecision, - doublePrecision - }; - - //============================================================================== - /** Destructor. */ - virtual ~AudioProcessor(); - - //============================================================================== - /** Returns the name of this processor. */ - virtual const String getName() const = 0; - - /** Returns a list of alternative names to use for this processor. - - Some hosts truncate the name of your AudioProcessor when there isn't enough - space in the GUI to show the full name. Overriding this method, allows the host - to choose an alternative name (such as an abbreviation) to better fit the - available space. - */ - virtual StringArray getAlternateDisplayNames() const; - - //============================================================================== - /** Called before playback starts, to let the filter prepare itself. - - The sample rate is the target sample rate, and will remain constant until - playback stops. - - You can call getTotalNumInputChannels and getTotalNumOutputChannels - or query the busLayout member variable to find out the number of - channels your processBlock callback must process. - - The maximumExpectedSamplesPerBlock value is a strong hint about the maximum - number of samples that will be provided in each block. You may want to use - this value to resize internal buffers. You should program defensively in - case a buggy host exceeds this value. The actual block sizes that the host - uses may be different each time the callback happens: completely variable - block sizes can be expected from some hosts. - - @see busLayout, getTotalNumInputChannels, getTotalNumOutputChannels - */ - virtual void prepareToPlay (double sampleRate, - int maximumExpectedSamplesPerBlock) = 0; - - /** Called after playback has stopped, to let the filter free up any resources it - no longer needs. - */ - virtual void releaseResources() = 0; - - /** Renders the next block. - - When this method is called, the buffer contains a number of channels which is - at least as great as the maximum number of input and output channels that - this filter is using. It will be filled with the filter's input data and - should be replaced with the filter's output. - - So for example if your filter has a total of 2 input channels and 4 output - channels, then the buffer will contain 4 channels, the first two being filled - with the input data. Your filter should read these, do its processing, and - replace the contents of all 4 channels with its output. - - Or if your filter has a total of 5 inputs and 2 outputs, the buffer will have 5 - channels, all filled with data, and your filter should overwrite the first 2 of - these with its output. But be VERY careful not to write anything to the last 3 - channels, as these might be mapped to memory that the host assumes is read-only! - - If your plug-in has more than one input or output buses then the buffer passed - to the processBlock methods will contain a bundle of all channels of each bus. - Use AudiobusLayout::getBusBuffer to obtain an audio buffer for a - particular bus. - - Note that if you have more outputs than inputs, then only those channels that - correspond to an input channel are guaranteed to contain sensible data - e.g. - in the case of 2 inputs and 4 outputs, the first two channels contain the input, - but the last two channels may contain garbage, so you should be careful not to - let this pass through without being overwritten or cleared. - - Also note that the buffer may have more channels than are strictly necessary, - but you should only read/write from the ones that your filter is supposed to - be using. - - The number of samples in these buffers is NOT guaranteed to be the same for every - callback, and may be more or less than the estimated value given to prepareToPlay(). - Your code must be able to cope with variable-sized blocks, or you're going to get - clicks and crashes! - - Also note that some hosts will occasionally decide to pass a buffer containing - zero samples, so make sure that your algorithm can deal with that! - - If the filter is receiving a midi input, then the midiMessages array will be filled - with the midi messages for this block. Each message's timestamp will indicate the - message's time, as a number of samples from the start of the block. - - Any messages left in the midi buffer when this method has finished are assumed to - be the filter's midi output. This means that your filter should be careful to - clear any incoming messages from the array if it doesn't want them to be passed-on. - - Be very careful about what you do in this callback - it's going to be called by - the audio thread, so any kind of interaction with the UI is absolutely - out of the question. If you change a parameter in here and need to tell your UI to - update itself, the best way is probably to inherit from a ChangeBroadcaster, let - the UI components register as listeners, and then call sendChangeMessage() inside the - processBlock() method to send out an asynchronous message. You could also use - the AsyncUpdater class in a similar way. - - @see AudiobusLayout::getBusBuffer - */ - - virtual void processBlock (AudioBuffer& buffer, - MidiBuffer& midiMessages) = 0; - - /** Renders the next block. - - When this method is called, the buffer contains a number of channels which is - at least as great as the maximum number of input and output channels that - this filter is using. It will be filled with the filter's input data and - should be replaced with the filter's output. - - So for example if your filter has a combined total of 2 input channels and - 4 output channels, then the buffer will contain 4 channels, the first two - being filled with the input data. Your filter should read these, do its - processing, and replace the contents of all 4 channels with its output. - - Or if your filter has 5 inputs and 2 outputs, the buffer will have 5 channels, - all filled with data, and your filter should overwrite the first 2 of these - with its output. But be VERY careful not to write anything to the last 3 - channels, as these might be mapped to memory that the host assumes is read-only! - - If your plug-in has more than one input or output buses then the buffer passed - to the processBlock methods will contain a bundle of all channels of - each bus. Use AudiobusLayout::getBusBuffer to obtain a audio buffer - for a particular bus. - - Note that if you have more outputs than inputs, then only those channels that - correspond to an input channel are guaranteed to contain sensible data - e.g. - in the case of 2 inputs and 4 outputs, the first two channels contain the input, - but the last two channels may contain garbage, so you should be careful not to - let this pass through without being overwritten or cleared. - - Also note that the buffer may have more channels than are strictly necessary, - but you should only read/write from the ones that your filter is supposed to - be using. - - If your plugin uses buses, then you should use AudiobusLayout::getBusBuffer() - or AudiobusLayout::getChannelIndexInProcessBlockBuffer() to find out which - of the input and output channels correspond to which of the buses. - - The number of samples in these buffers is NOT guaranteed to be the same for every - callback, and may be more or less than the estimated value given to prepareToPlay(). - Your code must be able to cope with variable-sized blocks, or you're going to get - clicks and crashes! - - Also note that some hosts will occasionally decide to pass a buffer containing - zero samples, so make sure that your algorithm can deal with that! - - If the filter is receiving a midi input, then the midiMessages array will be filled - with the midi messages for this block. Each message's timestamp will indicate the - message's time, as a number of samples from the start of the block. - - Any messages left in the midi buffer when this method has finished are assumed to - be the filter's midi output. This means that your filter should be careful to - clear any incoming messages from the array if it doesn't want them to be passed-on. - - Be very careful about what you do in this callback - it's going to be called by - the audio thread, so any kind of interaction with the UI is absolutely - out of the question. If you change a parameter in here and need to tell your UI to - update itself, the best way is probably to inherit from a ChangeBroadcaster, let - the UI components register as listeners, and then call sendChangeMessage() inside the - processBlock() method to send out an asynchronous message. You could also use - the AsyncUpdater class in a similar way. - - @see AudiobusLayout::getBusBuffer - */ - virtual void processBlock (AudioBuffer& buffer, - MidiBuffer& midiMessages); - - /** Renders the next block when the processor is being bypassed. - - The default implementation of this method will pass-through any incoming audio, but - you may override this method e.g. to add latency compensation to the data to match - the processor's latency characteristics. This will avoid situations where bypassing - will shift the signal forward in time, possibly creating pre-echo effects and odd timings. - Another use for this method would be to cross-fade or morph between the wet (not bypassed) - and dry (bypassed) signals. - */ - virtual void processBlockBypassed (AudioBuffer& buffer, - MidiBuffer& midiMessages); - - /** Renders the next block when the processor is being bypassed. - - The default implementation of this method will pass-through any incoming audio, but - you may override this method e.g. to add latency compensation to the data to match - the processor's latency characteristics. This will avoid situations where bypassing - will shift the signal forward in time, possibly creating pre-echo effects and odd timings. - Another use for this method would be to cross-fade or morph between the wet (not bypassed) - and dry (bypassed) signals. - */ - virtual void processBlockBypassed (AudioBuffer& buffer, - MidiBuffer& midiMessages); - - - //============================================================================== - /** - Represents the bus layout state of a plug-in - */ - struct BusesLayout - { - /** An array containing the list of input buses that this processor supports. */ - Array inputBuses; - - /** An array containing the list of output buses that this processor supports. */ - Array outputBuses; - - /** Get the number of channels of a particular bus */ - int getNumChannels (bool isInput, int busIndex) const noexcept - { - const Array& bus = (isInput ? inputBuses : outputBuses); - return isPositiveAndBelow (busIndex, bus.size()) ? bus.getReference (busIndex).size() : 0; - } - - /** Get the channel set of a particular bus */ - AudioChannelSet& getChannelSet (bool isInput, int busIndex) - { - return (isInput ? inputBuses : outputBuses).getReference (busIndex); - } - - /** Get the channel set of a particular bus */ - AudioChannelSet getChannelSet (bool isInput, int busIndex) const noexcept - { - return (isInput ? inputBuses : outputBuses) [busIndex]; - } - - /** Get the input channel layout on the main bus. */ - AudioChannelSet getMainInputChannelSet() const noexcept { return getChannelSet (true, 0); } - - /** Get the output channel layout on the main bus. */ - AudioChannelSet getMainOutputChannelSet() const noexcept { return getChannelSet (false, 0); } - - /** Get the number of input channels on the main bus. */ - int getMainInputChannels() const noexcept { return getNumChannels (true, 0); } - - /** Get the number of output channels on the main bus. */ - int getMainOutputChannels() const noexcept { return getNumChannels (false, 0); } - - bool operator== (const BusesLayout& other) const noexcept { return inputBuses == other.inputBuses && outputBuses == other.outputBuses; } - bool operator!= (const BusesLayout& other) const noexcept { return inputBuses != other.inputBuses || outputBuses != other.outputBuses; } - }; - - //============================================================================== - /** - Describes the layout and properties of an audio bus. - Effectively a bus description is a named set of channel types. - - @see AudioChannelSet, AudioProcessor::addBus - */ - class Bus - { - public: - /** Returns true if this bus is an input bus. */ - bool isInput() const; - - /** Returns the index of this bus. */ - int getBusIndex() const; - - /** Returns true if the current bus is the main input or output bus. */ - bool isMain() const { return getBusIndex() == 0; } - - //============================================================================== - /** The bus's name. */ - const String &getName() const noexcept { return name; } - - /** Get the default layout of this bus. - @see AudioChannelSet - */ - const AudioChannelSet& getDefaultLayout() const noexcept { return dfltLayout; } - - //============================================================================== - /** The bus's current layout. This will be AudioChannelSet::disabled() if the current - layout is dfisabled. - - @see AudioChannelSet - */ - const AudioChannelSet& getCurrentLayout() const noexcept { return layout; } - - /** Return the bus's last active channel layout. - If the bus is currently enabled then the result will be identical to getCurrentLayout - otherwise it will return the last enabled layout. - - @see AudioChannelSet - */ - const AudioChannelSet& getLastEnabledLayout() const noexcept { return lastLayout; } - - /** Sets the bus's current layout. - If the AudioProcessor does not support this layout then this will return false. - @see AudioChannelSet - */ - bool setCurrentLayout (const AudioChannelSet& layout); - - /** Sets the bus's current layout without changing the enabled state. - - If the AudioProcessor does not support this layout then this will return false. - - @see AudioChannelSet - */ - bool setCurrentLayoutWithoutEnabling (const AudioChannelSet& layout); - - /** Return the number of channels of the current bus. */ - inline int getNumberOfChannels() const noexcept { return cachedChannelCount; } - - /** Set the number of channles of this bus. This will return false if the AudioProcessor - does not support this layout. - */ - bool setNumberOfChannels (int channels); - - //============================================================================== - /** Checks if a particular layout is supported. - - @param set The AudioChannelSet which is to be probed. - @param currentLayout If non-null, pretend that the current layout of the AudioProcessor is - currentLayout. On exit, currentLayout will be modified to - to represent the buses layouts of the AudioProcessor as if the layout - of the reciever had been succesfully changed. This is useful as changing - the layout of the reciever may change the bus layout of other buses. - - @see AudioChannelSet - */ - bool isLayoutSupported (const AudioChannelSet& set, BusesLayout* currentLayout = nullptr) const; - - /** Checks if this bus can support a given number of channels. */ - bool isNumberOfChannelsSupported (int channels) const; - - /** Returns a ChannelSet that the bus supports with a given number of channels. */ - AudioChannelSet supportedLayoutWithChannels (int channels) const; - - /** Returns the maximum number of channels that this bus can support. - @param limit The maximum value to return. - */ - int getMaxSupportedChannels (int limit = AudioChannelSet::maxChannelsOfNamedLayout) const; - - /** Returns the resulting layouts of all buses after changing the layout of this bus. - - Changing an individual layout of a bus may also change the layout of all the other - buses. This method returns what the layouts of all the buses of the audio processor - would be, if you were to change the layout of this bus to the given layout. If there - is no way to support the given layout then this method will return the next best - layout. - */ - BusesLayout getBusesLayoutForLayoutChangeOfBus (const AudioChannelSet& set) const; - - //============================================================================== - /** Returns true if the current bus is enabled. */ - bool isEnabled() const noexcept { return ! layout.isDisabled(); } - - /** Enable or disable this bus. This will return false if the AudioProcessor - does not support disabling this bus. */ - bool enable (bool shouldEnable = true); - - /** Returns if this bus is enabled by default. */ - bool isEnabledByDefault() const noexcept { return enabledByDefault; } - - //============================================================================== - /** Returns the position of a bus's channels within the processBlock buffer. - This can be called in processBlock to figure out which channel of the master AudioSampleBuffer - maps onto a specific bus's channel. - */ - int getChannelIndexInProcessBlockBuffer (int channelIndex) const noexcept; - - - /** Returns an AudioBuffer containing a set of channel pointers for a specific bus. - This can be called in processBlock to get a buffer containing a sub-group of the master - AudioSampleBuffer which contains all the plugin channels. - */ - template - AudioBuffer getBusBuffer (AudioBuffer& processBlockBuffer) const - { - bool isIn; - int busIdx; - busDirAndIndex (isIn, busIdx); - return owner.getBusBuffer (processBlockBuffer, isIn, busIdx); - } - - private: - friend class AudioProcessor; - Bus (AudioProcessor&, const String&, const AudioChannelSet&, bool); - void busDirAndIndex (bool&, int&) const noexcept; - void updateChannelCount() noexcept; - - AudioProcessor& owner; - String name; - AudioChannelSet layout, dfltLayout, lastLayout; - bool enabledByDefault; - int cachedChannelCount; - - JUCE_DECLARE_NON_COPYABLE (Bus) - }; - - //============================================================================== - /** Returns the number of buses on the input or output side */ - int getBusCount (bool isInput) const noexcept { return (isInput ? inputBuses : outputBuses).size(); } - - /** Returns the audio bus with a given index and direction. - - If busIdx is invalid then this method will return a nullptr. - */ - Bus* getBus (bool isInput, int busIdx) noexcept { return (isInput ? inputBuses : outputBuses)[busIdx]; } - - /** Returns the audio bus with a given index and direction. - - If busIdx is invalid then this method will return a nullptr. - */ - const Bus* getBus (bool isInput, int busIdx) const noexcept { return const_cast (this)->getBus (isInput, busIdx); } - - //============================================================================== - /** Callback to query if a bus can currently be added. - - This callback probes if a bus can currently be added. You should override - this callback if you want to support dynamically adding/removing buses by - the host. This is useful for mixer audio processors. - - The default implementation will always return false. - - @see addBus - */ - virtual bool canAddBus (bool isInput) const { ignoreUnused (isInput); return false; } - - /** Callback to query if the last bus can currently be removed. - - This callback probes if the last bus can currently be removed. You should - override this callback if you want to support dynamically adding/removing - buses by the host. This is useful for mixer audio processors. - - If you return true in this callback then the AudioProcessor will go ahead - and delete the bus. - - The default implementation will always return false. - */ - virtual bool canRemoveBus (bool isInput) const { ignoreUnused (isInput); return false; } - - /** Dynamically request an additional bus. - - Request an additional bus from the audio processor. If the audio processor - does not support adding additional buses then this method will return false. - - Most audio processors will not allow you to dynamically add/remove - audio buses and will return false. - - This method will invoke the canApplyBusCountChange callback to probe - if a bus can be added and, if yes, will use the supplied bus properties - of the canApplyBusCountChange callback to create a new bus. - - @see canApplyBusCountChange, removeBus - */ - bool addBus (bool isInput); - - /** Dynamically remove the latest added bus. - - Request the removal of the last bus from the audio processor. If the - audio processor does not support removing buses then this method will - return false. - - Most audio processors will not allow you to dynamically add/remove - audio buses and will return false. - - The default implementation will return false. - - This method will invoke the canApplyBusCountChange callback to probe if - a bus can currently be removed and, if yes, will go ahead and remove it. - - @see addBus, canRemoveBus - */ - bool removeBus (bool isInput); - - //============================================================================== - /** Set the channel layouts of this audio processor. - - If the layout is not supported by this audio processor then - this method will return false. You can use the checkBusesLayoutSupported - and getNextBestLayout methods to probe which layouts this audio - processor supports. - */ - bool setBusesLayout (const BusesLayout&); - - /** Set the channel layouts of this audio processor without changing the - enablement state of the buses. - - If the layout is not supported by this audio processor then - this method will return false. You can use the checkBusesLayoutSupported - methods to probe which layouts this audio processor supports. - */ - bool setBusesLayoutWithoutEnabling (const BusesLayout&); - - /** Provides the current channel layouts of this audio processor. */ - BusesLayout getBusesLayout() const; - - /** Provides the channel layout of the bus with a given index and direction. - - If the index, direction combination is invalid then this will return an - AudioChannelSet with no channels. - */ - AudioChannelSet getChannelLayoutOfBus (bool isInput, int busIndex) const noexcept; - - /** Set the channel layout of the bus with a given index and direction. - - If the index, direction combination is invalid or the layout is not - supported by the audio processor then this method will return false. - */ - bool setChannelLayoutOfBus (bool isInput, int busIdx, const AudioChannelSet& layout); - - /** Provides the number of channels of the bus with a given index and direction. - - If the index, direction combination is invalid then this will return zero. - */ - inline int getChannelCountOfBus (bool isInput, int busIdx) const noexcept - { - if (const Bus* bus = getBus (isInput, busIdx)) - return bus->getNumberOfChannels(); - - return 0; - } - - /** Enables all buses */ - bool enableAllBuses(); - - /** Disables all non-main buses (aux and sidechains). */ - bool disableNonMainBuses(); - - //============================================================================== - /** Returns the position of a bus's channels within the processBlock buffer. - This can be called in processBlock to figure out which channel of the master AudioSampleBuffer - maps onto a specific bus's channel. - */ - int getChannelIndexInProcessBlockBuffer (bool isInput, int busIndex, int channelIndex) const noexcept; - - /** Returns the offset in a bus's buffer from an absolute channel indes. - - This method returns the offset in a bus's buffer given an absolute channel index. - It also provides the bus index. For example, this method would return one - for a processor with two stereo buses when given the absolute channel index. - */ - int getOffsetInBusBufferForAbsoluteChannelIndex (bool isInput, int absoluteChannelIndex, /*out*/ int& busIdx) const noexcept; - - /** Returns an AudioBuffer containing a set of channel pointers for a specific bus. - This can be called in processBlock to get a buffer containing a sub-group of the master - AudioSampleBuffer which contains all the plugin channels. - */ - template - AudioBuffer getBusBuffer (AudioBuffer& processBlockBuffer, bool isInput, int busIndex) const - { - const int busNumChannels = getChannelCountOfBus (isInput, busIndex); - const int channelOffset = getChannelIndexInProcessBlockBuffer (isInput, busIndex, 0); - - return AudioBuffer (processBlockBuffer.getArrayOfWritePointers() + channelOffset, - busNumChannels, processBlockBuffer.getNumSamples()); - } - - //============================================================================== - /** Returns true if the Audio processor is likely to support a given layout. - This can be called regardless if the processor is currently running. - */ - bool checkBusesLayoutSupported (const BusesLayout&) const; - - //============================================================================== - /** Returns true if the Audio processor supports double precision floating point processing. - The default implementation will always return false. - If you return true here then you must override the double precision versions - of processBlock. Additionally, you must call getProcessingPrecision() in - your prepareToPlay method to determine the precision with which you need to - allocate your internal buffers. - @see getProcessingPrecision, setProcessingPrecision - */ - virtual bool supportsDoublePrecisionProcessing() const; - - /** Returns the precision-mode of the processor. - Depending on the result of this method you MUST call the corresponding version - of processBlock. The default processing precision is single precision. - @see setProcessingPrecision, supportsDoublePrecisionProcessing - */ - ProcessingPrecision getProcessingPrecision() const noexcept { return processingPrecision; } - - /** Returns true if the current precision is set to doublePrecision. */ - bool isUsingDoublePrecision() const noexcept { return processingPrecision == doublePrecision; } - - /** Changes the processing precision of the receiver. A client of the AudioProcessor - calls this function to indicate which version of processBlock (single or double - precision) it intends to call. The client MUST call this function before calling - the prepareToPlay method so that the receiver can do any necessary allocations - in the prepareToPlay() method. An implementation of prepareToPlay() should call - getProcessingPrecision() to determine with which precision it should allocate - it's internal buffers. - - Note that setting the processing precision to double floating point precision - on a receiver which does not support double precision processing (i.e. - supportsDoublePrecisionProcessing() returns false) will result in an assertion. - - @see getProcessingPrecision, supportsDoublePrecisionProcessing - */ - void setProcessingPrecision (ProcessingPrecision newPrecision) noexcept; - - //============================================================================== - /** Returns the current AudioPlayHead object that should be used to find - out the state and position of the playhead. - - You can ONLY call this from your processBlock() method! Calling it at other - times will produce undefined behaviour, as the host may not have any context - in which a time would make sense, and some hosts will almost certainly have - multithreading issues if it's not called on the audio thread. - - The AudioPlayHead object that is returned can be used to get the details about - the time of the start of the block currently being processed. But do not - store this pointer or use it outside of the current audio callback, because - the host may delete or re-use it. - - If the host can't or won't provide any time info, this will return nullptr. - */ - AudioPlayHead* getPlayHead() const noexcept { return playHead; } - - //============================================================================== - /** Returns the total number of input channels. - - This method will return the total number of input channels by accumulating - the number of channels on each input bus. The number of channels of the - buffer passed to your processBlock callback will be equivalent to either - getTotalNumInputChannels or getTotalNumOutputChannels - which ever - is greater. - - Note that getTotalNumInputChannels is equivalent to - getMainBusNumInputChannels if your processor does not have any sidechains - or aux buses. - */ - int getTotalNumInputChannels() const noexcept { return cachedTotalIns; } - - /** Returns the total number of output channels. - - This method will return the total number of output channels by accumulating - the number of channels on each output bus. The number of channels of the - buffer passed to your processBlock callback will be equivalent to either - getTotalNumInputChannels or getTotalNumOutputChannels - which ever - is greater. - - Note that getTotalNumOutputChannels is equivalent to - getMainBusNumOutputChannels if your processor does not have any sidechains - or aux buses. - */ - int getTotalNumOutputChannels() const noexcept { return cachedTotalOuts; } - - /** Returns the number of input channels on the main bus. */ - inline int getMainBusNumInputChannels() const noexcept { return getChannelCountOfBus (true, 0); } - - /** Returns the number of output channels on the main bus. */ - inline int getMainBusNumOutputChannels() const noexcept { return getChannelCountOfBus (false, 0); } - - //============================================================================== - /** Returns true if the channel layout map contains a certain layout. - - You can use this method to help you implement the checkBusesLayoutSupported - method. For example - - @code - bool checkBusesLayoutSupported (const BusesLayout& layouts) override - { - return containsLayout (layouts, {{1,1},{2,2}}); - } - @endcode - */ - #if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS - static bool containsLayout (const BusesLayout& layouts, const std::initializer_list& channelLayoutList) - { - return containsLayout (layouts, layoutListToArray (channelLayoutList)); - } - #endif - - template - static bool containsLayout (const BusesLayout& layouts, const short (&channelLayoutList) [numLayouts][2]) - { - return containsLayout (layouts, layoutListToArray (channelLayoutList)); - } - - /** Returns the next best layout which is contained in a channel layout map. - - You can use this mehtod to help you implement getNextBestLayout. For example: - - @code - BusesLayout getNextBestLayout (const BusesLayout& layouts) override - { - return getNextBestLayoutInLayoutList (layouts, {{1,1},{2,2}}); - } - @endcode - */ - template - BusesLayout getNextBestLayoutInLayoutList (const BusesLayout& layouts, - const short (&channelLayoutList) [numLayouts][2]) - { - return getNextBestLayoutInList (layouts, layoutListToArray (channelLayoutList)); - } - - //============================================================================== - /** Returns the current sample rate. - - This can be called from your processBlock() method - it's not guaranteed - to be valid at any other time, and may return 0 if it's unknown. - */ - double getSampleRate() const noexcept { return currentSampleRate; } - - /** Returns the current typical block size that is being used. - - This can be called from your processBlock() method - it's not guaranteed - to be valid at any other time. - - Remember it's not the ONLY block size that may be used when calling - processBlock, it's just the normal one. The actual block sizes used may be - larger or smaller than this, and will vary between successive calls. - */ - int getBlockSize() const noexcept { return blockSize; } - - //============================================================================== - - /** This returns the number of samples delay that the filter imposes on the audio - passing through it. - - The host will call this to find the latency - the filter itself should set this value - by calling setLatencySamples() as soon as it can during its initialisation. - */ - int getLatencySamples() const noexcept { return latencySamples; } - - /** The filter should call this to set the number of samples delay that it introduces. - - The filter should call this as soon as it can during initialisation, and can call it - later if the value changes. - */ - void setLatencySamples (int newLatency); - - /** Returns the length of the filter's tail, in seconds. */ - virtual double getTailLengthSeconds() const = 0; - - /** Returns true if the processor wants midi messages. */ - virtual bool acceptsMidi() const = 0; - - /** Returns true if the processor produces midi messages. */ - virtual bool producesMidi() const = 0; - - /** Returns true if the processor supports MPE. */ - virtual bool supportsMPE() const { return false; } - - /** Returns true if this is a midi effect plug-in and does no audio processing. */ - virtual bool isMidiEffect() const { return false; } - - //============================================================================== - /** This returns a critical section that will automatically be locked while the host - is calling the processBlock() method. - - Use it from your UI or other threads to lock access to variables that are used - by the process callback, but obviously be careful not to keep it locked for - too long, because that could cause stuttering playback. If you need to do something - that'll take a long time and need the processing to stop while it happens, use the - suspendProcessing() method instead. - - @see suspendProcessing - */ - const CriticalSection& getCallbackLock() const noexcept { return callbackLock; } - - /** Enables and disables the processing callback. - - If you need to do something time-consuming on a thread and would like to make sure - the audio processing callback doesn't happen until you've finished, use this - to disable the callback and re-enable it again afterwards. - - E.g. - @code - void loadNewPatch() - { - suspendProcessing (true); - - ..do something that takes ages.. - - suspendProcessing (false); - } - @endcode - - If the host tries to make an audio callback while processing is suspended, the - filter will return an empty buffer, but won't block the audio thread like it would - do if you use the getCallbackLock() critical section to synchronise access. - - Any code that calls processBlock() should call isSuspended() before doing so, and - if the processor is suspended, it should avoid the call and emit silence or - whatever is appropriate. - - @see getCallbackLock - */ - void suspendProcessing (bool shouldBeSuspended); - - /** Returns true if processing is currently suspended. - @see suspendProcessing - */ - bool isSuspended() const noexcept { return suspended; } - - /** A plugin can override this to be told when it should reset any playing voices. - - The default implementation does nothing, but a host may call this to tell the - plugin that it should stop any tails or sounds that have been left running. - */ - virtual void reset(); - - //============================================================================== - /** Returns true if the processor is being run in an offline mode for rendering. - - If the processor is being run live on realtime signals, this returns false. - If the mode is unknown, this will assume it's realtime and return false. - - This value may be unreliable until the prepareToPlay() method has been called, - and could change each time prepareToPlay() is called. - - @see setNonRealtime() - */ - bool isNonRealtime() const noexcept { return nonRealtime; } - - /** Called by the host to tell this processor whether it's being used in a non-realtime - capacity for offline rendering or bouncing. - */ - virtual void setNonRealtime (bool isNonRealtime) noexcept; - - #if ! JUCE_AUDIOPROCESSOR_NO_GUI - //============================================================================== - /** Creates the filter's UI. - - This can return nullptr if you want a UI-less filter, in which case the host may create - a generic UI that lets the user twiddle the parameters directly. - - If you do want to pass back a component, the component should be created and set to - the correct size before returning it. If you implement this method, you must - also implement the hasEditor() method and make it return true. - - Remember not to do anything silly like allowing your filter to keep a pointer to - the component that gets created - it could be deleted later without any warning, which - would make your pointer into a dangler. Use the getActiveEditor() method instead. - - The correct way to handle the connection between an editor component and its - filter is to use something like a ChangeBroadcaster so that the editor can - register itself as a listener, and be told when a change occurs. This lets them - safely unregister themselves when they are deleted. - - Here are a few things to bear in mind when writing an editor: - - - Initially there won't be an editor, until the user opens one, or they might - not open one at all. Your filter mustn't rely on it being there. - - An editor object may be deleted and a replacement one created again at any time. - - It's safe to assume that an editor will be deleted before its filter. - - @see hasEditor - */ - virtual AudioProcessorEditor* createEditor() = 0; - - /** Your filter must override this and return true if it can create an editor component. - @see createEditor - */ - virtual bool hasEditor() const = 0; - - //============================================================================== - /** Returns the active editor, if there is one. - Bear in mind this can return nullptr, even if an editor has previously been opened. - */ - AudioProcessorEditor* getActiveEditor() const noexcept { return activeEditor; } - - /** Returns the active editor, or if there isn't one, it will create one. - This may call createEditor() internally to create the component. - */ - AudioProcessorEditor* createEditorIfNeeded(); - #endif - - //============================================================================== - /** This must return the correct value immediately after the object has been - created, and mustn't change the number of parameters later. - - NOTE! This method will eventually be deprecated! It's recommended that you use the - AudioProcessorParameter class instead to manage your parameters. - */ - virtual int getNumParameters(); - - /** Returns the name of a particular parameter. - - NOTE! This method will eventually be deprecated! It's recommended that you use the - AudioProcessorParameter class instead to manage your parameters. - */ - virtual const String getParameterName (int parameterIndex); - - /** Returns the ID of a particular parameter. - - The ID is used to communicate the value or mapping of a particular parameter with - the host. By default this method will simply return a string representation of - index. - - NOTE! This method will eventually be deprecated! It's recommended that you use the - AudioProcessorParameterWithID class instead to manage your parameters. - */ - virtual String getParameterID (int index); - - /** Called by the host to find out the value of one of the filter's parameters. - - The host will expect the value returned to be between 0 and 1.0. - - This could be called quite frequently, so try to make your code efficient. - It's also likely to be called by non-UI threads, so the code in here should - be thread-aware. - - NOTE! This method will eventually be deprecated! It's recommended that you use the - AudioProcessorParameter class instead to manage your parameters. - */ - virtual float getParameter (int parameterIndex); - - /** Returns the name of a parameter as a text string with a preferred maximum length. - If you want to provide customised short versions of your parameter names that - will look better in constrained spaces (e.g. the displays on hardware controller - devices or mixing desks) then you should implement this method. - If you don't override it, the default implementation will call getParameterName(int), - and truncate the result. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::getName() instead. - */ - virtual String getParameterName (int parameterIndex, int maximumStringLength); - - /** Returns the value of a parameter as a text string. - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::getText() instead. - */ - virtual const String getParameterText (int parameterIndex); - - /** Returns the value of a parameter as a text string with a preferred maximum length. - If you want to provide customised short versions of your parameter values that - will look better in constrained spaces (e.g. the displays on hardware controller - devices or mixing desks) then you should implement this method. - If you don't override it, the default implementation will call getParameterText(int), - and truncate the result. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::getText() instead. - */ - virtual String getParameterText (int parameterIndex, int maximumStringLength); - - /** Returns the number of discrete steps that this parameter can represent. - - The default return value if you don't implement this method is - AudioProcessor::getDefaultNumParameterSteps(). - - If your parameter is boolean, then you may want to make this return 2. - - If you want the host to display stepped automation values, rather than a - continuous interpolation between successive values, you should ensure that - isParameterDiscrete returns true. - - The value that is returned may or may not be used, depending on the host. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::getNumSteps() instead. - - @see isParameterDiscrete - */ - virtual int getParameterNumSteps (int parameterIndex); - - /** Returns the default number of steps for a parameter. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::getNumSteps() instead. - - @see getParameterNumSteps - */ - static int getDefaultNumParameterSteps() noexcept; - - /** Returns true if the parameter should take discrete, rather than continuous - values. - - If the parameter is boolean, this should return true (with getParameterNumSteps - returning 2). - - The value that is returned may or may not be used, depending on the host. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::isDiscrete() instead. - - @see getParameterNumSteps - */ - virtual bool isParameterDiscrete (int parameterIndex) const; - - /** Returns the default value for the parameter. - By default, this just returns 0. - The value that is returned may or may not be used, depending on the host. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::getDefaultValue() instead. - */ - virtual float getParameterDefaultValue (int parameterIndex); - - /** Some plugin types may be able to return a label string for a - parameter's units. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::getLabel() instead. - */ - virtual String getParameterLabel (int index) const; - - /** This can be overridden to tell the host that particular parameters operate in the - reverse direction. (Not all plugin formats or hosts will actually use this information). - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::isOrientationInverted() instead. - */ - virtual bool isParameterOrientationInverted (int index) const; - - /** The host will call this method to change the value of one of the filter's parameters. - - The host may call this at any time, including during the audio processing - callback, so the filter has to process this very fast and avoid blocking. - - If you want to set the value of a parameter internally, e.g. from your - editor component, then don't call this directly - instead, use the - setParameterNotifyingHost() method, which will also send a message to - the host telling it about the change. If the message isn't sent, the host - won't be able to automate your parameters properly. - - The value passed will be between 0 and 1.0. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::setValue() instead. - */ - virtual void setParameter (int parameterIndex, float newValue); - - /** Your filter can call this when it needs to change one of its parameters. - - This could happen when the editor or some other internal operation changes - a parameter. This method will call the setParameter() method to change the - value, and will then send a message to the host telling it about the change. - - Note that to make sure the host correctly handles automation, you should call - the beginParameterChangeGesture() and endParameterChangeGesture() methods to - tell the host when the user has started and stopped changing the parameter. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::setValueNotifyingHost() instead. - */ - void setParameterNotifyingHost (int parameterIndex, float newValue); - - /** Returns true if the host can automate this parameter. - By default, this returns true for all parameters. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::isAutomatable() instead. - */ - virtual bool isParameterAutomatable (int parameterIndex) const; - - /** Should return true if this parameter is a "meta" parameter. - A meta-parameter is a parameter that changes other params. It is used - by some hosts (e.g. AudioUnit hosts). - By default this returns false. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::isMetaParameter() instead. - */ - virtual bool isMetaParameter (int parameterIndex) const; - - /** Should return the parameter's category. - By default, this returns the "generic" category. - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::getCategory() instead. - */ - virtual AudioProcessorParameter::Category getParameterCategory (int parameterIndex) const; - - /** Sends a signal to the host to tell it that the user is about to start changing this - parameter. - - This allows the host to know when a parameter is actively being held by the user, and - it may use this information to help it record automation. - - If you call this, it must be matched by a later call to endParameterChangeGesture(). - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::beginChangeGesture() instead. - */ - void beginParameterChangeGesture (int parameterIndex); - - /** Tells the host that the user has finished changing this parameter. - - This allows the host to know when a parameter is actively being held by the user, and - it may use this information to help it record automation. - - A call to this method must follow a call to beginParameterChangeGesture(). - - NOTE! This method will eventually be deprecated! It's recommended that you use - AudioProcessorParameter::endChangeGesture() instead. - */ - void endParameterChangeGesture (int parameterIndex); - - /** The filter can call this when something (apart from a parameter value) has changed. - - It sends a hint to the host that something like the program, number of parameters, - etc, has changed, and that it should update itself. - */ - void updateHostDisplay(); - - //============================================================================== - /** Adds a parameter to the list. - The parameter object will be managed and deleted automatically by the list - when no longer needed. - */ - void addParameter (AudioProcessorParameter*); - - /** Returns the current list of parameters. */ - const OwnedArray& getParameters() const noexcept; - - //============================================================================== - /** Returns the number of preset programs the filter supports. - - The value returned must be valid as soon as this object is created, and - must not change over its lifetime. - - This value shouldn't be less than 1. - */ - virtual int getNumPrograms() = 0; - - /** Returns the number of the currently active program. */ - virtual int getCurrentProgram() = 0; - - /** Called by the host to change the current program. */ - virtual void setCurrentProgram (int index) = 0; - - /** Must return the name of a given program. */ - virtual const String getProgramName (int index) = 0; - - /** Called by the host to rename a program. */ - virtual void changeProgramName (int index, const String& newName) = 0; - - //============================================================================== - /** The host will call this method when it wants to save the filter's internal state. - - This must copy any info about the filter's state into the block of memory provided, - so that the host can store this and later restore it using setStateInformation(). - - Note that there's also a getCurrentProgramStateInformation() method, which only - stores the current program, not the state of the entire filter. - - See also the helper function copyXmlToBinary() for storing settings as XML. - - @see getCurrentProgramStateInformation - */ - virtual void getStateInformation (juce::MemoryBlock& destData) = 0; - - /** The host will call this method if it wants to save the state of just the filter's - current program. - - Unlike getStateInformation, this should only return the current program's state. - - Not all hosts support this, and if you don't implement it, the base class - method just calls getStateInformation() instead. If you do implement it, be - sure to also implement getCurrentProgramStateInformation. - - @see getStateInformation, setCurrentProgramStateInformation - */ - virtual void getCurrentProgramStateInformation (juce::MemoryBlock& destData); - - /** This must restore the filter's state from a block of data previously created - using getStateInformation(). - - Note that there's also a setCurrentProgramStateInformation() method, which tries - to restore just the current program, not the state of the entire filter. - - See also the helper function getXmlFromBinary() for loading settings as XML. - - @see setCurrentProgramStateInformation - */ - virtual void setStateInformation (const void* data, int sizeInBytes) = 0; - - /** The host will call this method if it wants to restore the state of just the filter's - current program. - - Not all hosts support this, and if you don't implement it, the base class - method just calls setStateInformation() instead. If you do implement it, be - sure to also implement getCurrentProgramStateInformation. - - @see setStateInformation, getCurrentProgramStateInformation - */ - virtual void setCurrentProgramStateInformation (const void* data, int sizeInBytes); - - /** This method is called when the total number of input or output channels is changed. */ - virtual void numChannelsChanged(); - - /** This method is called when the number of buses is changed. */ - virtual void numBusesChanged(); - - /** This method is called when the layout of the audio processor changes. */ - virtual void processorLayoutsChanged(); - - //============================================================================== - /** LV2 specific calls, saving/restore as string. */ - virtual String getStateInformationString () { return String(); } - virtual void setStateInformationString (const String&) {} - - //============================================================================== - /** Adds a listener that will be called when an aspect of this processor changes. */ - virtual void addListener (AudioProcessorListener* newListener); - - /** Removes a previously added listener. */ - virtual void removeListener (AudioProcessorListener* listenerToRemove); - - //============================================================================== - /** Tells the processor to use this playhead object. - The processor will not take ownership of the object, so the caller must delete it when - it is no longer being used. - */ - virtual void setPlayHead (AudioPlayHead* newPlayHead); - - //============================================================================== - /** This is called by the processor to specify its details before being played. Use this - version of the function if you are not interested in any sidechain and/or aux buses - and do not care about the layout of channels. Otherwise use setRateAndBufferSizeDetails.*/ - void setPlayConfigDetails (int numIns, int numOuts, double sampleRate, int blockSize); - - /** This is called by the processor to specify its details before being played. You - should call this function after having informed the processor about the channel - and bus layouts via setBusesLayout. - - @see setBusesLayout - */ - void setRateAndBufferSizeDetails (double sampleRate, int blockSize) noexcept; - - //============================================================================== - /** AAX plug-ins need to report a unique "plug-in id" for every audio layout - configuration that your AudioProcessor supports on the main bus. Override this - function if you want your AudioProcessor to use a custom "plug-in id" (for example - to stay backward compatible with older versions of JUCE). - - The default implementation will compute a unique integer from the input and output - layout and add this value to the 4 character code 'jcaa' (for native AAX) or 'jyaa' - (for AudioSuite plug-ins). - */ - virtual int32 getAAXPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout, - const AudioChannelSet& mainOutputLayout, - bool idForAudioSuite) const; - - #if ! JUCE_AUDIOPROCESSOR_NO_GUI - //============================================================================== - /** Not for public use - this is called before deleting an editor component. */ - void editorBeingDeleted (AudioProcessorEditor*) noexcept; - #endif - - /** Flags to indicate the type of plugin context in which a processor is being used. */ - enum WrapperType - { - wrapperType_Undefined = 0, - wrapperType_VST, - wrapperType_VST3, - wrapperType_AudioUnit, - wrapperType_AudioUnitv3, - wrapperType_RTAS, - wrapperType_AAX, - wrapperType_LV2, - wrapperType_Standalone - }; - - /** When loaded by a plugin wrapper, this flag will be set to indicate the type - of plugin within which the processor is running. - */ - WrapperType wrapperType; - - /** A struct containing information about the DAW track inside which your - AudioProcessor is loaded. */ - struct TrackProperties - { - String name; // The name of the track - this will be empty if the track name is not known - Colour colour; // The colour of the track - this will be transparentBlack if the colour is not known - - // other properties may be added in the future - }; - - /** Informs the AudioProcessor that track properties such as the track's name or - colour has been changed. - - If you are hosting this AudioProcessor then use this method to inform the - AudioProcessor about which track the AudioProcessor is loaded on. This method - may only be called on the message thread. - - If you are implemeting an AudioProcessor then you can override this callback - to do something useful with the track properties such as changing the colour - of your AudioProcessor's editor. It's entirely up to the host when and how - often this callback will be called. - - The default implementation of this callback will do nothing. - */ - virtual void updateTrackProperties (const TrackProperties& properties); - - //============================================================================== - #ifndef DOXYGEN - /** Deprecated: use getTotalNumInputChannels instead. */ - JUCE_DEPRECATED_WITH_BODY (int getNumInputChannels() const noexcept, { return getTotalNumInputChannels(); }) - JUCE_DEPRECATED_WITH_BODY (int getNumOutputChannels() const noexcept, { return getTotalNumOutputChannels(); }) - - /** Returns a string containing a whitespace-separated list of speaker types - These functions are deprecated: use the methods provided in the AudioChannelSet - class. - */ - JUCE_DEPRECATED_WITH_BODY (const String getInputSpeakerArrangement() const noexcept, { return cachedInputSpeakerArrString; }) - JUCE_DEPRECATED_WITH_BODY (const String getOutputSpeakerArrangement() const noexcept, { return cachedOutputSpeakerArrString; }) - - /** Returns the name of one of the processor's input channels. - - These functions are deprecated: your audio processor can inform the host - on channel layouts and names via the methods in the AudiobusLayout class. - */ - JUCE_DEPRECATED (virtual const String getInputChannelName (int channelIndex) const); - JUCE_DEPRECATED (virtual const String getOutputChannelName (int channelIndex) const); - - /** Returns true if the specified channel is part of a stereo pair with its neighbour. - - These functions are deprecated: your audio processor should specify the audio - channel pairing information by modifying the busLayout member variable in - the constructor. */ - JUCE_DEPRECATED (virtual bool isInputChannelStereoPair (int index) const); - JUCE_DEPRECATED (virtual bool isOutputChannelStereoPair (int index) const); - #endif - - //============================================================================== - /** Helper function that just converts an xml element into a binary blob. - - Use this in your filter's getStateInformation() method if you want to - store its state as xml. - - Then use getXmlFromBinary() to reverse this operation and retrieve the XML - from a binary blob. - */ - static void copyXmlToBinary (const XmlElement& xml, - juce::MemoryBlock& destData); - - /** Retrieves an XML element that was stored as binary with the copyXmlToBinary() method. - - This might return nullptr if the data's unsuitable or corrupted. Otherwise it will return - an XmlElement object that the caller must delete when no longer needed. - */ - static XmlElement* getXmlFromBinary (const void* data, int sizeInBytes); - - /** @internal */ - static void JUCE_CALLTYPE setTypeOfNextNewPlugin (WrapperType); - -protected: - /** Callback to query if the AudioProcessor supports a specific layout. - - This callback is called when the host probes the supported bus layouts via - the checkBusesLayoutSupported method. You should override this callback if you - would like to limit the layouts that your AudioProcessor supports. The default - implementation will accept any layout. JUCE does basic sanity checks so that - the provided layouts parameter will have the same number of buses as your - AudioProcessor. - - @see checkBusesLayoutSupported - */ - virtual bool isBusesLayoutSupported (const BusesLayout&) const { return true; } - - /** Callback to check if a certain bus layout can now be applied - - Most subclasses will not need to override this method and should instead - override the isBusesLayoutSupported callback to reject certain layout changes. - - This callback is called when the user requests a layout change. It will only be - called if processing of the AudioProcessor has been stopped by a previous call to - releaseResources or after the construction of the AudioProcessor. It will be called - just before the actual layout change. By returning false you will abort the layout - change and setBusesLayout will return false indicating that the layout change - was not successful. - - The default implementation will simply call isBusesLayoutSupported. - - You only need to override this method if there is a chance that your AudioProcessor - may not accept a layout although you have previously claimed to support it via the - isBusesLayoutSupported callback. This can occur if your AudioProcessor's supported - layouts depend on other plug-in parameters which may have changed since the last - call to isBusesLayoutSupported, such as the format of an audio file which can be - selected by the user in the AudioProcessor's editor. This callback gives the - AudioProcessor a last chance to reject a layout if conditions have changed as it - is always called just before the actual layout change. - - As it is never called while the AudioProcessor is processing audio, it can also - be used for AudioProcessors which wrap other plug-in formats to apply the current - layout to the underlying plug-in. This callback gives such AudioProcessors a - chance to reject the layout change should an error occur with the underlying plug-in - during the layout change. - - @see isBusesLayoutSupported, setBusesLayout - */ - virtual bool canApplyBusesLayout (const BusesLayout& layouts) const { return isBusesLayoutSupported (layouts); } - - //============================================================================== - /** Structure used for AudioProcessor Callbacks */ - struct BusProperties - { - /** The name of the bus */ - String busName; - - /** The default layout of the bus */ - AudioChannelSet defaultLayout; - - /** Is this bus activated by default? */ - bool isActivatedByDefault; - }; - - struct BusesProperties - { - /** The layouts of the input buses */ - Array inputLayouts; - - /** The layouts of the output buses */ - Array outputLayouts; - - void addBus (bool isInput, const String& name, const AudioChannelSet& defaultLayout, bool isActivatedByDefault = true); - - BusesProperties withInput (const String& name, const AudioChannelSet& defaultLayout, bool isActivatedByDefault = true) const; - BusesProperties withOutput (const String& name, const AudioChannelSet& defaultLayout, bool isActivatedByDefault = true) const; - }; - - /** Callback to query if adding/removing buses currently possible. - - This callback is called when the host calls addBus or removeBus. - Similar to canApplyBusesLayout, this callback is only called while - the AudioProcessor is stopped and gives the processor a last - chance to reject a requested bus change. It can also be used to apply - the bus count change to an underlying wrapped plug-in. - - When adding a bus, isAddingBuses will be true and the plug-in is - expected to fill out outNewBusProperties with the properties of the - bus which will be created just after the succesful return of this callback. - - Implementations of AudioProcessor will rarely need to override this - method. Only override this method if your processor supports adding - and removing buses and if it needs more fine grain control over the - naming of new buses or may reject bus number changes although canAddBus - or canRemoveBus returned true. - - The default implementation will return false if canAddBus/canRemoveBus - returns false (the default behavior). Otherwise, this method returns - "Input #busIdx" for input buses and "Output #busIdx" for output buses - where busIdx is the index for newly created buses. The default layout - in this case will be the layout of the previous bus of the same direction. - */ - virtual bool canApplyBusCountChange (bool isInput, bool isAddingBuses, - BusProperties& outNewBusProperties); - - //============================================================================== - friend struct PluginBusUtilities; - - /** @internal */ - AudioPlayHead* playHead; - - /** @internal */ - void sendParamChangeMessageToListeners (int parameterIndex, float newValue); - -private: - //============================================================================== - struct InOutChannelPair - { - int16 inChannels, outChannels; - - InOutChannelPair() noexcept : inChannels (0), outChannels (0) {} - InOutChannelPair (const InOutChannelPair& o) noexcept : inChannels (o.inChannels), outChannels (o.outChannels) {} - InOutChannelPair (int16 inCh, int16 outCh) noexcept : inChannels (inCh), outChannels (outCh) {} - InOutChannelPair (const int16 (&config)[2]) noexcept : inChannels (config[0]), outChannels (config[1]) {} - - InOutChannelPair& operator= (const InOutChannelPair& o) noexcept { inChannels = o.inChannels; outChannels = o.outChannels; return *this; } - - bool operator== (const InOutChannelPair& other) const noexcept - { - return other.inChannels == inChannels && other.outChannels == outChannels; - } - }; - - template - static Array layoutListToArray (const short (&configuration) [numLayouts][2]) - { - Array layouts; - - for (int i = 0; i < numLayouts; ++i) - { - InOutChannelPair pair (configuration [i]); - layouts.add (pair); - } - - return layouts; - } - - #if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS - static Array layoutListToArray (const std::initializer_list& configuration) - { - Array layouts; - - for (std::initializer_list::const_iterator it = configuration.begin(); - it != configuration.end(); ++it) - { - InOutChannelPair pair (*it); - layouts.add (pair); - } - - return layouts; - } - #endif - - //============================================================================== - static BusesProperties busesPropertiesFromLayoutArray (const Array&); - - BusesLayout getNextBestLayoutInList (const BusesLayout&, const Array&) const; - static bool containsLayout (const BusesLayout&, const Array&); - - //============================================================================== - void initialise (const BusesProperties&); - void createBus (bool isInput, const BusProperties&); - - //============================================================================== - Array listeners; - #if ! JUCE_AUDIOPROCESSOR_NO_GUI - Component::SafePointer activeEditor; - #endif - double currentSampleRate; - int blockSize, latencySamples; - #if JUCE_DEBUG - bool textRecursionCheck; - #endif - bool suspended, nonRealtime; - ProcessingPrecision processingPrecision; - CriticalSection callbackLock, listenerLock; - - friend class Bus; - mutable OwnedArray inputBuses, outputBuses; - - String cachedInputSpeakerArrString; - String cachedOutputSpeakerArrString; - - int cachedTotalIns, cachedTotalOuts; - - OwnedArray managedParameters; - AudioProcessorParameter* getParamChecked (int) const noexcept; - - #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING - BigInteger changingParams; - #endif - - AudioProcessorListener* getListenerLocked (int) const noexcept; - void updateSpeakerFormatStrings(); - bool applyBusLayouts (const BusesLayout&); - void audioIOChanged (bool busNumberChanged, bool channelNumChanged); - void getNextBestLayout (const BusesLayout&, BusesLayout&) const; - - template - void processBypassed (AudioBuffer&, MidiBuffer&); - - // This method is no longer used - you can delete it from your AudioProcessor classes. - JUCE_DEPRECATED_WITH_BODY (virtual bool silenceInProducesSilenceOut() const, { return false; }) - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessor) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp b/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp deleted file mode 100644 index e7a3ace6f..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -AudioProcessorEditor::AudioProcessorEditor (AudioProcessor& p) noexcept : processor (p) -{ - initialise(); -} - -AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* p) noexcept : processor (*p) -{ - // the filter must be valid.. - jassert (p != nullptr); - initialise(); -} - -AudioProcessorEditor::~AudioProcessorEditor() -{ - // if this fails, then the wrapper hasn't called editorBeingDeleted() on the - // filter for some reason.. - jassert (processor.getActiveEditor() != this); - removeComponentListener (resizeListener); -} - -void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {} -int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; } - -bool AudioProcessorEditor::supportsHostMIDIControllerPresence (bool) { return true; } -void AudioProcessorEditor::hostMIDIControllerIsAvailable (bool) {} - -void AudioProcessorEditor::initialise() -{ - resizable = false; - - attachConstrainer (&defaultConstrainer); - addComponentListener (resizeListener = new AudioProcessorEditorListener (*this)); -} - -//============================================================================== -void AudioProcessorEditor::setResizable (const bool shouldBeResizable, const bool useBottomRightCornerResizer) -{ - if (shouldBeResizable != resizable) - { - resizable = shouldBeResizable; - - if (! resizable) - { - setConstrainer (&defaultConstrainer); - - if (auto w = getWidth()) - { - if (auto h = getHeight()) - { - defaultConstrainer.setSizeLimits (w, h, w, h); - resized(); - } - } - } - } - - bool shouldHaveCornerResizer = (useBottomRightCornerResizer && shouldBeResizable); - - if (shouldHaveCornerResizer != (resizableCorner != nullptr)) - { - if (shouldHaveCornerResizer) - { - Component::addChildComponent (resizableCorner = new ResizableCornerComponent (this, constrainer)); - resizableCorner->setAlwaysOnTop (true); - } - else - { - resizableCorner = nullptr; - } - } -} - -void AudioProcessorEditor::setResizeLimits (int newMinimumWidth, - int newMinimumHeight, - int newMaximumWidth, - int newMaximumHeight) noexcept -{ - // if you've set up a custom constrainer then these settings won't have any effect.. - jassert (constrainer == &defaultConstrainer || constrainer == nullptr); - - const bool shouldEnableResize = (newMinimumWidth != newMaximumWidth || newMinimumHeight != newMaximumHeight); - const bool shouldHaveCornerResizer = (shouldEnableResize != resizable || resizableCorner != nullptr); - - setResizable (shouldEnableResize, shouldHaveCornerResizer); - - if (constrainer == nullptr) - setConstrainer (&defaultConstrainer); - - defaultConstrainer.setSizeLimits (newMinimumWidth, newMinimumHeight, - newMaximumWidth, newMaximumHeight); - - setBoundsConstrained (getBounds()); -} - -void AudioProcessorEditor::setConstrainer (ComponentBoundsConstrainer* newConstrainer) -{ - if (constrainer != newConstrainer) - { - resizable = true; - attachConstrainer (newConstrainer); - } -} - -void AudioProcessorEditor::attachConstrainer (ComponentBoundsConstrainer* newConstrainer) -{ - if (constrainer != newConstrainer) - { - constrainer = newConstrainer; - updatePeer(); - } -} - -void AudioProcessorEditor::setBoundsConstrained (Rectangle newBounds) -{ - if (constrainer != nullptr) - constrainer->setBoundsForComponent (this, newBounds, false, false, false, false); - else - setBounds (newBounds); -} - -void AudioProcessorEditor::editorResized (bool wasResized) -{ - if (wasResized) - { - bool resizerHidden = false; - - if (auto* peer = getPeer()) - resizerHidden = peer->isFullScreen() || peer->isKioskMode(); - - if (resizableCorner != nullptr) - { - resizableCorner->setVisible (! resizerHidden); - - const int resizerSize = 18; - resizableCorner->setBounds (getWidth() - resizerSize, - getHeight() - resizerSize, - resizerSize, resizerSize); - } - - if (! resizable) - if (auto w = getWidth()) - if (auto h = getHeight()) - defaultConstrainer.setSizeLimits (w, h, w, h); - } -} - -void AudioProcessorEditor::updatePeer() -{ - if (isOnDesktop()) - if (auto* peer = getPeer()) - peer->setConstrainer (constrainer); -} - -void AudioProcessorEditor::setScaleFactor (float newScale) -{ - setTransform (AffineTransform::scale (newScale)); - editorResized (true); -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h b/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h deleted file mode 100644 index 7017bd053..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -class AudioProcessor; -class AudioProcessorEditorListener; - -//============================================================================== -/** - Base class for the component that acts as the GUI for an AudioProcessor. - - Derive your editor component from this class, and create an instance of it - by overriding the AudioProcessor::createEditor() method. - - @see AudioProcessor, GenericAudioProcessorEditor -*/ -class JUCE_API AudioProcessorEditor : public Component -{ -protected: - //============================================================================== - /** Creates an editor for the specified processor. */ - AudioProcessorEditor (AudioProcessor&) noexcept; - - /** Creates an editor for the specified processor. */ - AudioProcessorEditor (AudioProcessor*) noexcept; - -public: - /** Destructor. */ - ~AudioProcessorEditor(); - - - //============================================================================== - /** The AudioProcessor that this editor represents. */ - AudioProcessor& processor; - - /** Returns a pointer to the processor that this editor represents. - This method is here to support legacy code, but it's easier to just use the - AudioProcessorEditor::processor member variable directly to get this object. - */ - AudioProcessor* getAudioProcessor() const noexcept { return &processor; } - - //============================================================================== - /** Used by the setParameterHighlighting() method. */ - struct ParameterControlHighlightInfo - { - int parameterIndex; - bool isHighlighted; - Colour suggestedColour; - }; - - /** Some types of plugin can call this to suggest that the control for a particular - parameter should be highlighted. - Currently only AAX plugins will call this, and implementing it is optional. - */ - virtual void setControlHighlight (ParameterControlHighlightInfo); - - /** Called by certain plug-in wrappers to find out whether a component is used - to control a parameter. - - If the given component represents a particular plugin parameter, then this - method should return the index of that parameter. If not, it should return -1. - Currently only AAX plugins will call this, and implementing it is optional. - */ - virtual int getControlParameterIndex (Component&); - - /** Override this method to indicate if your editor supports the presence or - absence of a host-provided MIDI controller. - - Currently only AUv3 plug-ins compiled for MacOS 10.13 or iOS 11.0 (or later) - support this functionality, and even then the host may choose to ignore this - information. - - The default behaviour is to report support for both cases. - */ - virtual bool supportsHostMIDIControllerPresence (bool hostMIDIControllerIsAvailable); - - /** Called to indicate if a host is providing a MIDI controller when the host - reconfigures its layout. - - Use this as an opportunity to hide or display your own onscreen keyboard or - other input component. - - Currently only AUv3 plug-ins compiled for MacOS 10.13 or iOS 11.0 (or later) - support this functionality. - */ - virtual void hostMIDIControllerIsAvailable (bool controllerIsAvailable); - - /** Can be called by a host to tell the editor that it should use a non-unity - GUI scale. - */ - virtual void setScaleFactor (float newScale); - - //============================================================================== - /** Marks the host's editor window as resizable - - @param allowHostToResize whether the editor's parent window can be resized - by the user or the host. Even if this is false, you - can still resize your window yourself by calling - setBounds (for example, when a user clicks on a button - in your editor to drop out a panel) which will bypass any - resizable/constraints checks. If you are using - your own corner resizer than this will also bypass - any checks. - @param useBottomRightCornerResizer - @see setResizeLimits, isResizable - */ - void setResizable (bool allowHostToResize, bool useBottomRightCornerResizer); - - /** Returns true if the host is allowed to resize editor's parent window - - @see setResizable - */ - bool isResizable() const noexcept { return resizable; } - - /** This sets the maximum and minimum sizes for the window. - - If the window's current size is outside these limits, it will be resized to - make sure it's within them. - - A direct call to setBounds() will bypass any constraint checks, but when the - window is dragged by the user or resized by other indirect means, the constrainer - will limit the numbers involved. - - @see setResizable - */ - void setResizeLimits (int newMinimumWidth, - int newMinimumHeight, - int newMaximumWidth, - int newMaximumHeight) noexcept; - - - /** Returns the bounds constrainer object that this window is using. - You can access this to change its properties. - */ - ComponentBoundsConstrainer* getConstrainer() noexcept { return constrainer; } - - /** Sets the bounds-constrainer object to use for resizing and dragging this window. - - A pointer to the object you pass in will be kept, but it won't be deleted - by this object, so it's the caller's responsibility to manage it. - - If you pass a nullptr, then no contraints will be placed on the positioning of the window. - */ - void setConstrainer (ComponentBoundsConstrainer* newConstrainer); - - /** Calls the window's setBounds method, after first checking these bounds - with the current constrainer. - - @see setConstrainer - */ - void setBoundsConstrained (Rectangle newBounds); - - ScopedPointer resizableCorner; - -private: - //============================================================================== - struct AudioProcessorEditorListener : ComponentListener - { - AudioProcessorEditorListener (AudioProcessorEditor& e) : ed (e) {} - - void componentMovedOrResized (Component&, bool, bool wasResized) override { ed.editorResized (wasResized); } - void componentParentHierarchyChanged (Component&) override { ed.updatePeer(); } - - AudioProcessorEditor& ed; - - JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditorListener) - }; - - //============================================================================== - void initialise(); - void editorResized (bool wasResized); - void updatePeer(); - void attachConstrainer (ComponentBoundsConstrainer*); - - //============================================================================== - ScopedPointer resizeListener; - bool resizable; - ComponentBoundsConstrainer defaultConstrainer; - ComponentBoundsConstrainer* constrainer = {}; - - JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp b/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp deleted file mode 100644 index ef59bc470..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp +++ /dev/null @@ -1,1702 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -const int AudioProcessorGraph::midiChannelIndex = 0x1000; - -//============================================================================== -template struct FloatDoubleUtil {}; -template struct FloatDoubleType {}; - -template -struct FloatAndDoubleComposition -{ - typedef typename FloatDoubleType::Type FloatType; - typedef typename FloatDoubleType::Type DoubleType; - - template - inline typename FloatDoubleType::Type& get() noexcept - { - return FloatDoubleUtil >::get (*this); - } - - FloatType floatVersion; - DoubleType doubleVersion; -}; - -template struct FloatDoubleUtil { static inline typename Impl::FloatType& get (Impl& i) noexcept { return i.floatVersion; } }; -template struct FloatDoubleUtil { static inline typename Impl::DoubleType& get (Impl& i) noexcept { return i.doubleVersion; } }; - -struct FloatPlaceholder; - -template struct FloatDoubleType, FloatingType> { typedef HeapBlock Type; }; -template struct FloatDoubleType, FloatingType> { typedef HeapBlock Type; }; -template struct FloatDoubleType, FloatingType> { typedef AudioBuffer Type; }; -template struct FloatDoubleType*, FloatingType> { typedef AudioBuffer* Type; }; - -//============================================================================== -namespace GraphRenderingOps -{ - -struct AudioGraphRenderingOpBase -{ - AudioGraphRenderingOpBase() noexcept {} - virtual ~AudioGraphRenderingOpBase() {} - - virtual void perform (AudioBuffer& sharedBufferChans, - const OwnedArray& sharedMidiBuffers, - const int numSamples) = 0; - - virtual void perform (AudioBuffer& sharedBufferChans, - const OwnedArray& sharedMidiBuffers, - const int numSamples) = 0; - - JUCE_LEAK_DETECTOR (AudioGraphRenderingOpBase) -}; - -// use CRTP -template -struct AudioGraphRenderingOp : public AudioGraphRenderingOpBase -{ - void perform (AudioBuffer& sharedBufferChans, - const OwnedArray& sharedMidiBuffers, - const int numSamples) override - { - static_cast (this)->perform (sharedBufferChans, sharedMidiBuffers, numSamples); - } - - void perform (AudioBuffer& sharedBufferChans, - const OwnedArray& sharedMidiBuffers, - const int numSamples) override - { - static_cast (this)->perform (sharedBufferChans, sharedMidiBuffers, numSamples); - } -}; - -//============================================================================== -struct ClearChannelOp : public AudioGraphRenderingOp -{ - ClearChannelOp (const int channel) noexcept : channelNum (channel) {} - - template - void perform (AudioBuffer& sharedBufferChans, const OwnedArray&, const int numSamples) - { - sharedBufferChans.clear (channelNum, 0, numSamples); - } - - const int channelNum; - - JUCE_DECLARE_NON_COPYABLE (ClearChannelOp) -}; - -//============================================================================== -struct CopyChannelOp : public AudioGraphRenderingOp -{ - CopyChannelOp (const int srcChan, const int dstChan) noexcept - : srcChannelNum (srcChan), dstChannelNum (dstChan) - {} - - template - void perform (AudioBuffer& sharedBufferChans, const OwnedArray&, const int numSamples) - { - sharedBufferChans.copyFrom (dstChannelNum, 0, sharedBufferChans, srcChannelNum, 0, numSamples); - } - - const int srcChannelNum, dstChannelNum; - - JUCE_DECLARE_NON_COPYABLE (CopyChannelOp) -}; - -//============================================================================== -struct AddChannelOp : public AudioGraphRenderingOp -{ - AddChannelOp (const int srcChan, const int dstChan) noexcept - : srcChannelNum (srcChan), dstChannelNum (dstChan) - {} - - template - void perform (AudioBuffer& sharedBufferChans, const OwnedArray&, const int numSamples) - { - sharedBufferChans.addFrom (dstChannelNum, 0, sharedBufferChans, srcChannelNum, 0, numSamples); - } - - const int srcChannelNum, dstChannelNum; - - JUCE_DECLARE_NON_COPYABLE (AddChannelOp) -}; - -//============================================================================== -struct ClearMidiBufferOp : public AudioGraphRenderingOp -{ - ClearMidiBufferOp (const int buffer) noexcept : bufferNum (buffer) {} - - template - void perform (AudioBuffer&, const OwnedArray& sharedMidiBuffers, const int) - { - sharedMidiBuffers.getUnchecked (bufferNum)->clear(); - } - - const int bufferNum; - - JUCE_DECLARE_NON_COPYABLE (ClearMidiBufferOp) -}; - -//============================================================================== -struct CopyMidiBufferOp : public AudioGraphRenderingOp -{ - CopyMidiBufferOp (const int srcBuffer, const int dstBuffer) noexcept - : srcBufferNum (srcBuffer), dstBufferNum (dstBuffer) - {} - - template - void perform (AudioBuffer&, const OwnedArray& sharedMidiBuffers, const int) - { - *sharedMidiBuffers.getUnchecked (dstBufferNum) = *sharedMidiBuffers.getUnchecked (srcBufferNum); - } - - const int srcBufferNum, dstBufferNum; - - JUCE_DECLARE_NON_COPYABLE (CopyMidiBufferOp) -}; - -//============================================================================== -struct AddMidiBufferOp : public AudioGraphRenderingOp -{ - AddMidiBufferOp (const int srcBuffer, const int dstBuffer) - : srcBufferNum (srcBuffer), dstBufferNum (dstBuffer) - {} - - template - void perform (AudioBuffer&, const OwnedArray& sharedMidiBuffers, const int numSamples) - { - sharedMidiBuffers.getUnchecked (dstBufferNum) - ->addEvents (*sharedMidiBuffers.getUnchecked (srcBufferNum), 0, numSamples, 0); - } - - const int srcBufferNum, dstBufferNum; - - JUCE_DECLARE_NON_COPYABLE (AddMidiBufferOp) -}; - -//============================================================================== -struct DelayChannelOp : public AudioGraphRenderingOp -{ - DelayChannelOp (const int chan, const int delaySize) - : channel (chan), - bufferSize (delaySize + 1), - readIndex (0), writeIndex (delaySize) - { - buffer.floatVersion. calloc ((size_t) bufferSize); - buffer.doubleVersion.calloc ((size_t) bufferSize); - } - - template - void perform (AudioBuffer& sharedBufferChans, const OwnedArray&, const int numSamples) - { - FloatType* data = sharedBufferChans.getWritePointer (channel, 0); - HeapBlock& block = buffer.get(); - - for (int i = numSamples; --i >= 0;) - { - block [writeIndex] = *data; - *data++ = block [readIndex]; - - if (++readIndex >= bufferSize) readIndex = 0; - if (++writeIndex >= bufferSize) writeIndex = 0; - } - } - -private: - FloatAndDoubleComposition > buffer; - const int channel, bufferSize; - int readIndex, writeIndex; - - JUCE_DECLARE_NON_COPYABLE (DelayChannelOp) -}; - -//============================================================================== -struct ProcessBufferOp : public AudioGraphRenderingOp -{ - ProcessBufferOp (const AudioProcessorGraph::Node::Ptr& n, - const Array& audioChannelsUsed, - const int totalNumChans, - const int midiBuffer) - : node (n), - processor (n->getProcessor()), - audioChannelsToUse (audioChannelsUsed), - totalChans (jmax (1, totalNumChans)), - midiBufferToUse (midiBuffer) - { - audioChannels.floatVersion. calloc ((size_t) totalChans); - audioChannels.doubleVersion.calloc ((size_t) totalChans); - - while (audioChannelsToUse.size() < totalChans) - audioChannelsToUse.add (0); - } - - template - void perform (AudioBuffer& sharedBufferChans, const OwnedArray& sharedMidiBuffers, const int numSamples) - { - HeapBlock& channels = audioChannels.get(); - - for (int i = totalChans; --i >= 0;) - channels[i] = sharedBufferChans.getWritePointer (audioChannelsToUse.getUnchecked (i), 0); - - AudioBuffer buffer (channels, totalChans, numSamples); - - if (processor->isSuspended()) - { - buffer.clear(); - } - else - { - ScopedLock lock (processor->getCallbackLock()); - - callProcess (buffer, *sharedMidiBuffers.getUnchecked (midiBufferToUse)); - } - } - - void callProcess (AudioBuffer& buffer, MidiBuffer& midiMessages) - { - processor->processBlock (buffer, midiMessages); - } - - void callProcess (AudioBuffer& buffer, MidiBuffer& midiMessages) - { - if (processor->isUsingDoublePrecision()) - { - processor->processBlock (buffer, midiMessages); - } - else - { - // if the processor is in single precision mode but the graph in double - // precision then we need to convert between buffer formats. Note, that - // this will only happen if the processor does not support double - // precision processing. - tempBuffer.makeCopyOf (buffer, true); - processor->processBlock (tempBuffer, midiMessages); - buffer.makeCopyOf (tempBuffer, true); - } - } - - const AudioProcessorGraph::Node::Ptr node; - AudioProcessor* const processor; - -private: - Array audioChannelsToUse; - FloatAndDoubleComposition > audioChannels; - AudioBuffer tempBuffer; - const int totalChans; - const int midiBufferToUse; - - JUCE_DECLARE_NON_COPYABLE (ProcessBufferOp) -}; - -//============================================================================== -/** Used to calculate the correct sequence of rendering ops needed, based on - the best re-use of shared buffers at each stage. -*/ -struct RenderingOpSequenceCalculator -{ - RenderingOpSequenceCalculator (AudioProcessorGraph& g, - const Array& nodes, - Array& renderingOps) - : graph (g), - orderedNodes (nodes), - totalLatency (0) - { - nodeIds.add ((uint32) zeroNodeID); // first buffer is read-only zeros - channels.add (0); - - midiNodeIds.add ((uint32) zeroNodeID); - - for (int i = 0; i < orderedNodes.size(); ++i) - { - createRenderingOpsForNode (*orderedNodes.getUnchecked(i), renderingOps, i); - markAnyUnusedBuffersAsFree (i); - } - - graph.setLatencySamples (totalLatency); - } - - int getNumBuffersNeeded() const noexcept { return nodeIds.size(); } - int getNumMidiBuffersNeeded() const noexcept { return midiNodeIds.size(); } - -private: - //============================================================================== - AudioProcessorGraph& graph; - const Array& orderedNodes; - Array channels; - Array nodeIds, midiNodeIds; - - enum { freeNodeID = 0xffffffff, zeroNodeID = 0xfffffffe, anonymousNodeID = 0xfffffffd }; - - static bool isNodeBusy (uint32 nodeID) noexcept { return nodeID != freeNodeID && nodeID != zeroNodeID; } - - Array nodeDelayIDs; - Array nodeDelays; - int totalLatency; - - int getNodeDelay (const uint32 nodeID) const { return nodeDelays [nodeDelayIDs.indexOf (nodeID)]; } - - void setNodeDelay (const uint32 nodeID, const int latency) - { - const int index = nodeDelayIDs.indexOf (nodeID); - - if (index >= 0) - { - nodeDelays.set (index, latency); - } - else - { - nodeDelayIDs.add (nodeID); - nodeDelays.add (latency); - } - } - - int getInputLatencyForNode (const uint32 nodeID) const - { - int maxLatency = 0; - - for (int i = graph.getNumConnections(); --i >= 0;) - { - const AudioProcessorGraph::Connection* const c = graph.getConnection (i); - - if (c->destNodeId == nodeID) - maxLatency = jmax (maxLatency, getNodeDelay (c->sourceNodeId)); - } - - return maxLatency; - } - - //============================================================================== - void createRenderingOpsForNode (AudioProcessorGraph::Node& node, - Array& renderingOps, - const int ourRenderingIndex) - { - AudioProcessor& processor = *node.getProcessor(); - const int numIns = processor.getTotalNumInputChannels(); - const int numOuts = processor.getTotalNumOutputChannels(); - const int totalChans = jmax (numIns, numOuts); - - Array audioChannelsToUse; - int midiBufferToUse = -1; - - int maxLatency = getInputLatencyForNode (node.nodeId); - - for (int inputChan = 0; inputChan < numIns; ++inputChan) - { - // get a list of all the inputs to this node - Array sourceNodes; - Array sourceOutputChans; - - for (int i = graph.getNumConnections(); --i >= 0;) - { - const AudioProcessorGraph::Connection* const c = graph.getConnection (i); - - if (c->destNodeId == node.nodeId && c->destChannelIndex == inputChan) - { - sourceNodes.add (c->sourceNodeId); - sourceOutputChans.add (c->sourceChannelIndex); - } - } - - int bufIndex = -1; - - if (sourceNodes.size() == 0) - { - // unconnected input channel - - if (inputChan >= numOuts) - { - bufIndex = getReadOnlyEmptyBuffer(); - jassert (bufIndex >= 0); - } - else - { - bufIndex = getFreeBuffer (false); - renderingOps.add (new ClearChannelOp (bufIndex)); - } - } - else if (sourceNodes.size() == 1) - { - // channel with a straightforward single input.. - const uint32 srcNode = sourceNodes.getUnchecked(0); - const int srcChan = sourceOutputChans.getUnchecked(0); - - bufIndex = getBufferContaining (srcNode, srcChan); - - if (bufIndex < 0) - { - // if not found, this is probably a feedback loop - bufIndex = getReadOnlyEmptyBuffer(); - jassert (bufIndex >= 0); - } - - if (inputChan < numOuts - && isBufferNeededLater (ourRenderingIndex, - inputChan, - srcNode, srcChan)) - { - // can't mess up this channel because it's needed later by another node, so we - // need to use a copy of it.. - const int newFreeBuffer = getFreeBuffer (false); - - renderingOps.add (new CopyChannelOp (bufIndex, newFreeBuffer)); - - bufIndex = newFreeBuffer; - } - - const int nodeDelay = getNodeDelay (srcNode); - - if (nodeDelay < maxLatency) - renderingOps.add (new DelayChannelOp (bufIndex, maxLatency - nodeDelay)); - } - else - { - // channel with a mix of several inputs.. - - // try to find a re-usable channel from our inputs.. - int reusableInputIndex = -1; - - for (int i = 0; i < sourceNodes.size(); ++i) - { - const int sourceBufIndex = getBufferContaining (sourceNodes.getUnchecked(i), - sourceOutputChans.getUnchecked(i)); - - if (sourceBufIndex >= 0 - && ! isBufferNeededLater (ourRenderingIndex, - inputChan, - sourceNodes.getUnchecked(i), - sourceOutputChans.getUnchecked(i))) - { - // we've found one of our input chans that can be re-used.. - reusableInputIndex = i; - bufIndex = sourceBufIndex; - - const int nodeDelay = getNodeDelay (sourceNodes.getUnchecked (i)); - if (nodeDelay < maxLatency) - renderingOps.add (new DelayChannelOp (sourceBufIndex, maxLatency - nodeDelay)); - - break; - } - } - - if (reusableInputIndex < 0) - { - // can't re-use any of our input chans, so get a new one and copy everything into it.. - bufIndex = getFreeBuffer (false); - jassert (bufIndex != 0); - - markBufferAsContaining (bufIndex, static_cast (anonymousNodeID), 0); - - const int srcIndex = getBufferContaining (sourceNodes.getUnchecked (0), - sourceOutputChans.getUnchecked (0)); - if (srcIndex < 0) - { - // if not found, this is probably a feedback loop - renderingOps.add (new ClearChannelOp (bufIndex)); - } - else - { - renderingOps.add (new CopyChannelOp (srcIndex, bufIndex)); - } - - reusableInputIndex = 0; - const int nodeDelay = getNodeDelay (sourceNodes.getFirst()); - - if (nodeDelay < maxLatency) - renderingOps.add (new DelayChannelOp (bufIndex, maxLatency - nodeDelay)); - } - - for (int j = 0; j < sourceNodes.size(); ++j) - { - if (j != reusableInputIndex) - { - int srcIndex = getBufferContaining (sourceNodes.getUnchecked(j), - sourceOutputChans.getUnchecked(j)); - if (srcIndex >= 0) - { - const int nodeDelay = getNodeDelay (sourceNodes.getUnchecked (j)); - - if (nodeDelay < maxLatency) - { - if (! isBufferNeededLater (ourRenderingIndex, inputChan, - sourceNodes.getUnchecked(j), - sourceOutputChans.getUnchecked(j))) - { - renderingOps.add (new DelayChannelOp (srcIndex, maxLatency - nodeDelay)); - } - else // buffer is reused elsewhere, can't be delayed - { - const int bufferToDelay = getFreeBuffer (false); - renderingOps.add (new CopyChannelOp (srcIndex, bufferToDelay)); - renderingOps.add (new DelayChannelOp (bufferToDelay, maxLatency - nodeDelay)); - srcIndex = bufferToDelay; - } - } - - renderingOps.add (new AddChannelOp (srcIndex, bufIndex)); - } - } - } - } - - jassert (bufIndex >= 0); - audioChannelsToUse.add (bufIndex); - - if (inputChan < numOuts) - markBufferAsContaining (bufIndex, node.nodeId, inputChan); - } - - for (int outputChan = numIns; outputChan < numOuts; ++outputChan) - { - const int bufIndex = getFreeBuffer (false); - jassert (bufIndex != 0); - audioChannelsToUse.add (bufIndex); - - markBufferAsContaining (bufIndex, node.nodeId, outputChan); - } - - // Now the same thing for midi.. - Array midiSourceNodes; - - for (int i = graph.getNumConnections(); --i >= 0;) - { - const AudioProcessorGraph::Connection* const c = graph.getConnection (i); - - if (c->destNodeId == node.nodeId && c->destChannelIndex == AudioProcessorGraph::midiChannelIndex) - midiSourceNodes.add (c->sourceNodeId); - } - - if (midiSourceNodes.size() == 0) - { - // No midi inputs.. - midiBufferToUse = getFreeBuffer (true); // need to pick a buffer even if the processor doesn't use midi - - if (processor.acceptsMidi() || processor.producesMidi()) - renderingOps.add (new ClearMidiBufferOp (midiBufferToUse)); - } - else if (midiSourceNodes.size() == 1) - { - // One midi input.. - midiBufferToUse = getBufferContaining (midiSourceNodes.getUnchecked(0), - AudioProcessorGraph::midiChannelIndex); - - if (midiBufferToUse >= 0) - { - if (isBufferNeededLater (ourRenderingIndex, - AudioProcessorGraph::midiChannelIndex, - midiSourceNodes.getUnchecked(0), - AudioProcessorGraph::midiChannelIndex)) - { - // can't mess up this channel because it's needed later by another node, so we - // need to use a copy of it.. - const int newFreeBuffer = getFreeBuffer (true); - renderingOps.add (new CopyMidiBufferOp (midiBufferToUse, newFreeBuffer)); - midiBufferToUse = newFreeBuffer; - } - } - else - { - // probably a feedback loop, so just use an empty one.. - midiBufferToUse = getFreeBuffer (true); // need to pick a buffer even if the processor doesn't use midi - } - } - else - { - // More than one midi input being mixed.. - int reusableInputIndex = -1; - - for (int i = 0; i < midiSourceNodes.size(); ++i) - { - const int sourceBufIndex = getBufferContaining (midiSourceNodes.getUnchecked(i), - AudioProcessorGraph::midiChannelIndex); - - if (sourceBufIndex >= 0 - && ! isBufferNeededLater (ourRenderingIndex, - AudioProcessorGraph::midiChannelIndex, - midiSourceNodes.getUnchecked(i), - AudioProcessorGraph::midiChannelIndex)) - { - // we've found one of our input buffers that can be re-used.. - reusableInputIndex = i; - midiBufferToUse = sourceBufIndex; - break; - } - } - - if (reusableInputIndex < 0) - { - // can't re-use any of our input buffers, so get a new one and copy everything into it.. - midiBufferToUse = getFreeBuffer (true); - jassert (midiBufferToUse >= 0); - - const int srcIndex = getBufferContaining (midiSourceNodes.getUnchecked(0), - AudioProcessorGraph::midiChannelIndex); - if (srcIndex >= 0) - renderingOps.add (new CopyMidiBufferOp (srcIndex, midiBufferToUse)); - else - renderingOps.add (new ClearMidiBufferOp (midiBufferToUse)); - - reusableInputIndex = 0; - } - - for (int j = 0; j < midiSourceNodes.size(); ++j) - { - if (j != reusableInputIndex) - { - const int srcIndex = getBufferContaining (midiSourceNodes.getUnchecked(j), - AudioProcessorGraph::midiChannelIndex); - if (srcIndex >= 0) - renderingOps.add (new AddMidiBufferOp (srcIndex, midiBufferToUse)); - } - } - } - - if (processor.producesMidi()) - markBufferAsContaining (midiBufferToUse, node.nodeId, - AudioProcessorGraph::midiChannelIndex); - - setNodeDelay (node.nodeId, maxLatency + processor.getLatencySamples()); - - if (numOuts == 0) - totalLatency = maxLatency; - - renderingOps.add (new ProcessBufferOp (&node, audioChannelsToUse, - totalChans, midiBufferToUse)); - } - - //============================================================================== - int getFreeBuffer (const bool forMidi) - { - if (forMidi) - { - for (int i = 1; i < midiNodeIds.size(); ++i) - if (midiNodeIds.getUnchecked(i) == freeNodeID) - return i; - - midiNodeIds.add ((uint32) freeNodeID); - return midiNodeIds.size() - 1; - } - else - { - for (int i = 1; i < nodeIds.size(); ++i) - if (nodeIds.getUnchecked(i) == freeNodeID) - return i; - - nodeIds.add ((uint32) freeNodeID); - channels.add (0); - return nodeIds.size() - 1; - } - } - - int getReadOnlyEmptyBuffer() const noexcept - { - return 0; - } - - int getBufferContaining (const uint32 nodeId, const int outputChannel) const noexcept - { - if (outputChannel == AudioProcessorGraph::midiChannelIndex) - { - for (int i = midiNodeIds.size(); --i >= 0;) - if (midiNodeIds.getUnchecked(i) == nodeId) - return i; - } - else - { - for (int i = nodeIds.size(); --i >= 0;) - if (nodeIds.getUnchecked(i) == nodeId - && channels.getUnchecked(i) == outputChannel) - return i; - } - - return -1; - } - - void markAnyUnusedBuffersAsFree (const int stepIndex) - { - for (int i = 0; i < nodeIds.size(); ++i) - { - if (isNodeBusy (nodeIds.getUnchecked(i)) - && ! isBufferNeededLater (stepIndex, -1, - nodeIds.getUnchecked(i), - channels.getUnchecked(i))) - { - nodeIds.set (i, (uint32) freeNodeID); - } - } - - for (int i = 0; i < midiNodeIds.size(); ++i) - { - if (isNodeBusy (midiNodeIds.getUnchecked(i)) - && ! isBufferNeededLater (stepIndex, -1, - midiNodeIds.getUnchecked(i), - AudioProcessorGraph::midiChannelIndex)) - { - midiNodeIds.set (i, (uint32) freeNodeID); - } - } - } - - bool isBufferNeededLater (int stepIndexToSearchFrom, - int inputChannelOfIndexToIgnore, - const uint32 nodeId, - const int outputChanIndex) const - { - while (stepIndexToSearchFrom < orderedNodes.size()) - { - const AudioProcessorGraph::Node* const node = (const AudioProcessorGraph::Node*) orderedNodes.getUnchecked (stepIndexToSearchFrom); - - if (outputChanIndex == AudioProcessorGraph::midiChannelIndex) - { - if (inputChannelOfIndexToIgnore != AudioProcessorGraph::midiChannelIndex - && graph.getConnectionBetween (nodeId, AudioProcessorGraph::midiChannelIndex, - node->nodeId, AudioProcessorGraph::midiChannelIndex) != nullptr) - return true; - } - else - { - for (int i = 0; i < node->getProcessor()->getTotalNumInputChannels(); ++i) - if (i != inputChannelOfIndexToIgnore - && graph.getConnectionBetween (nodeId, outputChanIndex, - node->nodeId, i) != nullptr) - return true; - } - - inputChannelOfIndexToIgnore = -1; - ++stepIndexToSearchFrom; - } - - return false; - } - - void markBufferAsContaining (int bufferNum, uint32 nodeId, int outputIndex) - { - if (outputIndex == AudioProcessorGraph::midiChannelIndex) - { - jassert (bufferNum > 0 && bufferNum < midiNodeIds.size()); - - midiNodeIds.set (bufferNum, nodeId); - } - else - { - jassert (bufferNum >= 0 && bufferNum < nodeIds.size()); - - nodeIds.set (bufferNum, nodeId); - channels.set (bufferNum, outputIndex); - } - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RenderingOpSequenceCalculator) -}; - -//============================================================================== -// Holds a fast lookup table for checking which nodes are inputs to others. -class ConnectionLookupTable -{ -public: - explicit ConnectionLookupTable (const OwnedArray& connections) - { - for (int i = 0; i < connections.size(); ++i) - { - const AudioProcessorGraph::Connection* const c = connections.getUnchecked(i); - - int index; - Entry* entry = findEntry (c->destNodeId, index); - - if (entry == nullptr) - { - entry = new Entry (c->destNodeId); - entries.insert (index, entry); - } - - entry->srcNodes.add (c->sourceNodeId); - } - } - - bool isAnInputTo (const uint32 possibleInputId, - const uint32 possibleDestinationId) const noexcept - { - return isAnInputToRecursive (possibleInputId, possibleDestinationId, entries.size()); - } - -private: - //============================================================================== - struct Entry - { - explicit Entry (const uint32 destNodeId_) noexcept : destNodeId (destNodeId_) {} - - const uint32 destNodeId; - SortedSet srcNodes; - - JUCE_DECLARE_NON_COPYABLE (Entry) - }; - - OwnedArray entries; - - bool isAnInputToRecursive (const uint32 possibleInputId, - const uint32 possibleDestinationId, - int recursionCheck) const noexcept - { - int index; - - if (const Entry* const entry = findEntry (possibleDestinationId, index)) - { - const SortedSet& srcNodes = entry->srcNodes; - - if (srcNodes.contains (possibleInputId)) - return true; - - if (--recursionCheck >= 0) - { - for (int i = 0; i < srcNodes.size(); ++i) - if (isAnInputToRecursive (possibleInputId, srcNodes.getUnchecked(i), recursionCheck)) - return true; - } - } - - return false; - } - - Entry* findEntry (const uint32 destNodeId, int& insertIndex) const noexcept - { - Entry* result = nullptr; - - int start = 0; - int end = entries.size(); - - for (;;) - { - if (start >= end) - { - break; - } - else if (destNodeId == entries.getUnchecked (start)->destNodeId) - { - result = entries.getUnchecked (start); - break; - } - else - { - const int halfway = (start + end) / 2; - - if (halfway == start) - { - if (destNodeId >= entries.getUnchecked (halfway)->destNodeId) - ++start; - - break; - } - else if (destNodeId >= entries.getUnchecked (halfway)->destNodeId) - start = halfway; - else - end = halfway; - } - } - - insertIndex = start; - return result; - } - - JUCE_DECLARE_NON_COPYABLE (ConnectionLookupTable) -}; - -//============================================================================== -struct ConnectionSorter -{ - static int compareElements (const AudioProcessorGraph::Connection* const first, - const AudioProcessorGraph::Connection* const second) noexcept - { - if (first->sourceNodeId < second->sourceNodeId) return -1; - if (first->sourceNodeId > second->sourceNodeId) return 1; - if (first->destNodeId < second->destNodeId) return -1; - if (first->destNodeId > second->destNodeId) return 1; - if (first->sourceChannelIndex < second->sourceChannelIndex) return -1; - if (first->sourceChannelIndex > second->sourceChannelIndex) return 1; - if (first->destChannelIndex < second->destChannelIndex) return -1; - if (first->destChannelIndex > second->destChannelIndex) return 1; - - return 0; - } -}; - -} - -//============================================================================== -AudioProcessorGraph::Connection::Connection (const uint32 sourceID, const int sourceChannel, - const uint32 destID, const int destChannel) noexcept - : sourceNodeId (sourceID), sourceChannelIndex (sourceChannel), - destNodeId (destID), destChannelIndex (destChannel) -{ -} - -//============================================================================== -AudioProcessorGraph::Node::Node (const uint32 nodeID, AudioProcessor* const p) noexcept - : nodeId (nodeID), processor (p), isPrepared (false) -{ - jassert (processor != nullptr); -} - -void AudioProcessorGraph::Node::prepare (const double newSampleRate, const int newBlockSize, - AudioProcessorGraph* const graph, ProcessingPrecision precision) -{ - if (! isPrepared) - { - isPrepared = true; - setParentGraph (graph); - - // try to align the precision of the processor and the graph - processor->setProcessingPrecision (processor->supportsDoublePrecisionProcessing() ? precision - : singlePrecision); - - processor->setRateAndBufferSizeDetails (newSampleRate, newBlockSize); - processor->prepareToPlay (newSampleRate, newBlockSize); - } -} - -void AudioProcessorGraph::Node::unprepare() -{ - if (isPrepared) - { - isPrepared = false; - processor->releaseResources(); - } -} - -void AudioProcessorGraph::Node::setParentGraph (AudioProcessorGraph* const graph) const -{ - if (AudioProcessorGraph::AudioGraphIOProcessor* const ioProc - = dynamic_cast (processor.get())) - ioProc->setParentGraph (graph); -} - -//============================================================================== -struct AudioProcessorGraph::AudioProcessorGraphBufferHelpers -{ - AudioProcessorGraphBufferHelpers() - { - currentAudioInputBuffer.floatVersion = nullptr; - currentAudioInputBuffer.doubleVersion = nullptr; - } - - void setRenderingBufferSize (int newNumChannels, int newNumSamples) - { - renderingBuffers.floatVersion. setSize (newNumChannels, newNumSamples); - renderingBuffers.doubleVersion.setSize (newNumChannels, newNumSamples); - - renderingBuffers.floatVersion. clear(); - renderingBuffers.doubleVersion.clear(); - } - - void release() - { - renderingBuffers.floatVersion. setSize (1, 1); - renderingBuffers.doubleVersion.setSize (1, 1); - - currentAudioInputBuffer.floatVersion = nullptr; - currentAudioInputBuffer.doubleVersion = nullptr; - - currentAudioOutputBuffer.floatVersion. setSize (1, 1); - currentAudioOutputBuffer.doubleVersion.setSize (1, 1); - } - - void prepareInOutBuffers(int newNumChannels, int newNumSamples) - { - currentAudioInputBuffer.floatVersion = nullptr; - currentAudioInputBuffer.doubleVersion = nullptr; - - currentAudioOutputBuffer.floatVersion. setSize (newNumChannels, newNumSamples); - currentAudioOutputBuffer.doubleVersion.setSize (newNumChannels, newNumSamples); - } - - FloatAndDoubleComposition > renderingBuffers; - FloatAndDoubleComposition*> currentAudioInputBuffer; - FloatAndDoubleComposition > currentAudioOutputBuffer; -}; - -//============================================================================== -AudioProcessorGraph::AudioProcessorGraph() - : lastNodeId (0), audioBuffers (new AudioProcessorGraphBufferHelpers), - currentMidiInputBuffer (nullptr), isPrepared (false) -{ -} - -AudioProcessorGraph::~AudioProcessorGraph() -{ - clearRenderingSequence(); - clear(); -} - -const String AudioProcessorGraph::getName() const -{ - return "Audio Graph"; -} - -//============================================================================== -void AudioProcessorGraph::clear() -{ - nodes.clear(); - connections.clear(); - triggerAsyncUpdate(); -} - -AudioProcessorGraph::Node* AudioProcessorGraph::getNodeForId (const uint32 nodeId) const -{ - for (int i = nodes.size(); --i >= 0;) - if (nodes.getUnchecked(i)->nodeId == nodeId) - return nodes.getUnchecked(i); - - return nullptr; -} - -AudioProcessorGraph::Node* AudioProcessorGraph::addNode (AudioProcessor* const newProcessor, uint32 nodeId) -{ - if (newProcessor == nullptr || newProcessor == this) - { - jassertfalse; - return nullptr; - } - - for (int i = nodes.size(); --i >= 0;) - { - if (nodes.getUnchecked(i)->getProcessor() == newProcessor) - { - jassertfalse; // Cannot add the same object to the graph twice! - return nullptr; - } - } - - if (nodeId == 0) - { - nodeId = ++lastNodeId; - } - else - { - // you can't add a node with an id that already exists in the graph.. - jassert (getNodeForId (nodeId) == nullptr); - removeNode (nodeId); - - if (nodeId > lastNodeId) - lastNodeId = nodeId; - } - - newProcessor->setPlayHead (getPlayHead()); - - Node* const n = new Node (nodeId, newProcessor); - nodes.add (n); - - if (isPrepared) - triggerAsyncUpdate(); - - n->setParentGraph (this); - return n; -} - -bool AudioProcessorGraph::removeNode (const uint32 nodeId) -{ - disconnectNode (nodeId); - - for (int i = nodes.size(); --i >= 0;) - { - if (nodes.getUnchecked(i)->nodeId == nodeId) - { - nodes.remove (i); - - if (isPrepared) - triggerAsyncUpdate(); - - return true; - } - } - - return false; -} - -bool AudioProcessorGraph::removeNode (Node* node) -{ - if (node != nullptr) - return removeNode (node->nodeId); - - jassertfalse; - return false; -} - -//============================================================================== -const AudioProcessorGraph::Connection* AudioProcessorGraph::getConnectionBetween (const uint32 sourceNodeId, - const int sourceChannelIndex, - const uint32 destNodeId, - const int destChannelIndex) const -{ - const Connection c (sourceNodeId, sourceChannelIndex, destNodeId, destChannelIndex); - GraphRenderingOps::ConnectionSorter sorter; - return connections [connections.indexOfSorted (sorter, &c)]; -} - -bool AudioProcessorGraph::isConnected (const uint32 possibleSourceNodeId, - const uint32 possibleDestNodeId) const -{ - for (int i = connections.size(); --i >= 0;) - { - const Connection* const c = connections.getUnchecked(i); - - if (c->sourceNodeId == possibleSourceNodeId - && c->destNodeId == possibleDestNodeId) - { - return true; - } - } - - return false; -} - -bool AudioProcessorGraph::canConnect (const uint32 sourceNodeId, - const int sourceChannelIndex, - const uint32 destNodeId, - const int destChannelIndex) const -{ - if (sourceChannelIndex < 0 - || destChannelIndex < 0 - || sourceNodeId == destNodeId - || (destChannelIndex == midiChannelIndex) != (sourceChannelIndex == midiChannelIndex)) - return false; - - const Node* const source = getNodeForId (sourceNodeId); - - if (source == nullptr - || (sourceChannelIndex != midiChannelIndex && sourceChannelIndex >= source->processor->getTotalNumOutputChannels()) - || (sourceChannelIndex == midiChannelIndex && ! source->processor->producesMidi())) - return false; - - const Node* const dest = getNodeForId (destNodeId); - - if (dest == nullptr - || (destChannelIndex != midiChannelIndex && destChannelIndex >= dest->processor->getTotalNumInputChannels()) - || (destChannelIndex == midiChannelIndex && ! dest->processor->acceptsMidi())) - return false; - - return getConnectionBetween (sourceNodeId, sourceChannelIndex, - destNodeId, destChannelIndex) == nullptr; -} - -bool AudioProcessorGraph::addConnection (const uint32 sourceNodeId, - const int sourceChannelIndex, - const uint32 destNodeId, - const int destChannelIndex) -{ - if (! canConnect (sourceNodeId, sourceChannelIndex, destNodeId, destChannelIndex)) - return false; - - GraphRenderingOps::ConnectionSorter sorter; - connections.addSorted (sorter, new Connection (sourceNodeId, sourceChannelIndex, - destNodeId, destChannelIndex)); - - if (isPrepared) - triggerAsyncUpdate(); - - return true; -} - -void AudioProcessorGraph::removeConnection (const int index) -{ - connections.remove (index); - - if (isPrepared) - triggerAsyncUpdate(); -} - -bool AudioProcessorGraph::removeConnection (const uint32 sourceNodeId, const int sourceChannelIndex, - const uint32 destNodeId, const int destChannelIndex) -{ - bool doneAnything = false; - - for (int i = connections.size(); --i >= 0;) - { - const Connection* const c = connections.getUnchecked(i); - - if (c->sourceNodeId == sourceNodeId - && c->destNodeId == destNodeId - && c->sourceChannelIndex == sourceChannelIndex - && c->destChannelIndex == destChannelIndex) - { - removeConnection (i); - doneAnything = true; - } - } - - return doneAnything; -} - -bool AudioProcessorGraph::disconnectNode (const uint32 nodeId) -{ - bool doneAnything = false; - - for (int i = connections.size(); --i >= 0;) - { - const Connection* const c = connections.getUnchecked(i); - - if (c->sourceNodeId == nodeId || c->destNodeId == nodeId) - { - removeConnection (i); - doneAnything = true; - } - } - - return doneAnything; -} - -bool AudioProcessorGraph::isConnectionLegal (const Connection* const c) const -{ - jassert (c != nullptr); - - const Node* const source = getNodeForId (c->sourceNodeId); - const Node* const dest = getNodeForId (c->destNodeId); - - return source != nullptr - && dest != nullptr - && (c->sourceChannelIndex != midiChannelIndex ? isPositiveAndBelow (c->sourceChannelIndex, source->processor->getTotalNumOutputChannels()) - : source->processor->producesMidi()) - && (c->destChannelIndex != midiChannelIndex ? isPositiveAndBelow (c->destChannelIndex, dest->processor->getTotalNumInputChannels()) - : dest->processor->acceptsMidi()); -} - -bool AudioProcessorGraph::removeIllegalConnections() -{ - bool doneAnything = false; - - for (int i = connections.size(); --i >= 0;) - { - if (! isConnectionLegal (connections.getUnchecked(i))) - { - removeConnection (i); - doneAnything = true; - } - } - - return doneAnything; -} - -//============================================================================== -static void deleteRenderOpArray (Array& ops) -{ - for (int i = ops.size(); --i >= 0;) - delete static_cast (ops.getUnchecked(i)); -} - -void AudioProcessorGraph::clearRenderingSequence() -{ - Array oldOps; - - { - const ScopedLock sl (getCallbackLock()); - renderingOps.swapWith (oldOps); - } - - deleteRenderOpArray (oldOps); -} - -bool AudioProcessorGraph::isAnInputTo (const uint32 possibleInputId, - const uint32 possibleDestinationId, - const int recursionCheck) const -{ - if (recursionCheck > 0) - { - for (int i = connections.size(); --i >= 0;) - { - const AudioProcessorGraph::Connection* const c = connections.getUnchecked (i); - - if (c->destNodeId == possibleDestinationId - && (c->sourceNodeId == possibleInputId - || isAnInputTo (possibleInputId, c->sourceNodeId, recursionCheck - 1))) - return true; - } - } - - return false; -} - -void AudioProcessorGraph::buildRenderingSequence() -{ - Array newRenderingOps; - int numRenderingBuffersNeeded = 2; - int numMidiBuffersNeeded = 1; - - { - MessageManagerLock mml; - - Array orderedNodes; - - { - const GraphRenderingOps::ConnectionLookupTable table (connections); - - for (int i = 0; i < nodes.size(); ++i) - { - Node* const node = nodes.getUnchecked(i); - - node->prepare (getSampleRate(), getBlockSize(), this, getProcessingPrecision()); - - int j = 0; - for (; j < orderedNodes.size(); ++j) - if (table.isAnInputTo (node->nodeId, ((Node*) orderedNodes.getUnchecked(j))->nodeId)) - break; - - orderedNodes.insert (j, node); - } - } - - GraphRenderingOps::RenderingOpSequenceCalculator calculator (*this, orderedNodes, newRenderingOps); - - numRenderingBuffersNeeded = calculator.getNumBuffersNeeded(); - numMidiBuffersNeeded = calculator.getNumMidiBuffersNeeded(); - } - - { - // swap over to the new rendering sequence.. - const ScopedLock sl (getCallbackLock()); - - audioBuffers->setRenderingBufferSize (numRenderingBuffersNeeded, getBlockSize()); - - for (int i = midiBuffers.size(); --i >= 0;) - midiBuffers.getUnchecked(i)->clear(); - - while (midiBuffers.size() < numMidiBuffersNeeded) - midiBuffers.add (new MidiBuffer()); - - renderingOps.swapWith (newRenderingOps); - } - - // delete the old ones.. - deleteRenderOpArray (newRenderingOps); -} - -void AudioProcessorGraph::handleAsyncUpdate() -{ - buildRenderingSequence(); -} - -//============================================================================== -void AudioProcessorGraph::prepareToPlay (double /*sampleRate*/, int estimatedSamplesPerBlock) -{ - audioBuffers->prepareInOutBuffers (jmax (1, getTotalNumOutputChannels()), estimatedSamplesPerBlock); - - currentMidiInputBuffer = nullptr; - currentMidiOutputBuffer.clear(); - - clearRenderingSequence(); - buildRenderingSequence(); - - isPrepared = true; -} - -bool AudioProcessorGraph::supportsDoublePrecisionProcessing() const -{ - return true; -} - -void AudioProcessorGraph::releaseResources() -{ - isPrepared = false; - - for (int i = 0; i < nodes.size(); ++i) - nodes.getUnchecked(i)->unprepare(); - - audioBuffers->release(); - midiBuffers.clear(); - - currentMidiInputBuffer = nullptr; - currentMidiOutputBuffer.clear(); -} - -void AudioProcessorGraph::reset() -{ - const ScopedLock sl (getCallbackLock()); - - for (int i = 0; i < nodes.size(); ++i) - nodes.getUnchecked(i)->getProcessor()->reset(); -} - -void AudioProcessorGraph::setNonRealtime (bool isProcessingNonRealtime) noexcept -{ - const ScopedLock sl (getCallbackLock()); - - AudioProcessor::setNonRealtime (isProcessingNonRealtime); - - for (int i = 0; i < nodes.size(); ++i) - nodes.getUnchecked(i)->getProcessor()->setNonRealtime (isProcessingNonRealtime); -} - -void AudioProcessorGraph::setPlayHead (AudioPlayHead* audioPlayHead) -{ - const ScopedLock sl (getCallbackLock()); - - AudioProcessor::setPlayHead (audioPlayHead); - - for (int i = 0; i < nodes.size(); ++i) - nodes.getUnchecked(i)->getProcessor()->setPlayHead (audioPlayHead); -} - -template -void AudioProcessorGraph::processAudio (AudioBuffer& buffer, MidiBuffer& midiMessages) -{ - AudioBuffer& renderingBuffers = audioBuffers->renderingBuffers.get(); - AudioBuffer*& currentAudioInputBuffer = audioBuffers->currentAudioInputBuffer.get(); - AudioBuffer& currentAudioOutputBuffer = audioBuffers->currentAudioOutputBuffer.get(); - - const int numSamples = buffer.getNumSamples(); - jassert (numSamples <= getBlockSize()); - - currentAudioInputBuffer = &buffer; - currentAudioOutputBuffer.setSize (jmax (1, buffer.getNumChannels()), numSamples); - currentAudioOutputBuffer.clear(); - currentMidiInputBuffer = &midiMessages; - currentMidiOutputBuffer.clear(); - - for (int i = 0; i < renderingOps.size(); ++i) - { - GraphRenderingOps::AudioGraphRenderingOpBase* const op - = (GraphRenderingOps::AudioGraphRenderingOpBase*) renderingOps.getUnchecked(i); - - op->perform (renderingBuffers, midiBuffers, numSamples); - } - - for (int i = 0; i < buffer.getNumChannels(); ++i) - buffer.copyFrom (i, 0, currentAudioOutputBuffer, i, 0, numSamples); - - midiMessages.clear(); - midiMessages.addEvents (currentMidiOutputBuffer, 0, buffer.getNumSamples(), 0); -} - -template -void AudioProcessorGraph::sliceAndProcess (AudioBuffer& buffer, MidiBuffer& midiMessages) -{ - auto n = buffer.getNumSamples(); - auto ch = buffer.getNumChannels(); - auto max = 0; - - for (auto pos = 0; pos < n; pos += max) - { - max = jmin (n - pos, getBlockSize()); - - AudioBuffer audioSlice (buffer.getArrayOfWritePointers(), ch, pos, max); - MidiBuffer midiSlice; - - midiSlice.addEvents (midiMessages, pos, max, 0); - processAudio (audioSlice, midiSlice); - } -} - -double AudioProcessorGraph::getTailLengthSeconds() const { return 0; } -bool AudioProcessorGraph::acceptsMidi() const { return true; } -bool AudioProcessorGraph::producesMidi() const { return true; } -void AudioProcessorGraph::getStateInformation (juce::MemoryBlock&) {} -void AudioProcessorGraph::setStateInformation (const void*, int) {} - -void AudioProcessorGraph::processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) -{ - sliceAndProcess (buffer, midiMessages); -} - -void AudioProcessorGraph::processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) -{ - sliceAndProcess (buffer, midiMessages); -} - -// explicit template instantiation -template void AudioProcessorGraph::processAudio ( AudioBuffer& buffer, - MidiBuffer& midiMessages); -template void AudioProcessorGraph::processAudio (AudioBuffer& buffer, - MidiBuffer& midiMessages); - -//============================================================================== -AudioProcessorGraph::AudioGraphIOProcessor::AudioGraphIOProcessor (const IODeviceType deviceType) - : type (deviceType), graph (nullptr) -{ -} - -AudioProcessorGraph::AudioGraphIOProcessor::~AudioGraphIOProcessor() -{ -} - -const String AudioProcessorGraph::AudioGraphIOProcessor::getName() const -{ - switch (type) - { - case audioOutputNode: return "Audio Output"; - case audioInputNode: return "Audio Input"; - case midiOutputNode: return "Midi Output"; - case midiInputNode: return "Midi Input"; - default: break; - } - - return {}; -} - -void AudioProcessorGraph::AudioGraphIOProcessor::fillInPluginDescription (PluginDescription& d) const -{ - d.name = getName(); - d.uid = d.name.hashCode(); - d.category = "I/O devices"; - d.pluginFormatName = "Internal"; - d.manufacturerName = "ROLI Ltd."; - d.version = "1.0"; - d.isInstrument = false; - - d.numInputChannels = getTotalNumInputChannels(); - if (type == audioOutputNode && graph != nullptr) - d.numInputChannels = graph->getTotalNumInputChannels(); - - d.numOutputChannels = getTotalNumOutputChannels(); - if (type == audioInputNode && graph != nullptr) - d.numOutputChannels = graph->getTotalNumOutputChannels(); -} - -void AudioProcessorGraph::AudioGraphIOProcessor::prepareToPlay (double, int) -{ - jassert (graph != nullptr); -} - -void AudioProcessorGraph::AudioGraphIOProcessor::releaseResources() -{ -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::supportsDoublePrecisionProcessing() const -{ - return true; -} - -template -void AudioProcessorGraph::AudioGraphIOProcessor::processAudio (AudioBuffer& buffer, - MidiBuffer& midiMessages) -{ - AudioBuffer*& currentAudioInputBuffer = - graph->audioBuffers->currentAudioInputBuffer.get(); - - AudioBuffer& currentAudioOutputBuffer = - graph->audioBuffers->currentAudioOutputBuffer.get(); - - jassert (graph != nullptr); - - switch (type) - { - case audioOutputNode: - { - for (int i = jmin (currentAudioOutputBuffer.getNumChannels(), - buffer.getNumChannels()); --i >= 0;) - { - currentAudioOutputBuffer.addFrom (i, 0, buffer, i, 0, buffer.getNumSamples()); - } - - break; - } - - case audioInputNode: - { - for (int i = jmin (currentAudioInputBuffer->getNumChannels(), - buffer.getNumChannels()); --i >= 0;) - { - buffer.copyFrom (i, 0, *currentAudioInputBuffer, i, 0, buffer.getNumSamples()); - } - - break; - } - - case midiOutputNode: - graph->currentMidiOutputBuffer.addEvents (midiMessages, 0, buffer.getNumSamples(), 0); - break; - - case midiInputNode: - midiMessages.addEvents (*graph->currentMidiInputBuffer, 0, buffer.getNumSamples(), 0); - break; - - default: - break; - } -} - -void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioBuffer& buffer, - MidiBuffer& midiMessages) -{ - processAudio (buffer, midiMessages); -} - -void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioBuffer& buffer, - MidiBuffer& midiMessages) -{ - processAudio (buffer, midiMessages); -} - -double AudioProcessorGraph::AudioGraphIOProcessor::getTailLengthSeconds() const -{ - return 0; -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::acceptsMidi() const -{ - return type == midiOutputNode; -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::producesMidi() const -{ - return type == midiInputNode; -} - -bool AudioProcessorGraph::AudioGraphIOProcessor::isInput() const noexcept { return type == audioInputNode || type == midiInputNode; } -bool AudioProcessorGraph::AudioGraphIOProcessor::isOutput() const noexcept { return type == audioOutputNode || type == midiOutputNode; } - -#if ! JUCE_AUDIOPROCESSOR_NO_GUI -bool AudioProcessorGraph::AudioGraphIOProcessor::hasEditor() const { return false; } -AudioProcessorEditor* AudioProcessorGraph::AudioGraphIOProcessor::createEditor() { return nullptr; } -#endif - -int AudioProcessorGraph::AudioGraphIOProcessor::getNumPrograms() { return 0; } -int AudioProcessorGraph::AudioGraphIOProcessor::getCurrentProgram() { return 0; } -void AudioProcessorGraph::AudioGraphIOProcessor::setCurrentProgram (int) { } - -const String AudioProcessorGraph::AudioGraphIOProcessor::getProgramName (int) { return {}; } -void AudioProcessorGraph::AudioGraphIOProcessor::changeProgramName (int, const String&) {} - -void AudioProcessorGraph::AudioGraphIOProcessor::getStateInformation (juce::MemoryBlock&) {} -void AudioProcessorGraph::AudioGraphIOProcessor::setStateInformation (const void*, int) {} - -void AudioProcessorGraph::AudioGraphIOProcessor::setParentGraph (AudioProcessorGraph* const newGraph) -{ - graph = newGraph; - - if (graph != nullptr) - { - setPlayConfigDetails (type == audioOutputNode ? graph->getTotalNumOutputChannels() : 0, - type == audioInputNode ? graph->getTotalNumInputChannels() : 0, - getSampleRate(), - getBlockSize()); - - updateHostDisplay(); - } -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h b/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h deleted file mode 100644 index bfd21d118..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h +++ /dev/null @@ -1,411 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - A type of AudioProcessor which plays back a graph of other AudioProcessors. - - Use one of these objects if you want to wire-up a set of AudioProcessors - and play back the result. - - Processors can be added to the graph as "nodes" using addNode(), and once - added, you can connect any of their input or output channels to other - nodes using addConnection(). - - To play back a graph through an audio device, you might want to use an - AudioProcessorPlayer object. -*/ -class JUCE_API AudioProcessorGraph : public AudioProcessor, - private AsyncUpdater -{ -public: - //============================================================================== - /** Creates an empty graph. */ - AudioProcessorGraph(); - - /** Destructor. - Any processor objects that have been added to the graph will also be deleted. - */ - ~AudioProcessorGraph(); - - //============================================================================== - /** Represents one of the nodes, or processors, in an AudioProcessorGraph. - - To create a node, call AudioProcessorGraph::addNode(). - */ - class JUCE_API Node : public ReferenceCountedObject - { - public: - //============================================================================== - /** The ID number assigned to this node. - This is assigned by the graph that owns it, and can't be changed. - */ - const uint32 nodeId; - - /** The actual processor object that this node represents. */ - AudioProcessor* getProcessor() const noexcept { return processor; } - - /** A set of user-definable properties that are associated with this node. - - This can be used to attach values to the node for whatever purpose seems - useful. For example, you might store an x and y position if your application - is displaying the nodes on-screen. - */ - NamedValueSet properties; - - //============================================================================== - /** A convenient typedef for referring to a pointer to a node object. */ - typedef ReferenceCountedObjectPtr Ptr; - - private: - //============================================================================== - friend class AudioProcessorGraph; - - const ScopedPointer processor; - bool isPrepared; - - Node (uint32 nodeId, AudioProcessor*) noexcept; - - void setParentGraph (AudioProcessorGraph*) const; - void prepare (double newSampleRate, int newBlockSize, AudioProcessorGraph*, ProcessingPrecision); - void unprepare(); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Node) - }; - - //============================================================================== - /** Represents a connection between two channels of two nodes in an AudioProcessorGraph. - - To create a connection, use AudioProcessorGraph::addConnection(). - */ - struct JUCE_API Connection - { - //============================================================================== - Connection (uint32 sourceNodeId, int sourceChannelIndex, - uint32 destNodeId, int destChannelIndex) noexcept; - - //============================================================================== - /** The ID number of the node which is the input source for this connection. - @see AudioProcessorGraph::getNodeForId - */ - uint32 sourceNodeId; - - /** The index of the output channel of the source node from which this - connection takes its data. - - If this value is the special number AudioProcessorGraph::midiChannelIndex, then - it is referring to the source node's midi output. Otherwise, it is the zero-based - index of an audio output channel in the source node. - */ - int sourceChannelIndex; - - /** The ID number of the node which is the destination for this connection. - @see AudioProcessorGraph::getNodeForId - */ - uint32 destNodeId; - - /** The index of the input channel of the destination node to which this - connection delivers its data. - - If this value is the special number AudioProcessorGraph::midiChannelIndex, then - it is referring to the destination node's midi input. Otherwise, it is the zero-based - index of an audio input channel in the destination node. - */ - int destChannelIndex; - - private: - //============================================================================== - JUCE_LEAK_DETECTOR (Connection) - }; - - //============================================================================== - /** Deletes all nodes and connections from this graph. - Any processor objects in the graph will be deleted. - */ - void clear(); - - /** Returns the number of nodes in the graph. */ - int getNumNodes() const noexcept { return nodes.size(); } - - /** Returns a pointer to one of the nodes in the graph. - This will return nullptr if the index is out of range. - @see getNodeForId - */ - Node* getNode (const int index) const noexcept { return nodes [index]; } - - /** Searches the graph for a node with the given ID number and returns it. - If no such node was found, this returns nullptr. - @see getNode - */ - Node* getNodeForId (const uint32 nodeId) const; - - /** Adds a node to the graph. - - This creates a new node in the graph, for the specified processor. Once you have - added a processor to the graph, the graph owns it and will delete it later when - it is no longer needed. - - The optional nodeId parameter lets you specify an ID to use for the node, but - if the value is already in use, this new node will overwrite the old one. - - If this succeeds, it returns a pointer to the newly-created node. - */ - Node* addNode (AudioProcessor* newProcessor, uint32 nodeId = 0); - - /** Deletes a node within the graph which has the specified ID. - This will also delete any connections that are attached to this node. - */ - bool removeNode (uint32 nodeId); - - /** Deletes a node within the graph. - This will also delete any connections that are attached to this node. - */ - bool removeNode (Node* node); - - //============================================================================== - /** Returns the number of connections in the graph. */ - int getNumConnections() const { return connections.size(); } - - /** Returns a pointer to one of the connections in the graph. */ - const Connection* getConnection (int index) const { return connections [index]; } - - /** Searches for a connection between some specified channels. - If no such connection is found, this returns nullptr. - */ - const Connection* getConnectionBetween (uint32 sourceNodeId, - int sourceChannelIndex, - uint32 destNodeId, - int destChannelIndex) const; - - /** Returns true if there is a connection between any of the channels of - two specified nodes. - */ - bool isConnected (uint32 possibleSourceNodeId, - uint32 possibleDestNodeId) const; - - /** Returns true if it would be legal to connect the specified points. */ - bool canConnect (uint32 sourceNodeId, int sourceChannelIndex, - uint32 destNodeId, int destChannelIndex) const; - - /** Attempts to connect two specified channels of two nodes. - - If this isn't allowed (e.g. because you're trying to connect a midi channel - to an audio one or other such nonsense), then it'll return false. - */ - bool addConnection (uint32 sourceNodeId, int sourceChannelIndex, - uint32 destNodeId, int destChannelIndex); - - /** Deletes the connection with the specified index. */ - void removeConnection (int index); - - /** Deletes any connection between two specified points. - Returns true if a connection was actually deleted. - */ - bool removeConnection (uint32 sourceNodeId, int sourceChannelIndex, - uint32 destNodeId, int destChannelIndex); - - /** Removes all connections from the specified node. */ - bool disconnectNode (uint32 nodeId); - - /** Returns true if the given connection's channel numbers map on to valid - channels at each end. - Even if a connection is valid when created, its status could change if - a node changes its channel config. - */ - bool isConnectionLegal (const Connection* connection) const; - - /** Performs a sanity checks of all the connections. - - This might be useful if some of the processors are doing things like changing - their channel counts, which could render some connections obsolete. - */ - bool removeIllegalConnections(); - - //============================================================================== - /** A special number that represents the midi channel of a node. - - This is used as a channel index value if you want to refer to the midi input - or output instead of an audio channel. - */ - static const int midiChannelIndex; - - - //============================================================================== - /** A special type of AudioProcessor that can live inside an AudioProcessorGraph - in order to use the audio that comes into and out of the graph itself. - - If you create an AudioGraphIOProcessor in "input" mode, it will act as a - node in the graph which delivers the audio that is coming into the parent - graph. This allows you to stream the data to other nodes and process the - incoming audio. - - Likewise, one of these in "output" mode can be sent data which it will add to - the sum of data being sent to the graph's output. - - @see AudioProcessorGraph - */ - class JUCE_API AudioGraphIOProcessor : public AudioPluginInstance - { - public: - /** Specifies the mode in which this processor will operate. - */ - enum IODeviceType - { - audioInputNode, /**< In this mode, the processor has output channels - representing all the audio input channels that are - coming into its parent audio graph. */ - audioOutputNode, /**< In this mode, the processor has input channels - representing all the audio output channels that are - going out of its parent audio graph. */ - midiInputNode, /**< In this mode, the processor has a midi output which - delivers the same midi data that is arriving at its - parent graph. */ - midiOutputNode /**< In this mode, the processor has a midi input and - any data sent to it will be passed out of the parent - graph. */ - }; - - //============================================================================== - /** Returns the mode of this processor. */ - IODeviceType getType() const noexcept { return type; } - - /** Returns the parent graph to which this processor belongs, or nullptr if it - hasn't yet been added to one. */ - AudioProcessorGraph* getParentGraph() const noexcept { return graph; } - - /** True if this is an audio or midi input. */ - bool isInput() const noexcept; - /** True if this is an audio or midi output. */ - bool isOutput() const noexcept; - - //============================================================================== - AudioGraphIOProcessor (const IODeviceType type); - ~AudioGraphIOProcessor(); - - const String getName() const override; - void fillInPluginDescription (PluginDescription&) const override; - void prepareToPlay (double newSampleRate, int estimatedSamplesPerBlock) override; - void releaseResources() override; - void processBlock (AudioBuffer& , MidiBuffer&) override; - void processBlock (AudioBuffer&, MidiBuffer&) override; - bool supportsDoublePrecisionProcessing() const override; - - double getTailLengthSeconds() const override; - bool acceptsMidi() const override; - bool producesMidi() const override; - - #if ! JUCE_AUDIOPROCESSOR_NO_GUI - bool hasEditor() const override; - AudioProcessorEditor* createEditor() override; - #endif - - int getNumPrograms() override; - int getCurrentProgram() override; - void setCurrentProgram (int) override; - const String getProgramName (int) override; - void changeProgramName (int, const String&) override; - - void getStateInformation (juce::MemoryBlock& destData) override; - void setStateInformation (const void* data, int sizeInBytes) override; - - /** @internal */ - void setParentGraph (AudioProcessorGraph*); - - private: - const IODeviceType type; - AudioProcessorGraph* graph; - - //============================================================================== - template - void processAudio (AudioBuffer& buffer, MidiBuffer& midiMessages); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioGraphIOProcessor) - }; - - //============================================================================== - const String getName() const override; - void prepareToPlay (double, int) override; - void releaseResources() override; - void processBlock (AudioBuffer&, MidiBuffer&) override; - void processBlock (AudioBuffer&, MidiBuffer&) override; - bool supportsDoublePrecisionProcessing() const override; - - void reset() override; - void setNonRealtime (bool) noexcept override; - void setPlayHead (AudioPlayHead*) override; - - double getTailLengthSeconds() const override; - bool acceptsMidi() const override; - bool producesMidi() const override; - - #if ! JUCE_AUDIOPROCESSOR_NO_GUI - bool hasEditor() const override { return false; } - AudioProcessorEditor* createEditor() override { return nullptr; } - #endif - int getNumPrograms() override { return 0; } - int getCurrentProgram() override { return 0; } - void setCurrentProgram (int) override { } - const String getProgramName (int) override { return {}; } - void changeProgramName (int, const String&) override { } - void getStateInformation (juce::MemoryBlock&) override; - void setStateInformation (const void* data, int sizeInBytes) override; - -private: - //============================================================================== - template - void processAudio (AudioBuffer& buffer, MidiBuffer& midiMessages); - - template - void sliceAndProcess (AudioBuffer& buffer, MidiBuffer& midiMessages); - - //============================================================================== - ReferenceCountedArray nodes; - OwnedArray connections; - uint32 lastNodeId; - OwnedArray midiBuffers; - Array renderingOps; - - friend class AudioGraphIOProcessor; - struct AudioProcessorGraphBufferHelpers; - ScopedPointer audioBuffers; - - MidiBuffer* currentMidiInputBuffer; - MidiBuffer currentMidiOutputBuffer; - - bool isPrepared; - - void handleAsyncUpdate() override; - void clearRenderingSequence(); - void buildRenderingSequence(); - bool isAnInputTo (uint32 possibleInputId, uint32 possibleDestinationId, int recursionCheck) const; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorGraph) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorListener.h b/source/modules/juce_audio_processors/processors/juce_AudioProcessorListener.h deleted file mode 100644 index 7781af1fe..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorListener.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - Base class for listeners that want to know about changes to an AudioProcessor. - - Use AudioProcessor::addListener() to register your listener with an AudioProcessor. - - @see AudioProcessor -*/ -class JUCE_API AudioProcessorListener -{ -public: - //============================================================================== - /** Destructor. */ - virtual ~AudioProcessorListener() {} - - //============================================================================== - /** Receives a callback when a parameter is changed. - - IMPORTANT NOTE: this will be called synchronously when a parameter changes, and - many audio processors will change their parameter during their audio callback. - This means that not only has your handler code got to be completely thread-safe, - but it's also got to be VERY fast, and avoid blocking. If you need to handle - this event on your message thread, use this callback to trigger an AsyncUpdater - or ChangeBroadcaster which you can respond to on the message thread. - */ - virtual void audioProcessorParameterChanged (AudioProcessor* processor, - int parameterIndex, - float newValue) = 0; - - /** Called to indicate that something else in the plugin has changed, like its - program, number of parameters, etc. - - IMPORTANT NOTE: this will be called synchronously, and many audio processors will - call it during their audio callback. This means that not only has your handler code - got to be completely thread-safe, but it's also got to be VERY fast, and avoid - blocking. If you need to handle this event on your message thread, use this callback - to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the - message thread. - */ - virtual void audioProcessorChanged (AudioProcessor* processor) = 0; - - /** Indicates that a parameter change gesture has started. - - E.g. if the user is dragging a slider, this would be called when they first - press the mouse button, and audioProcessorParameterChangeGestureEnd would be - called when they release it. - - IMPORTANT NOTE: this will be called synchronously, and many audio processors will - call it during their audio callback. This means that not only has your handler code - got to be completely thread-safe, but it's also got to be VERY fast, and avoid - blocking. If you need to handle this event on your message thread, use this callback - to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the - message thread. - - @see audioProcessorParameterChangeGestureEnd - */ - virtual void audioProcessorParameterChangeGestureBegin (AudioProcessor* processor, - int parameterIndex); - - /** Indicates that a parameter change gesture has finished. - - E.g. if the user is dragging a slider, this would be called when they release - the mouse button. - - IMPORTANT NOTE: this will be called synchronously, and many audio processors will - call it during their audio callback. This means that not only has your handler code - got to be completely thread-safe, but it's also got to be VERY fast, and avoid - blocking. If you need to handle this event on your message thread, use this callback - to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the - message thread. - - @see audioProcessorParameterChangeGestureBegin - */ - virtual void audioProcessorParameterChangeGestureEnd (AudioProcessor* processor, - int parameterIndex); -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h b/source/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h deleted file mode 100644 index 8dc6e5eb0..000000000 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** An abstract base class for parameter objects that can be added to an - AudioProcessor. - - @see AudioProcessor::addParameter -*/ -class JUCE_API AudioProcessorParameter -{ -public: - AudioProcessorParameter() noexcept; - - /** Destructor. */ - virtual ~AudioProcessorParameter(); - - /** Called by the host to find out the value of this parameter. - - Hosts will expect the value returned to be between 0 and 1.0. - - This could be called quite frequently, so try to make your code efficient. - It's also likely to be called by non-UI threads, so the code in here should - be thread-aware. - */ - virtual float getValue() const = 0; - - /** The host will call this method to change the value of one of the filter's parameters. - - The host may call this at any time, including during the audio processing - callback, so the filter has to process this very fast and avoid blocking. - - If you want to set the value of a parameter internally, e.g. from your - editor component, then don't call this directly - instead, use the - setValueNotifyingHost() method, which will also send a message to - the host telling it about the change. If the message isn't sent, the host - won't be able to automate your parameters properly. - - The value passed will be between 0 and 1.0. - */ - virtual void setValue (float newValue) = 0; - - /** Your filter can call this when it needs to change one of its parameters. - - This could happen when the editor or some other internal operation changes - a parameter. This method will call the setValue() method to change the - value, and will then send a message to the host telling it about the change. - - Note that to make sure the host correctly handles automation, you should call - the beginChangeGesture() and endChangeGesture() methods to tell the host when - the user has started and stopped changing the parameter. - */ - void setValueNotifyingHost (float newValue); - - /** Sends a signal to the host to tell it that the user is about to start changing this - parameter. - This allows the host to know when a parameter is actively being held by the user, and - it may use this information to help it record automation. - If you call this, it must be matched by a later call to endChangeGesture(). - */ - void beginChangeGesture(); - - /** Tells the host that the user has finished changing this parameter. - This allows the host to know when a parameter is actively being held by the user, - and it may use this information to help it record automation. - A call to this method must follow a call to beginChangeGesture(). - */ - void endChangeGesture(); - - /** This should return the default value for this parameter. */ - virtual float getDefaultValue() const = 0; - - /** Returns the name to display for this parameter, which should be made - to fit within the given string length. - */ - virtual String getName (int maximumStringLength) const = 0; - - /** Some parameters may be able to return a label string for - their units. For example "Hz" or "%". - */ - virtual String getLabel() const = 0; - - /** Returns the number of steps that this parameter's range should be quantised into. - - If you want a continuous range of values, don't override this method, and allow - the default implementation to return AudioProcessor::getDefaultNumParameterSteps(). - - If your parameter is boolean, then you may want to make this return 2. - - The value that is returned may or may not be used, depending on the host. If you - want the host to display stepped automation values, rather than a continuous - interpolation between successive values, you should override isDiscrete to return true. - - @see isDiscrete - */ - virtual int getNumSteps() const; - - /** Returns whether the parameter uses discrete values, based on the result of - getNumSteps, or allows the host to select values continuously. - - This information may or may not be used, depending on the host. If you - want the host to display stepped automation values, rather than a continuous - interpolation between successive values, override this method to return true. - - @see getNumSteps - */ - virtual bool isDiscrete() const; - - /** Returns a textual version of the supplied parameter value. - The default implementation just returns the floating point value - as a string, but this could do anything you need for a custom type - of value. - */ - virtual String getText (float value, int /*maximumStringLength*/) const; - - /** Should parse a string and return the appropriate value for it. */ - virtual float getValueForText (const String& text) const = 0; - - /** This can be overridden to tell the host that this parameter operates in the - reverse direction. - (Not all plugin formats or hosts will actually use this information). - */ - virtual bool isOrientationInverted() const; - - /** Returns true if the host can automate this parameter. - By default, this returns true. - */ - virtual bool isAutomatable() const; - - /** Should return true if this parameter is a "meta" parameter. - A meta-parameter is a parameter that changes other params. It is used - by some hosts (e.g. AudioUnit hosts). - By default this returns false. - */ - virtual bool isMetaParameter() const; - - enum Category - { - genericParameter = (0 << 16) | 0, /** If your parameter is not a meter then you should use this category */ - - inputGain = (1 << 16) | 0, /** Currently not used */ - outputGain = (1 << 16) | 1, - - /** The following categories tell the host that this parameter is a meter level value - and therefore read-only. Most hosts will display these type of parameters as - a meter in the generic view of your plug-in. Pro-Tools will also show the meter - in the mixer view. - */ - inputMeter = (2 << 16) | 0, - outputMeter = (2 << 16) | 1, - compressorLimiterGainReductionMeter = (2 << 16) | 2, - expanderGateGainReductionMeter = (2 << 16) | 3, - analysisMeter = (2 << 16) | 4, - otherMeter = (2 << 16) | 5 - }; - - /** Returns the parameter's category. */ - virtual Category getCategory() const; - - /** Returns the index of this parameter in its parent processor's parameter list. */ - int getParameterIndex() const noexcept { return parameterIndex; } - -private: - friend class AudioProcessor; - AudioProcessor* processor; - int parameterIndex; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameter) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp b/source/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp deleted file mode 100644 index 08f160932..000000000 --- a/source/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -class ProcessorParameterPropertyComp : public PropertyComponent, - private AudioProcessorListener, - private Timer -{ -public: - ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, int paramIndex) - : PropertyComponent (name), - owner (p), - index (paramIndex), - paramHasChanged (false), - slider (p, paramIndex) - { - startTimer (100); - addAndMakeVisible (slider); - owner.addListener (this); - } - - ~ProcessorParameterPropertyComp() - { - owner.removeListener (this); - } - - void refresh() override - { - paramHasChanged = false; - - if (slider.getThumbBeingDragged() < 0) - slider.setValue (owner.getParameter (index), dontSendNotification); - - slider.updateText(); - } - - void audioProcessorChanged (AudioProcessor*) override {} - - void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float) override - { - if (parameterIndex == index) - paramHasChanged = true; - } - - void timerCallback() override - { - if (paramHasChanged) - { - refresh(); - startTimerHz (50); - } - else - { - startTimer (jmin (1000 / 4, getTimerInterval() + 10)); - } - } - -private: - //============================================================================== - class ParamSlider : public Slider - { - public: - ParamSlider (AudioProcessor& p, int paramIndex) : owner (p), index (paramIndex) - { - const int steps = owner.getParameterNumSteps (index); - const AudioProcessorParameter::Category category = p.getParameterCategory (index); - const bool isLevelMeter = (((category & 0xffff0000) >> 16) == 2); - - if (steps > 1 && steps < 0x7fffffff) - setRange (0.0, 1.0, 1.0 / (steps - 1.0)); - else - setRange (0.0, 1.0); - - setEnabled (! isLevelMeter); - setSliderStyle (Slider::LinearBar); - setTextBoxIsEditable (false); - setScrollWheelEnabled (true); - } - - void valueChanged() override - { - const float newVal = (float) getValue(); - - if (owner.getParameter (index) != newVal) - { - owner.setParameterNotifyingHost (index, newVal); - updateText(); - } - } - - void startedDragging() override - { - owner.beginParameterChangeGesture(index); - } - - void stoppedDragging() override - { - owner.endParameterChangeGesture(index); - } - - String getTextFromValue (double /*value*/) override - { - return owner.getParameterText (index) + " " + owner.getParameterLabel (index).trimEnd(); - } - - private: - //============================================================================== - AudioProcessor& owner; - const int index; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamSlider) - }; - - AudioProcessor& owner; - const int index; - bool volatile paramHasChanged; - ParamSlider slider; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProcessorParameterPropertyComp) -}; - - -//============================================================================== -GenericAudioProcessorEditor::GenericAudioProcessorEditor (AudioProcessor* const p) - : AudioProcessorEditor (p) -{ - jassert (p != nullptr); - setOpaque (true); - - addAndMakeVisible (panel); - - Array params; - - const int numParams = p->getNumParameters(); - int totalHeight = 0; - - for (int i = 0; i < numParams; ++i) - { - String name (p->getParameterName (i)); - if (name.trim().isEmpty()) - name = "Unnamed"; - - ProcessorParameterPropertyComp* const pc = new ProcessorParameterPropertyComp (name, *p, i); - params.add (pc); - totalHeight += pc->getPreferredHeight(); - } - - panel.addProperties (params); - - setSize (400, jlimit (25, 400, totalHeight)); -} - -GenericAudioProcessorEditor::~GenericAudioProcessorEditor() -{ -} - -void GenericAudioProcessorEditor::paint (Graphics& g) -{ - g.fillAll (Colours::white); -} - -void GenericAudioProcessorEditor::resized() -{ - panel.setBounds (getLocalBounds()); -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h b/source/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h deleted file mode 100644 index 611d62129..000000000 --- a/source/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - A type of UI component that displays the parameters of an AudioProcessor as - a simple list of sliders. - - This can be used for showing an editor for a processor that doesn't supply - its own custom editor. - - @see AudioProcessor -*/ -class JUCE_API GenericAudioProcessorEditor : public AudioProcessorEditor -{ -public: - //============================================================================== - GenericAudioProcessorEditor (AudioProcessor* owner); - ~GenericAudioProcessorEditor(); - - //============================================================================== - void paint (Graphics&) override; - void resized() override; - -private: - //============================================================================== - PropertyPanel panel; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericAudioProcessorEditor) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_PluginDescription.cpp b/source/modules/juce_audio_processors/processors/juce_PluginDescription.cpp deleted file mode 100644 index 6d885d722..000000000 --- a/source/modules/juce_audio_processors/processors/juce_PluginDescription.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -PluginDescription::PluginDescription() - : uid (0), - isInstrument (false), - numInputChannels (0), - numOutputChannels (0), - hasSharedContainer (false) -{ -} - -PluginDescription::~PluginDescription() -{ -} - -PluginDescription::PluginDescription (const PluginDescription& other) - : name (other.name), - descriptiveName (other.descriptiveName), - pluginFormatName (other.pluginFormatName), - category (other.category), - manufacturerName (other.manufacturerName), - version (other.version), - fileOrIdentifier (other.fileOrIdentifier), - lastFileModTime (other.lastFileModTime), - lastInfoUpdateTime (other.lastInfoUpdateTime), - uid (other.uid), - isInstrument (other.isInstrument), - numInputChannels (other.numInputChannels), - numOutputChannels (other.numOutputChannels), - hasSharedContainer (other.hasSharedContainer) -{ -} - -PluginDescription& PluginDescription::operator= (const PluginDescription& other) -{ - name = other.name; - descriptiveName = other.descriptiveName; - pluginFormatName = other.pluginFormatName; - category = other.category; - manufacturerName = other.manufacturerName; - version = other.version; - fileOrIdentifier = other.fileOrIdentifier; - uid = other.uid; - isInstrument = other.isInstrument; - lastFileModTime = other.lastFileModTime; - lastInfoUpdateTime = other.lastInfoUpdateTime; - numInputChannels = other.numInputChannels; - numOutputChannels = other.numOutputChannels; - hasSharedContainer = other.hasSharedContainer; - - return *this; -} - -bool PluginDescription::isDuplicateOf (const PluginDescription& other) const noexcept -{ - return fileOrIdentifier == other.fileOrIdentifier - && uid == other.uid; -} - -static String getPluginDescSuffix (const PluginDescription& d) -{ - return "-" + String::toHexString (d.fileOrIdentifier.hashCode()) - + "-" + String::toHexString (d.uid); -} - -bool PluginDescription::matchesIdentifierString (const String& identifierString) const -{ - return identifierString.endsWithIgnoreCase (getPluginDescSuffix (*this)); -} - -String PluginDescription::createIdentifierString() const -{ - return pluginFormatName + "-" + name + getPluginDescSuffix (*this); -} - -XmlElement* PluginDescription::createXml() const -{ - XmlElement* const e = new XmlElement ("PLUGIN"); - e->setAttribute ("name", name); - if (descriptiveName != name) - e->setAttribute ("descriptiveName", descriptiveName); - - e->setAttribute ("format", pluginFormatName); - e->setAttribute ("category", category); - e->setAttribute ("manufacturer", manufacturerName); - e->setAttribute ("version", version); - e->setAttribute ("file", fileOrIdentifier); - e->setAttribute ("uid", String::toHexString (uid)); - e->setAttribute ("isInstrument", isInstrument); - e->setAttribute ("fileTime", String::toHexString (lastFileModTime.toMilliseconds())); - e->setAttribute ("infoUpdateTime", String::toHexString (lastInfoUpdateTime.toMilliseconds())); - e->setAttribute ("numInputs", numInputChannels); - e->setAttribute ("numOutputs", numOutputChannels); - e->setAttribute ("isShell", hasSharedContainer); - - return e; -} - -bool PluginDescription::loadFromXml (const XmlElement& xml) -{ - if (xml.hasTagName ("PLUGIN")) - { - name = xml.getStringAttribute ("name"); - descriptiveName = xml.getStringAttribute ("descriptiveName", name); - pluginFormatName = xml.getStringAttribute ("format"); - category = xml.getStringAttribute ("category"); - manufacturerName = xml.getStringAttribute ("manufacturer"); - version = xml.getStringAttribute ("version"); - fileOrIdentifier = xml.getStringAttribute ("file"); - uid = xml.getStringAttribute ("uid").getHexValue32(); - isInstrument = xml.getBoolAttribute ("isInstrument", false); - lastFileModTime = Time (xml.getStringAttribute ("fileTime").getHexValue64()); - lastInfoUpdateTime = Time (xml.getStringAttribute ("infoUpdateTime").getHexValue64()); - numInputChannels = xml.getIntAttribute ("numInputs"); - numOutputChannels = xml.getIntAttribute ("numOutputs"); - hasSharedContainer = xml.getBoolAttribute ("isShell", false); - - return true; - } - - return false; -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/processors/juce_PluginDescription.h b/source/modules/juce_audio_processors/processors/juce_PluginDescription.h deleted file mode 100644 index 7642545a1..000000000 --- a/source/modules/juce_audio_processors/processors/juce_PluginDescription.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - A small class to represent some facts about a particular type of plug-in. - - This class is for storing and managing the details about a plug-in without - actually having to load an instance of it. - - A KnownPluginList contains a list of PluginDescription objects. - - @see KnownPluginList -*/ -class JUCE_API PluginDescription -{ -public: - //============================================================================== - PluginDescription(); - PluginDescription (const PluginDescription& other); - PluginDescription& operator= (const PluginDescription& other); - ~PluginDescription(); - - //============================================================================== - /** The name of the plug-in. */ - String name; - - /** A more descriptive name for the plug-in. - This may be the same as the 'name' field, but some plug-ins may provide an - alternative name. - */ - String descriptiveName; - - /** The plug-in format, e.g. "VST", "AudioUnit", etc. */ - String pluginFormatName; - - /** A category, such as "Dynamics", "Reverbs", etc. */ - String category; - - /** The manufacturer. */ - String manufacturerName; - - /** The version. This string doesn't have any particular format. */ - String version; - - /** Either the file containing the plug-in module, or some other unique way - of identifying it. - - E.g. for an AU, this would be an ID string that the component manager - could use to retrieve the plug-in. For a VST, it's the file path. - */ - String fileOrIdentifier; - - /** The last time the plug-in file was changed. - This is handy when scanning for new or changed plug-ins. - */ - Time lastFileModTime; - - /** The last time that this information was updated. This would typically have - been during a scan when this plugin was first tested or found to have changed. - */ - Time lastInfoUpdateTime; - - /** A unique ID for the plug-in. - - Note that this might not be unique between formats, e.g. a VST and some - other format might actually have the same id. - - @see createIdentifierString - */ - int uid; - - /** True if the plug-in identifies itself as a synthesiser. */ - bool isInstrument; - - /** The number of inputs. */ - int numInputChannels; - - /** The number of outputs. */ - int numOutputChannels; - - /** True if the plug-in is part of a multi-type container, e.g. a VST Shell. */ - bool hasSharedContainer; - - /** Returns true if the two descriptions refer to the same plug-in. - - This isn't quite as simple as them just having the same file (because of - shell plug-ins). - */ - bool isDuplicateOf (const PluginDescription& other) const noexcept; - - /** Return true if this description is equivalent to another one which created the - given identifier string. - - Note that this isn't quite as simple as them just calling createIdentifierString() - and comparing the strings, because the identifiers can differ (thanks to shell plug-ins). - */ - bool matchesIdentifierString (const String& identifierString) const; - - //============================================================================== - /** Returns a string that can be saved and used to uniquely identify the - plugin again. - - This contains less info than the XML encoding, and is independent of the - plug-in's file location, so can be used to store a plug-in ID for use - across different machines. - */ - String createIdentifierString() const; - - //============================================================================== - /** Creates an XML object containing these details. - - @see loadFromXml - */ - XmlElement* createXml() const; - - /** Reloads the info in this structure from an XML record that was previously - saved with createXML(). - - Returns true if the XML was a valid plug-in description. - */ - bool loadFromXml (const XmlElement& xml); - - -private: - //============================================================================== - JUCE_LEAK_DETECTOR (PluginDescription) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp b/source/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp deleted file mode 100644 index f7c0bf71e..000000000 --- a/source/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp +++ /dev/null @@ -1,587 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -KnownPluginList::KnownPluginList() {} -KnownPluginList::~KnownPluginList() {} - -void KnownPluginList::clear() -{ - ScopedLock lock (typesArrayLock); - - if (! types.isEmpty()) - { - types.clear(); - sendChangeMessage(); - } -} - -PluginDescription* KnownPluginList::getTypeForFile (const String& fileOrIdentifier) const -{ - ScopedLock lock (typesArrayLock); - - for (auto* desc : types) - if (desc->fileOrIdentifier == fileOrIdentifier) - return desc; - - return nullptr; -} - -PluginDescription* KnownPluginList::getTypeForIdentifierString (const String& identifierString) const -{ - ScopedLock lock (typesArrayLock); - - for (auto* desc : types) - if (desc->matchesIdentifierString (identifierString)) - return desc; - - return nullptr; -} - -bool KnownPluginList::addType (const PluginDescription& type) -{ - { - ScopedLock lock (typesArrayLock); - - for (auto* desc : types) - { - if (desc->isDuplicateOf (type)) - { - // strange - found a duplicate plugin with different info.. - jassert (desc->name == type.name); - jassert (desc->isInstrument == type.isInstrument); - - *desc = type; - return false; - } - } - - types.insert (0, new PluginDescription (type)); - } - - sendChangeMessage(); - return true; -} - -void KnownPluginList::removeType (const int index) -{ - { - ScopedLock lock (typesArrayLock); - types.remove (index); - } - - sendChangeMessage(); -} - -bool KnownPluginList::isListingUpToDate (const String& fileOrIdentifier, - AudioPluginFormat& formatToUse) const -{ - if (getTypeForFile (fileOrIdentifier) == nullptr) - return false; - - ScopedLock lock (typesArrayLock); - - for (auto* d : types) - if (d->fileOrIdentifier == fileOrIdentifier && formatToUse.pluginNeedsRescanning (*d)) - return false; - - return true; -} - -void KnownPluginList::setCustomScanner (CustomScanner* newScanner) -{ - scanner = newScanner; -} - -bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier, - const bool dontRescanIfAlreadyInList, - OwnedArray& typesFound, - AudioPluginFormat& format) -{ - const ScopedLock sl (scanLock); - - if (dontRescanIfAlreadyInList - && getTypeForFile (fileOrIdentifier) != nullptr) - { - bool needsRescanning = false; - - ScopedLock lock (typesArrayLock); - - for (auto* d : types) - { - if (d->fileOrIdentifier == fileOrIdentifier && d->pluginFormatName == format.getName()) - { - if (format.pluginNeedsRescanning (*d)) - needsRescanning = true; - else - typesFound.add (new PluginDescription (*d)); - } - } - - if (! needsRescanning) - return false; - } - - if (blacklist.contains (fileOrIdentifier)) - return false; - - OwnedArray found; - - { - const ScopedUnlock sl2 (scanLock); - - if (scanner != nullptr) - { - if (! scanner->findPluginTypesFor (format, found, fileOrIdentifier)) - addToBlacklist (fileOrIdentifier); - } - else - { - format.findAllTypesForFile (found, fileOrIdentifier); - } - } - - for (auto* desc : found) - { - jassert (desc != nullptr); - addType (*desc); - typesFound.add (new PluginDescription (*desc)); - } - - return ! found.isEmpty(); -} - -void KnownPluginList::scanAndAddDragAndDroppedFiles (AudioPluginFormatManager& formatManager, - const StringArray& files, - OwnedArray& typesFound) -{ - for (const auto& filenameOrID : files) - { - bool found = false; - - for (int j = 0; j < formatManager.getNumFormats(); ++j) - { - auto* format = formatManager.getFormat (j); - - if (format->fileMightContainThisPluginType (filenameOrID) - && scanAndAddFile (filenameOrID, true, typesFound, *format)) - { - found = true; - break; - } - } - - if (! found) - { - const File f (filenameOrID); - - if (f.isDirectory()) - { - StringArray s; - - { - Array subFiles; - f.findChildFiles (subFiles, File::findFilesAndDirectories, false); - - for (auto& subFile : subFiles) - s.add (subFile.getFullPathName()); - } - - scanAndAddDragAndDroppedFiles (formatManager, s, typesFound); - } - } - } - - scanFinished(); -} - -void KnownPluginList::scanFinished() -{ - if (scanner != nullptr) - scanner->scanFinished(); -} - -const StringArray& KnownPluginList::getBlacklistedFiles() const -{ - return blacklist; -} - -void KnownPluginList::addToBlacklist (const String& pluginID) -{ - if (! blacklist.contains (pluginID)) - { - blacklist.add (pluginID); - sendChangeMessage(); - } -} - -void KnownPluginList::removeFromBlacklist (const String& pluginID) -{ - const int index = blacklist.indexOf (pluginID); - - if (index >= 0) - { - blacklist.remove (index); - sendChangeMessage(); - } -} - -void KnownPluginList::clearBlacklistedFiles() -{ - if (blacklist.size() > 0) - { - blacklist.clear(); - sendChangeMessage(); - } -} - -//============================================================================== -struct PluginSorter -{ - PluginSorter (KnownPluginList::SortMethod sortMethod, bool forwards) noexcept - : method (sortMethod), direction (forwards ? 1 : -1) {} - - int compareElements (const PluginDescription* const first, - const PluginDescription* const second) const - { - int diff = 0; - - switch (method) - { - case KnownPluginList::sortByCategory: diff = first->category.compareNatural (second->category, true); break; - case KnownPluginList::sortByManufacturer: diff = first->manufacturerName.compareNatural (second->manufacturerName, true); break; - case KnownPluginList::sortByFormat: diff = first->pluginFormatName.compare (second->pluginFormatName); break; - case KnownPluginList::sortByFileSystemLocation: diff = lastPathPart (first->fileOrIdentifier).compare (lastPathPart (second->fileOrIdentifier)); break; - case KnownPluginList::sortByInfoUpdateTime: diff = compare (first->lastInfoUpdateTime, second->lastInfoUpdateTime); break; - default: break; - } - - if (diff == 0) - diff = first->name.compareNatural (second->name, true); - - return diff * direction; - } - -private: - static String lastPathPart (const String& path) - { - return path.replaceCharacter ('\\', '/').upToLastOccurrenceOf ("/", false, false); - } - - static int compare (Time a, Time b) noexcept - { - if (a < b) return -1; - if (b < a) return 1; - - return 0; - } - - const KnownPluginList::SortMethod method; - const int direction; - - JUCE_DECLARE_NON_COPYABLE (PluginSorter) -}; - -void KnownPluginList::sort (const SortMethod method, bool forwards) -{ - if (method != defaultOrder) - { - Array oldOrder, newOrder; - - { - ScopedLock lock (typesArrayLock); - - oldOrder.addArray (types); - - PluginSorter sorter (method, forwards); - types.sort (sorter, true); - - newOrder.addArray (types); - } - - if (oldOrder != newOrder) - sendChangeMessage(); - } -} - -//============================================================================== -XmlElement* KnownPluginList::createXml() const -{ - auto e = new XmlElement ("KNOWNPLUGINS"); - - { - ScopedLock lock (typesArrayLock); - - for (int i = types.size(); --i >= 0;) - e->prependChildElement (types.getUnchecked(i)->createXml()); - } - - for (auto& b : blacklist) - e->createNewChildElement ("BLACKLISTED")->setAttribute ("id", b); - - return e; -} - -void KnownPluginList::recreateFromXml (const XmlElement& xml) -{ - clear(); - clearBlacklistedFiles(); - - if (xml.hasTagName ("KNOWNPLUGINS")) - { - forEachXmlChildElement (xml, e) - { - PluginDescription info; - - if (e->hasTagName ("BLACKLISTED")) - blacklist.add (e->getStringAttribute ("id")); - else if (info.loadFromXml (*e)) - addType (info); - } - } -} - -//============================================================================== -struct PluginTreeUtils -{ - enum { menuIdBase = 0x324503f4 }; - - static void buildTreeByFolder (KnownPluginList::PluginTree& tree, const Array& allPlugins) - { - for (auto* pd : allPlugins) - { - auto path = pd->fileOrIdentifier.replaceCharacter ('\\', '/') - .upToLastOccurrenceOf ("/", false, false); - - if (path.substring (1, 2) == ":") - path = path.substring (2); - - addPlugin (tree, pd, path); - } - - optimiseFolders (tree, false); - } - - static void optimiseFolders (KnownPluginList::PluginTree& tree, bool concatenateName) - { - for (int i = tree.subFolders.size(); --i >= 0;) - { - auto& sub = *tree.subFolders.getUnchecked(i); - optimiseFolders (sub, concatenateName || (tree.subFolders.size() > 1)); - - if (sub.plugins.isEmpty()) - { - for (auto* s : sub.subFolders) - { - if (concatenateName) - s->folder = sub.folder + "/" + s->folder; - - tree.subFolders.add (s); - } - - sub.subFolders.clear (false); - tree.subFolders.remove (i); - } - } - } - - static void buildTreeByCategory (KnownPluginList::PluginTree& tree, - const Array& sorted, - const KnownPluginList::SortMethod sortMethod) - { - String lastType; - ScopedPointer current (new KnownPluginList::PluginTree()); - - for (auto* pd : sorted) - { - auto thisType = (sortMethod == KnownPluginList::sortByCategory ? pd->category - : pd->manufacturerName); - - if (! thisType.containsNonWhitespaceChars()) - thisType = "Other"; - - if (! thisType.equalsIgnoreCase (lastType)) - { - if (current->plugins.size() + current->subFolders.size() > 0) - { - current->folder = lastType; - tree.subFolders.add (current.release()); - current = new KnownPluginList::PluginTree(); - } - - lastType = thisType; - } - - current->plugins.add (pd); - } - - if (current->plugins.size() + current->subFolders.size() > 0) - { - current->folder = lastType; - tree.subFolders.add (current.release()); - } - } - - static void addPlugin (KnownPluginList::PluginTree& tree, PluginDescription* const pd, String path) - { - if (path.isEmpty()) - { - tree.plugins.add (pd); - } - else - { - #if JUCE_MAC - if (path.containsChar (':')) - path = path.fromFirstOccurrenceOf (":", false, false); // avoid the special AU formatting nonsense on Mac.. - #endif - - auto firstSubFolder = path.upToFirstOccurrenceOf ("/", false, false); - auto remainingPath = path.fromFirstOccurrenceOf ("/", false, false); - - for (int i = tree.subFolders.size(); --i >= 0;) - { - KnownPluginList::PluginTree& subFolder = *tree.subFolders.getUnchecked(i); - - if (subFolder.folder.equalsIgnoreCase (firstSubFolder)) - { - addPlugin (subFolder, pd, remainingPath); - return; - } - } - - auto newFolder = new KnownPluginList::PluginTree(); - newFolder->folder = firstSubFolder; - tree.subFolders.add (newFolder); - addPlugin (*newFolder, pd, remainingPath); - } - } - - static bool containsDuplicateNames (const Array& plugins, const String& name) - { - int matches = 0; - - for (int i = 0; i < plugins.size(); ++i) - if (plugins.getUnchecked(i)->name == name) - if (++matches > 1) - return true; - - return false; - } - - static bool addToMenu (const KnownPluginList::PluginTree& tree, PopupMenu& m, - const OwnedArray& allPlugins, - const String& currentlyTickedPluginID) - { - bool isTicked = false; - - for (auto* sub : tree.subFolders) - { - PopupMenu subMenu; - const bool isItemTicked = addToMenu (*sub, subMenu, allPlugins, currentlyTickedPluginID); - isTicked = isTicked || isItemTicked; - - m.addSubMenu (sub->folder, subMenu, true, nullptr, isItemTicked, 0); - } - - for (auto* plugin : tree.plugins) - { - auto name = plugin->name; - - if (containsDuplicateNames (tree.plugins, name)) - name << " (" << plugin->pluginFormatName << ')'; - - const bool isItemTicked = plugin->matchesIdentifierString (currentlyTickedPluginID); - isTicked = isTicked || isItemTicked; - - m.addItem (allPlugins.indexOf (plugin) + menuIdBase, name, true, isItemTicked); - } - - return isTicked; - } -}; - -KnownPluginList::PluginTree* KnownPluginList::createTree (const SortMethod sortMethod) const -{ - Array sorted; - - { - ScopedLock lock (typesArrayLock); - PluginSorter sorter (sortMethod, true); - - for (auto* t : types) - sorted.addSorted (sorter, t); - } - - auto* tree = new PluginTree(); - - if (sortMethod == sortByCategory || sortMethod == sortByManufacturer || sortMethod == sortByFormat) - { - PluginTreeUtils::buildTreeByCategory (*tree, sorted, sortMethod); - } - else if (sortMethod == sortByFileSystemLocation) - { - PluginTreeUtils::buildTreeByFolder (*tree, sorted); - } - else - { - for (auto* p : sorted) - tree->plugins.add (p); - } - - return tree; -} - -//============================================================================== -void KnownPluginList::addToMenu (PopupMenu& menu, const SortMethod sortMethod, - const String& currentlyTickedPluginID) const -{ - ScopedPointer tree (createTree (sortMethod)); - PluginTreeUtils::addToMenu (*tree, menu, types, currentlyTickedPluginID); -} - -int KnownPluginList::getIndexChosenByMenu (const int menuResultCode) const -{ - const int i = menuResultCode - PluginTreeUtils::menuIdBase; - return isPositiveAndBelow (i, types.size()) ? i : -1; -} - -//============================================================================== -KnownPluginList::CustomScanner::CustomScanner() {} -KnownPluginList::CustomScanner::~CustomScanner() {} - -void KnownPluginList::CustomScanner::scanFinished() {} - -bool KnownPluginList::CustomScanner::shouldExit() const noexcept -{ - if (auto* job = ThreadPoolJob::getCurrentThreadPoolJob()) - return job->shouldExit(); - - return false; -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/scanning/juce_KnownPluginList.h b/source/modules/juce_audio_processors/scanning/juce_KnownPluginList.h deleted file mode 100644 index 17ce28fb3..000000000 --- a/source/modules/juce_audio_processors/scanning/juce_KnownPluginList.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - Manages a list of plugin types. - - This can be easily edited, saved and loaded, and used to create instances of - the plugin types in it. - - @see PluginListComponent -*/ -class JUCE_API KnownPluginList : public ChangeBroadcaster -{ -public: - //============================================================================== - /** Creates an empty list. */ - KnownPluginList(); - - /** Destructor. */ - ~KnownPluginList(); - - //============================================================================== - /** Clears the list. */ - void clear(); - - /** Returns the number of types currently in the list. - @see getType - */ - int getNumTypes() const noexcept { return types.size(); } - - /** Returns one of the types. - @see getNumTypes - */ - PluginDescription* getType (int index) const noexcept { return types [index]; } - - /** Type iteration. */ - PluginDescription** begin() const noexcept { return types.begin(); } - /** Type iteration. */ - PluginDescription** end() const noexcept { return types.end(); } - - /** Looks for a type in the list which comes from this file. */ - PluginDescription* getTypeForFile (const String& fileOrIdentifier) const; - - /** Looks for a type in the list which matches a plugin type ID. - - The identifierString parameter must have been created by - PluginDescription::createIdentifierString(). - */ - PluginDescription* getTypeForIdentifierString (const String& identifierString) const; - - /** Adds a type manually from its description. */ - bool addType (const PluginDescription& type); - - /** Removes a type. */ - void removeType (int index); - - /** Looks for all types that can be loaded from a given file, and adds them - to the list. - - If dontRescanIfAlreadyInList is true, then the file will only be loaded and - re-tested if it's not already in the list, or if the file's modification - time has changed since the list was created. If dontRescanIfAlreadyInList is - false, the file will always be reloaded and tested. - - Returns true if any new types were added, and all the types found in this - file (even if it was already known and hasn't been re-scanned) get returned - in the array. - */ - bool scanAndAddFile (const String& possiblePluginFileOrIdentifier, - bool dontRescanIfAlreadyInList, - OwnedArray & typesFound, - AudioPluginFormat& formatToUse); - - /** Tells a custom scanner that a scan has finished, and it can release any resources. */ - void scanFinished(); - - /** Returns true if the specified file is already known about and if it - hasn't been modified since our entry was created. - */ - bool isListingUpToDate (const String& possiblePluginFileOrIdentifier, - AudioPluginFormat& formatToUse) const; - - /** Scans and adds a bunch of files that might have been dragged-and-dropped. - If any types are found in the files, their descriptions are returned in the array. - */ - void scanAndAddDragAndDroppedFiles (AudioPluginFormatManager& formatManager, - const StringArray& filenames, - OwnedArray & typesFound); - - //============================================================================== - /** Returns the list of blacklisted files. */ - const StringArray& getBlacklistedFiles() const; - - /** Adds a plugin ID to the black-list. */ - void addToBlacklist (const String& pluginID); - - /** Removes a plugin ID from the black-list. */ - void removeFromBlacklist (const String& pluginID); - - /** Clears all the blacklisted files. */ - void clearBlacklistedFiles(); - - //============================================================================== - /** Sort methods used to change the order of the plugins in the list. - */ - enum SortMethod - { - defaultOrder = 0, - sortAlphabetically, - sortByCategory, - sortByManufacturer, - sortByFormat, - sortByFileSystemLocation, - sortByInfoUpdateTime - }; - - //============================================================================== - /** Adds all the plugin types to a popup menu so that the user can select one. - - Depending on the sort method, it may add sub-menus for categories, - manufacturers, etc. - - Use getIndexChosenByMenu() to find out the type that was chosen. - */ - void addToMenu (PopupMenu& menu, SortMethod sortMethod, - const String& currentlyTickedPluginID = String()) const; - - /** Converts a menu item index that has been chosen into its index in this list. - Returns -1 if it's not an ID that was used. - @see addToMenu - */ - int getIndexChosenByMenu (int menuResultCode) const; - - //============================================================================== - /** Sorts the list. */ - void sort (SortMethod method, bool forwards); - - //============================================================================== - /** Creates some XML that can be used to store the state of this list. */ - XmlElement* createXml() const; - - /** Recreates the state of this list from its stored XML format. */ - void recreateFromXml (const XmlElement& xml); - - //============================================================================== - /** A structure that recursively holds a tree of plugins. - @see KnownPluginList::createTree() - */ - struct PluginTree - { - String folder; /**< The name of this folder in the tree */ - OwnedArray subFolders; - Array plugins; - }; - - /** Creates a PluginTree object containing all the known plugins. */ - PluginTree* createTree (const SortMethod sortMethod) const; - - //============================================================================== - class CustomScanner - { - public: - CustomScanner(); - virtual ~CustomScanner(); - - /** Attempts to load the given file and find a list of plugins in it. - @returns true if the plugin loaded, false if it crashed - */ - virtual bool findPluginTypesFor (AudioPluginFormat& format, - OwnedArray & result, - const String& fileOrIdentifier) = 0; - - /** Called when a scan has finished, to allow clean-up of resources. */ - virtual void scanFinished(); - - /** Returns true if the current scan should be abandoned. - Any blocking methods should check this value repeatedly and return if - if becomes true. - */ - bool shouldExit() const noexcept; - }; - - /** Supplies a custom scanner to be used in future scans. - The KnownPluginList will take ownership of the object passed in. - */ - void setCustomScanner (CustomScanner*); - -private: - //============================================================================== - OwnedArray types; - StringArray blacklist; - ScopedPointer scanner; - CriticalSection scanLock, typesArrayLock; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownPluginList) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp b/source/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp deleted file mode 100644 index 1c68861b6..000000000 --- a/source/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -static StringArray readDeadMansPedalFile (const File& file) -{ - StringArray lines; - file.readLines (lines); - lines.removeEmptyStrings(); - return lines; -} - -PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, - AudioPluginFormat& formatToLookFor, - FileSearchPath directoriesToSearch, - const bool recursive, - const File& deadMansPedal, - bool allowPluginsWhichRequireAsynchronousInstantiation) - : list (listToAddTo), - format (formatToLookFor), - deadMansPedalFile (deadMansPedal), - allowAsync (allowPluginsWhichRequireAsynchronousInstantiation) -{ - directoriesToSearch.removeRedundantPaths(); - - filesOrIdentifiersToScan = format.searchPathsForPlugins (directoriesToSearch, recursive, allowAsync); - - // If any plugins have crashed recently when being loaded, move them to the - // end of the list to give the others a chance to load correctly.. - for (auto& crashed : readDeadMansPedalFile (deadMansPedalFile)) - for (int j = filesOrIdentifiersToScan.size(); --j >= 0;) - if (crashed == filesOrIdentifiersToScan[j]) - filesOrIdentifiersToScan.move (j, -1); - - applyBlacklistingsFromDeadMansPedal (listToAddTo, deadMansPedalFile); - nextIndex.set (filesOrIdentifiersToScan.size()); -} - -PluginDirectoryScanner::~PluginDirectoryScanner() -{ - list.scanFinished(); -} - -//============================================================================== -String PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const -{ - return format.getNameOfPluginFromIdentifier (filesOrIdentifiersToScan [nextIndex.get() - 1]); -} - -void PluginDirectoryScanner::updateProgress() -{ - progress = (1.0f - nextIndex.get() / (float) filesOrIdentifiersToScan.size()); -} - -bool PluginDirectoryScanner::scanNextFile (bool dontRescanIfAlreadyInList, - String& nameOfPluginBeingScanned) -{ - const int index = --nextIndex; - - if (index >= 0) - { - auto file = filesOrIdentifiersToScan [index]; - - if (file.isNotEmpty() && ! (dontRescanIfAlreadyInList && list.isListingUpToDate (file, format))) - { - nameOfPluginBeingScanned = format.getNameOfPluginFromIdentifier (file); - - OwnedArray typesFound; - - // Add this plugin to the end of the dead-man's pedal list in case it crashes... - auto crashedPlugins = readDeadMansPedalFile (deadMansPedalFile); - crashedPlugins.removeString (file); - crashedPlugins.add (file); - setDeadMansPedalFile (crashedPlugins); - - list.scanAndAddFile (file, dontRescanIfAlreadyInList, typesFound, format); - - // Managed to load without crashing, so remove it from the dead-man's-pedal.. - crashedPlugins.removeString (file); - setDeadMansPedalFile (crashedPlugins); - - if (typesFound.size() == 0 && ! list.getBlacklistedFiles().contains (file)) - failedFiles.add (file); - } - } - - updateProgress(); - return index > 0; -} - -bool PluginDirectoryScanner::skipNextFile() -{ - updateProgress(); - return --nextIndex > 0; -} - -void PluginDirectoryScanner::setDeadMansPedalFile (const StringArray& newContents) -{ - if (deadMansPedalFile.getFullPathName().isNotEmpty()) - deadMansPedalFile.replaceWithText (newContents.joinIntoString ("\n"), true, true); -} - -void PluginDirectoryScanner::applyBlacklistingsFromDeadMansPedal (KnownPluginList& list, const File& file) -{ - // If any plugins have crashed recently when being loaded, move them to the - // end of the list to give the others a chance to load correctly.. - for (auto& crashedPlugin : readDeadMansPedalFile (file)) - list.addToBlacklist (crashedPlugin); -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h b/source/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h deleted file mode 100644 index 200835a1e..000000000 --- a/source/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - Scans a directory for plugins, and adds them to a KnownPluginList. - - To use one of these, create it and call scanNextFile() repeatedly, until - it returns false. -*/ -class JUCE_API PluginDirectoryScanner -{ -public: - //============================================================================== - /** - Creates a scanner. - - @param listToAddResultsTo this will get the new types added to it. - @param formatToLookFor this is the type of format that you want to look for - @param directoriesToSearch the path to search - @param searchRecursively true to search recursively - @param deadMansPedalFile if this isn't File(), then it will be used as a file - to store the names of any plugins that crash during - initialisation. If there are any plugins listed in it, - then these will always be scanned after all other possible - files have been tried - in this way, even if there's a few - dodgy plugins in your path, then a couple of rescans - will still manage to find all the proper plugins. - It's probably best to choose a file in the user's - application data directory (alongside your app's - settings file) for this. The file format it uses - is just a list of filenames of the modules that - failed. - @param allowPluginsWhichRequireAsynchronousInstantiation - If this is false then the scanner will exclude plug-ins - asynchronous creation - such as AUv3 plug-ins. - */ - PluginDirectoryScanner (KnownPluginList& listToAddResultsTo, - AudioPluginFormat& formatToLookFor, - FileSearchPath directoriesToSearch, - bool searchRecursively, - const File& deadMansPedalFile, - bool allowPluginsWhichRequireAsynchronousInstantiation = false); - - /** Destructor. */ - ~PluginDirectoryScanner(); - - //============================================================================== - /** Tries the next likely-looking file. - - If dontRescanIfAlreadyInList is true, then the file will only be loaded and - re-tested if it's not already in the list, or if the file's modification - time has changed since the list was created. If dontRescanIfAlreadyInList is - false, the file will always be reloaded and tested. - The nameOfPluginBeingScanned will be updated to the name of the plugin being - scanned before the scan starts. - - Returns false when there are no more files to try. - */ - bool scanNextFile (bool dontRescanIfAlreadyInList, - String& nameOfPluginBeingScanned); - - /** Skips over the next file without scanning it. - Returns false when there are no more files to try. - */ - bool skipNextFile(); - - /** Returns the description of the plugin that will be scanned during the next - call to scanNextFile(). - - This is handy if you want to show the user which file is currently getting - scanned. - */ - String getNextPluginFileThatWillBeScanned() const; - - /** Returns the estimated progress, between 0 and 1. */ - float getProgress() const { return progress; } - - /** This returns a list of all the filenames of things that looked like being - a plugin file, but which failed to open for some reason. - */ - const StringArray& getFailedFiles() const noexcept { return failedFiles; } - - /** Reads the given dead-mans-pedal file and applies its contents to the list. */ - static void applyBlacklistingsFromDeadMansPedal (KnownPluginList& listToApplyTo, - const File& deadMansPedalFile); - -private: - //============================================================================== - KnownPluginList& list; - AudioPluginFormat& format; - StringArray filesOrIdentifiersToScan; - File deadMansPedalFile; - StringArray failedFiles; - Atomic nextIndex; - float progress = 0; - const bool allowAsync; - - void updateProgress(); - void setDeadMansPedalFile (const StringArray& newContents); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginDirectoryScanner) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp b/source/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp deleted file mode 100644 index 733842ffb..000000000 --- a/source/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp +++ /dev/null @@ -1,593 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -class PluginListComponent::TableModel : public TableListBoxModel -{ -public: - TableModel (PluginListComponent& c, KnownPluginList& l) : owner (c), list (l) {} - - int getNumRows() override - { - return list.getNumTypes() + list.getBlacklistedFiles().size(); - } - - void paintRowBackground (Graphics& g, int /*rowNumber*/, int /*width*/, int /*height*/, bool rowIsSelected) override - { - const auto defaultColour = owner.findColour (ListBox::backgroundColourId); - const auto c = rowIsSelected ? defaultColour.interpolatedWith (owner.findColour (ListBox::textColourId), 0.5f) - : defaultColour; - - g.fillAll (c); - } - - enum - { - nameCol = 1, - typeCol = 2, - categoryCol = 3, - manufacturerCol = 4, - descCol = 5 - }; - - void paintCell (Graphics& g, int row, int columnId, int width, int height, bool /*rowIsSelected*/) override - { - String text; - bool isBlacklisted = row >= list.getNumTypes(); - - if (isBlacklisted) - { - if (columnId == nameCol) - text = list.getBlacklistedFiles() [row - list.getNumTypes()]; - else if (columnId == descCol) - text = TRANS("Deactivated after failing to initialise correctly"); - } - else if (const PluginDescription* const desc = list.getType (row)) - { - switch (columnId) - { - case nameCol: text = desc->name; break; - case typeCol: text = desc->pluginFormatName; break; - case categoryCol: text = desc->category.isNotEmpty() ? desc->category : "-"; break; - case manufacturerCol: text = desc->manufacturerName; break; - case descCol: text = getPluginDescription (*desc); break; - - default: jassertfalse; break; - } - } - - if (text.isNotEmpty()) - { - const auto defaultTextColour = owner.findColour (ListBox::textColourId); - g.setColour (isBlacklisted ? Colours::red - : columnId == nameCol ? defaultTextColour - : defaultTextColour.interpolatedWith (Colours::transparentBlack, 0.3f)); - g.setFont (Font (height * 0.7f, Font::bold)); - g.drawFittedText (text, 4, 0, width - 6, height, Justification::centredLeft, 1, 0.9f); - } - } - - void deleteKeyPressed (int) override - { - owner.removeSelectedPlugins(); - } - - void sortOrderChanged (int newSortColumnId, bool isForwards) override - { - switch (newSortColumnId) - { - case nameCol: list.sort (KnownPluginList::sortAlphabetically, isForwards); break; - case typeCol: list.sort (KnownPluginList::sortByFormat, isForwards); break; - case categoryCol: list.sort (KnownPluginList::sortByCategory, isForwards); break; - case manufacturerCol: list.sort (KnownPluginList::sortByManufacturer, isForwards); break; - case descCol: break; - - default: jassertfalse; break; - } - } - - static String getPluginDescription (const PluginDescription& desc) - { - StringArray items; - - if (desc.descriptiveName != desc.name) - items.add (desc.descriptiveName); - - items.add (desc.version); - - items.removeEmptyStrings(); - return items.joinIntoString (" - "); - } - - PluginListComponent& owner; - KnownPluginList& list; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TableModel) -}; - -//============================================================================== -PluginListComponent::PluginListComponent (AudioPluginFormatManager& manager, KnownPluginList& listToEdit, - const File& deadMansPedal, PropertiesFile* const props, - bool allowPluginsWhichRequireAsynchronousInstantiation) - : formatManager (manager), - list (listToEdit), - deadMansPedalFile (deadMansPedal), - optionsButton ("Options..."), - propertiesToUse (props), - allowAsync (allowPluginsWhichRequireAsynchronousInstantiation), - numThreads (allowAsync ? 1 : 0) -{ - tableModel = new TableModel (*this, listToEdit); - - TableHeaderComponent& header = table.getHeader(); - - header.addColumn (TRANS("Name"), TableModel::nameCol, 200, 100, 700, TableHeaderComponent::defaultFlags | TableHeaderComponent::sortedForwards); - header.addColumn (TRANS("Format"), TableModel::typeCol, 80, 80, 80, TableHeaderComponent::notResizable); - header.addColumn (TRANS("Category"), TableModel::categoryCol, 100, 100, 200); - header.addColumn (TRANS("Manufacturer"), TableModel::manufacturerCol, 200, 100, 300); - header.addColumn (TRANS("Description"), TableModel::descCol, 300, 100, 500, TableHeaderComponent::notSortable); - - table.setHeaderHeight (22); - table.setRowHeight (20); - table.setModel (tableModel); - table.setMultipleSelectionEnabled (true); - addAndMakeVisible (table); - - addAndMakeVisible (optionsButton); - optionsButton.addListener (this); - optionsButton.setTriggeredOnMouseDown (true); - - setSize (400, 600); - list.addChangeListener (this); - updateList(); - table.getHeader().reSortTable(); - - PluginDirectoryScanner::applyBlacklistingsFromDeadMansPedal (list, deadMansPedalFile); - deadMansPedalFile.deleteFile(); -} - -PluginListComponent::~PluginListComponent() -{ - list.removeChangeListener (this); -} - -void PluginListComponent::setOptionsButtonText (const String& newText) -{ - optionsButton.setButtonText (newText); - resized(); -} - -void PluginListComponent::setScanDialogText (const String& title, const String& content) -{ - dialogTitle = title; - dialogText = content; -} - -void PluginListComponent::setNumberOfThreadsForScanning (int num) -{ - numThreads = num; -} - -void PluginListComponent::resized() -{ - Rectangle r (getLocalBounds().reduced (2)); - - optionsButton.setBounds (r.removeFromBottom (24)); - optionsButton.changeWidthToFitText (24); - - r.removeFromBottom (3); - table.setBounds (r); -} - -void PluginListComponent::changeListenerCallback (ChangeBroadcaster*) -{ - table.getHeader().reSortTable(); - updateList(); -} - -void PluginListComponent::updateList() -{ - table.updateContent(); - table.repaint(); -} - -void PluginListComponent::removeSelectedPlugins() -{ - const SparseSet selected (table.getSelectedRows()); - - for (int i = table.getNumRows(); --i >= 0;) - if (selected.contains (i)) - removePluginItem (i); -} - -void PluginListComponent::setTableModel (TableListBoxModel* model) -{ - table.setModel (nullptr); - tableModel = model; - table.setModel (tableModel); - - table.getHeader().reSortTable(); - table.updateContent(); - table.repaint(); -} - -bool PluginListComponent::canShowSelectedFolder() const -{ - if (const PluginDescription* const desc = list.getType (table.getSelectedRow())) - return File::createFileWithoutCheckingPath (desc->fileOrIdentifier).exists(); - - return false; -} - -void PluginListComponent::showSelectedFolder() -{ - if (canShowSelectedFolder()) - if (const PluginDescription* const desc = list.getType (table.getSelectedRow())) - File (desc->fileOrIdentifier).getParentDirectory().startAsProcess(); -} - -void PluginListComponent::removeMissingPlugins() -{ - for (int i = list.getNumTypes(); --i >= 0;) - if (! formatManager.doesPluginStillExist (*list.getType (i))) - list.removeType (i); -} - -void PluginListComponent::removePluginItem (int index) -{ - if (index < list.getNumTypes()) - list.removeType (index); - else - list.removeFromBlacklist (list.getBlacklistedFiles() [index - list.getNumTypes()]); -} - -void PluginListComponent::optionsMenuStaticCallback (int result, PluginListComponent* pluginList) -{ - if (pluginList != nullptr) - pluginList->optionsMenuCallback (result); -} - -void PluginListComponent::optionsMenuCallback (int result) -{ - switch (result) - { - case 0: break; - case 1: list.clear(); break; - case 2: removeSelectedPlugins(); break; - case 3: showSelectedFolder(); break; - case 4: removeMissingPlugins(); break; - - default: - if (AudioPluginFormat* format = formatManager.getFormat (result - 10)) - scanFor (*format); - - break; - } -} - -void PluginListComponent::buttonClicked (Button* button) -{ - if (button == &optionsButton) - { - PopupMenu menu; - menu.addItem (1, TRANS("Clear list")); - menu.addItem (2, TRANS("Remove selected plug-in from list"), table.getNumSelectedRows() > 0); - menu.addItem (3, TRANS("Show folder containing selected plug-in"), canShowSelectedFolder()); - menu.addItem (4, TRANS("Remove any plug-ins whose files no longer exist")); - menu.addSeparator(); - - for (int i = 0; i < formatManager.getNumFormats(); ++i) - { - AudioPluginFormat* const format = formatManager.getFormat (i); - - if (format->canScanForPlugins()) - menu.addItem (10 + i, "Scan for new or updated " + format->getName() + " plug-ins"); - } - - menu.showMenuAsync (PopupMenu::Options().withTargetComponent (&optionsButton), - ModalCallbackFunction::forComponent (optionsMenuStaticCallback, this)); - } -} - -bool PluginListComponent::isInterestedInFileDrag (const StringArray& /*files*/) -{ - return true; -} - -void PluginListComponent::filesDropped (const StringArray& files, int, int) -{ - OwnedArray typesFound; - list.scanAndAddDragAndDroppedFiles (formatManager, files, typesFound); -} - -FileSearchPath PluginListComponent::getLastSearchPath (PropertiesFile& properties, AudioPluginFormat& format) -{ - return FileSearchPath (properties.getValue ("lastPluginScanPath_" + format.getName(), - format.getDefaultLocationsToSearch().toString())); -} - -void PluginListComponent::setLastSearchPath (PropertiesFile& properties, AudioPluginFormat& format, - const FileSearchPath& newPath) -{ - properties.setValue ("lastPluginScanPath_" + format.getName(), newPath.toString()); -} - -//============================================================================== -class PluginListComponent::Scanner : private Timer -{ -public: - Scanner (PluginListComponent& plc, AudioPluginFormat& format, PropertiesFile* properties, - bool allowPluginsWhichRequireAsynchronousInstantiation, int threads, - const String& title, const String& text) - : owner (plc), formatToScan (format), propertiesToUse (properties), - pathChooserWindow (TRANS("Select folders to scan..."), String(), AlertWindow::NoIcon), - progressWindow (title, text, AlertWindow::NoIcon), - progress (0.0), numThreads (threads), allowAsync (allowPluginsWhichRequireAsynchronousInstantiation), - finished (false) - { - FileSearchPath path (formatToScan.getDefaultLocationsToSearch()); - - // You need to use at least one thread when scanning plug-ins asynchronously - jassert (! allowAsync || (numThreads > 0)); - - if (path.getNumPaths() > 0) // if the path is empty, then paths aren't used for this format. - { - #if ! JUCE_IOS - if (propertiesToUse != nullptr) - path = getLastSearchPath (*propertiesToUse, formatToScan); - #endif - - pathList.setSize (500, 300); - pathList.setPath (path); - - pathChooserWindow.addCustomComponent (&pathList); - pathChooserWindow.addButton (TRANS("Scan"), 1, KeyPress (KeyPress::returnKey)); - pathChooserWindow.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); - - pathChooserWindow.enterModalState (true, - ModalCallbackFunction::forComponent (startScanCallback, - &pathChooserWindow, this), - false); - } - else - { - startScan(); - } - } - - ~Scanner() - { - if (pool != nullptr) - { - pool->removeAllJobs (true, 60000); - pool = nullptr; - } - } - -private: - PluginListComponent& owner; - AudioPluginFormat& formatToScan; - PropertiesFile* propertiesToUse; - ScopedPointer scanner; - AlertWindow pathChooserWindow, progressWindow; - FileSearchPathListComponent pathList; - String pluginBeingScanned; - double progress; - int numThreads; - bool allowAsync, finished; - ScopedPointer pool; - - static void startScanCallback (int result, AlertWindow* alert, Scanner* scanner) - { - if (alert != nullptr && scanner != nullptr) - { - if (result != 0) - scanner->warnUserAboutStupidPaths(); - else - scanner->finishedScan(); - } - } - - // Try to dissuade people from to scanning their entire C: drive, or other system folders. - void warnUserAboutStupidPaths() - { - for (int i = 0; i < pathList.getPath().getNumPaths(); ++i) - { - const File f (pathList.getPath()[i]); - - if (isStupidPath (f)) - { - AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, - TRANS("Plugin Scanning"), - TRANS("If you choose to scan folders that contain non-plugin files, " - "then scanning may take a long time, and can cause crashes when " - "attempting to load unsuitable files.") - + newLine - + TRANS ("Are you sure you want to scan the folder \"XYZ\"?") - .replace ("XYZ", f.getFullPathName()), - TRANS ("Scan"), - String(), - nullptr, - ModalCallbackFunction::create (warnAboutStupidPathsCallback, this)); - return; - } - } - - startScan(); - } - - static bool isStupidPath (const File& f) - { - Array roots; - File::findFileSystemRoots (roots); - - if (roots.contains (f)) - return true; - - File::SpecialLocationType pathsThatWouldBeStupidToScan[] - = { File::globalApplicationsDirectory, - File::userHomeDirectory, - File::userDocumentsDirectory, - File::userDesktopDirectory, - File::tempDirectory, - File::userMusicDirectory, - File::userMoviesDirectory, - File::userPicturesDirectory }; - - for (int i = 0; i < numElementsInArray (pathsThatWouldBeStupidToScan); ++i) - { - const File sillyFolder (File::getSpecialLocation (pathsThatWouldBeStupidToScan[i])); - - if (f == sillyFolder || sillyFolder.isAChildOf (f)) - return true; - } - - return false; - } - - static void warnAboutStupidPathsCallback (int result, Scanner* scanner) - { - if (result != 0) - scanner->startScan(); - else - scanner->finishedScan(); - } - - void startScan() - { - pathChooserWindow.setVisible (false); - - scanner = new PluginDirectoryScanner (owner.list, formatToScan, pathList.getPath(), - true, owner.deadMansPedalFile, allowAsync); - - if (propertiesToUse != nullptr) - { - setLastSearchPath (*propertiesToUse, formatToScan, pathList.getPath()); - propertiesToUse->saveIfNeeded(); - } - - progressWindow.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); - progressWindow.addProgressBarComponent (progress); - progressWindow.enterModalState(); - - if (numThreads > 0) - { - pool = new ThreadPool (numThreads); - - for (int i = numThreads; --i >= 0;) - pool->addJob (new ScanJob (*this), true); - } - - startTimer (20); - } - - void finishedScan() - { - owner.scanFinished (scanner != nullptr ? scanner->getFailedFiles() - : StringArray()); - } - - void timerCallback() override - { - if (pool == nullptr) - { - if (doNextScan()) - startTimer (20); - } - - if (! progressWindow.isCurrentlyModal()) - finished = true; - - if (finished) - finishedScan(); - else - progressWindow.setMessage (TRANS("Testing") + ":\n\n" + pluginBeingScanned); - } - - bool doNextScan() - { - if (scanner->scanNextFile (true, pluginBeingScanned)) - { - progress = scanner->getProgress(); - return true; - } - - finished = true; - return false; - } - - struct ScanJob : public ThreadPoolJob - { - ScanJob (Scanner& s) : ThreadPoolJob ("pluginscan"), scanner (s) {} - - JobStatus runJob() - { - while (scanner.doNextScan() && ! shouldExit()) - {} - - return jobHasFinished; - } - - Scanner& scanner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScanJob) - }; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Scanner) -}; - -void PluginListComponent::scanFor (AudioPluginFormat& format) -{ - currentScanner = new Scanner (*this, format, propertiesToUse, allowAsync, numThreads, - dialogTitle.isNotEmpty() ? dialogTitle : TRANS("Scanning for plug-ins..."), - dialogText.isNotEmpty() ? dialogText : TRANS("Searching for all possible plug-in files...")); -} - -bool PluginListComponent::isScanning() const noexcept -{ - return currentScanner != nullptr; -} - -void PluginListComponent::scanFinished (const StringArray& failedFiles) -{ - StringArray shortNames; - - for (int i = 0; i < failedFiles.size(); ++i) - shortNames.add (File::createFileWithoutCheckingPath (failedFiles[i]).getFileName()); - - currentScanner = nullptr; // mustn't delete this before using the failed files array - - if (shortNames.size() > 0) - AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, - TRANS("Scan complete"), - TRANS("Note that the following files appeared to be plugin files, but failed to load correctly") - + ":\n\n" - + shortNames.joinIntoString (", ")); -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/scanning/juce_PluginListComponent.h b/source/modules/juce_audio_processors/scanning/juce_PluginListComponent.h deleted file mode 100644 index df3ec367c..000000000 --- a/source/modules/juce_audio_processors/scanning/juce_PluginListComponent.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -//============================================================================== -/** - A component displaying a list of plugins, with options to scan for them, - add, remove and sort them. -*/ -class JUCE_API PluginListComponent : public Component, - public FileDragAndDropTarget, - private ChangeListener, - private Button::Listener -{ -public: - //============================================================================== - /** - Creates the list component. - - For info about the deadMansPedalFile, see the PluginDirectoryScanner constructor. - The properties file, if supplied, is used to store the user's last search paths. - */ - PluginListComponent (AudioPluginFormatManager& formatManager, - KnownPluginList& listToRepresent, - const File& deadMansPedalFile, - PropertiesFile* propertiesToUse, - bool allowPluginsWhichRequireAsynchronousInstantiation = false); - - /** Destructor. */ - ~PluginListComponent(); - - /** Changes the text in the panel's options button. */ - void setOptionsButtonText (const String& newText); - - /** Changes the text in the progress dialog box that is shown when scanning. */ - void setScanDialogText (const String& textForProgressWindowTitle, - const String& textForProgressWindowDescription); - - /** Sets how many threads to simultaneously scan for plugins. - If this is 0, then all scanning happens on the message thread (this is the default when - allowPluginsWhichRequireAsynchronousInstantiation is false). If - allowPluginsWhichRequireAsynchronousInstantiation is true then numThreads must not - be zero (it is one by default). */ - void setNumberOfThreadsForScanning (int numThreads); - - /** Returns the last search path stored in a given properties file for the specified format. */ - static FileSearchPath getLastSearchPath (PropertiesFile&, AudioPluginFormat&); - - /** Stores a search path in a properties file for the given format. */ - static void setLastSearchPath (PropertiesFile&, AudioPluginFormat&, const FileSearchPath&); - - /** Triggers an asynchronous scan for the given format. */ - void scanFor (AudioPluginFormat&); - - /** Returns true if there's currently a scan in progress. */ - bool isScanning() const noexcept; - - /** Removes the plugins currently selected in the table. */ - void removeSelectedPlugins(); - - /** Sets a custom table model to be used. - This will take ownership of the model and delete it when no longer needed. - */ - void setTableModel (TableListBoxModel* model); - - /** Returns the table used to display the plugin list. */ - TableListBox& getTableListBox() noexcept { return table; } - -private: - //============================================================================== - AudioPluginFormatManager& formatManager; - KnownPluginList& list; - File deadMansPedalFile; - TableListBox table; - TextButton optionsButton; - PropertiesFile* propertiesToUse; - String dialogTitle, dialogText; - bool allowAsync; - int numThreads; - - class TableModel; - ScopedPointer tableModel; - - class Scanner; - friend class Scanner; - friend struct ContainerDeletePolicy; - ScopedPointer currentScanner; - - void scanFinished (const StringArray&); - static void optionsMenuStaticCallback (int, PluginListComponent*); - void optionsMenuCallback (int); - void updateList(); - void showSelectedFolder(); - bool canShowSelectedFolder() const; - void removeMissingPlugins(); - void removePluginItem (int index); - - void resized() override; - bool isInterestedInFileDrag (const StringArray&) override; - void filesDropped (const StringArray&, int, int) override; - void buttonClicked (Button*) override; - void changeListenerCallback (ChangeBroadcaster*) override; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListComponent) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h b/source/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h deleted file mode 100644 index c664ce801..000000000 --- a/source/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -/** - Provides a class of AudioProcessorParameter that can be used as a boolean value. - - @see AudioParameterFloat, AudioParameterInt, AudioParameterChoice -*/ -class JUCE_API AudioParameterBool : public AudioProcessorParameterWithID -{ -public: - /** Creates a AudioParameterBool with an ID and name. - On creation, its value is set to the default value. - */ - AudioParameterBool (const String& parameterID, const String& name, bool defaultValue, - const String& label = String()); - - /** Destructor. */ - ~AudioParameterBool(); - - /** Returns the parameter's current boolean value. */ - bool get() const noexcept { return value >= 0.5f; } - /** Returns the parameter's current boolean value. */ - operator bool() const noexcept { return get(); } - - /** Changes the parameter's current value to a new boolean. */ - AudioParameterBool& operator= (bool newValue); - - -private: - //============================================================================== - float value, defaultValue; - - float getValue() const override; - void setValue (float newValue) override; - float getDefaultValue() const override; - int getNumSteps() const override; - bool isDiscrete() const override; - String getText (float, int) const override; - float getValueForText (const String&) const override; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterBool) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h b/source/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h deleted file mode 100644 index dc711d583..000000000 --- a/source/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -/** - Provides a class of AudioProcessorParameter that can be used to select - an indexed, named choice from a list. - - @see AudioParameterFloat, AudioParameterInt, AudioParameterBool -*/ -class JUCE_API AudioParameterChoice : public AudioProcessorParameterWithID -{ -public: - /** Creates a AudioParameterChoice with an ID, name, and list of items. - On creation, its value is set to the default index. - */ - AudioParameterChoice (const String& parameterID, const String& name, - const StringArray& choices, - int defaultItemIndex, - const String& label = String()); - - /** Destructor. */ - ~AudioParameterChoice(); - - /** Returns the current index of the selected item. */ - int getIndex() const noexcept { return roundToInt (value); } - /** Returns the current index of the selected item. */ - operator int() const noexcept { return getIndex(); } - - /** Returns the name of the currently selected item. */ - String getCurrentChoiceName() const noexcept { return choices[getIndex()]; } - /** Returns the name of the currently selected item. */ - operator String() const noexcept { return getCurrentChoiceName(); } - - /** Changes the selected item to a new index. */ - AudioParameterChoice& operator= (int newValue); - - /** Provides access to the list of choices that this parameter is working with. */ - const StringArray choices; - - -private: - //============================================================================== - float value, defaultValue; - - float getValue() const override; - void setValue (float newValue) override; - float getDefaultValue() const override; - int getNumSteps() const override; - bool isDiscrete() const override; - String getText (float, int) const override; - float getValueForText (const String&) const override; - - int limitRange (int) const noexcept; - float convertTo0to1 (int) const noexcept; - int convertFrom0to1 (float) const noexcept; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterChoice) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h b/source/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h deleted file mode 100644 index c422749ed..000000000 --- a/source/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -/** - A subclass of AudioProcessorParameter that provides an easy way to create a - parameter which maps onto a given NormalisableRange. - - @see AudioParameterInt, AudioParameterBool, AudioParameterChoice -*/ -class JUCE_API AudioParameterFloat : public AudioProcessorParameterWithID -{ -public: - /** Creates a AudioParameterFloat with an ID, name, and range. - On creation, its value is set to the default value. - */ - AudioParameterFloat (const String& parameterID, const String& name, - NormalisableRange normalisableRange, - float defaultValue, - const String& label = String(), - Category category = AudioProcessorParameter::genericParameter); - - /** Creates a AudioParameterFloat with an ID, name, and range. - On creation, its value is set to the default value. - For control over skew factors, you can use the other - constructor and provide a NormalisableRange. - */ - AudioParameterFloat (String parameterID, String name, - float minValue, - float maxValue, - float defaultValue); - - /** Destructor. */ - ~AudioParameterFloat(); - - /** Returns the parameter's current value. */ - float get() const noexcept { return value; } - /** Returns the parameter's current value. */ - operator float() const noexcept { return value; } - - /** Changes the parameter's current value. */ - AudioParameterFloat& operator= (float newValue); - - /** Provides access to the parameter's range. */ - NormalisableRange range; - - -private: - //============================================================================== - float value, defaultValue; - - float getValue() const override; - void setValue (float newValue) override; - float getDefaultValue() const override; - int getNumSteps() const override; - String getText (float, int) const override; - float getValueForText (const String&) const override; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterFloat) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h b/source/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h deleted file mode 100644 index 4c2f02c33..000000000 --- a/source/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -/** - Provides a class of AudioProcessorParameter that can be used as an - integer value with a given range. - - @see AudioParameterFloat, AudioParameterBool, AudioParameterChoice -*/ -class JUCE_API AudioParameterInt : public AudioProcessorParameterWithID -{ -public: - /** Creates an AudioParameterInt with an ID, name, and range. - Note that the min and max range values are inclusive. - On creation, its value is set to the default value. - */ - AudioParameterInt (const String& parameterID, const String& name, - int minValue, int maxValue, - int defaultValue, - const String& label = String()); - - /** Destructor. */ - ~AudioParameterInt(); - - /** Returns the parameter's current value as an integer. */ - int get() const noexcept { return roundToInt (value); } - /** Returns the parameter's current value as an integer. */ - operator int() const noexcept { return get(); } - - /** Changes the parameter's current value to a new integer. - The value passed in will be snapped to the permitted range before being used. - */ - AudioParameterInt& operator= (int newValue); - - /** Returns the parameter's range. */ - Range getRange() const noexcept { return Range (minValue, maxValue); } - - -private: - //============================================================================== - int minValue, maxValue; - float value, defaultValue; - - float getValue() const override; - void setValue (float newValue) override; - float getDefaultValue() const override; - int getNumSteps() const override; - String getText (float, int) const override; - float getValueForText (const String&) const override; - - int limitRange (int) const noexcept; - float convertTo0to1 (int) const noexcept; - int convertFrom0to1 (float) const noexcept; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterInt) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/utilities/juce_AudioProcessorParameterWithID.h b/source/modules/juce_audio_processors/utilities/juce_AudioProcessorParameterWithID.h deleted file mode 100644 index d5d005234..000000000 --- a/source/modules/juce_audio_processors/utilities/juce_AudioProcessorParameterWithID.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -/** - This abstract base class is used by some AudioProcessorParameter helper classes. - - @see AudioParameterFloat, AudioParameterInt, AudioParameterBool, AudioParameterChoice -*/ -class JUCE_API AudioProcessorParameterWithID : public AudioProcessorParameter -{ -public: - /** Creation of this object requires providing a name and ID which will be - constant for its lifetime. - */ - AudioProcessorParameterWithID (const String& parameterID, - const String& name, - const String& label = String(), - Category category = AudioProcessorParameter::genericParameter); - - /** Destructor. */ - ~AudioProcessorParameterWithID(); - - /** Provides access to the parameter's ID string. */ - const String paramID; - - /** Provides access to the parameter's name. */ - const String name; - - /** Provides access to the parameter's label. */ - const String label; - - /** Provides access to the parameter's category. */ - const Category category; - -private: - String getName (int) const override; - String getLabel() const override; - Category getCategory() const override; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameterWithID) -}; - -} // namespace juce diff --git a/source/modules/juce_audio_processors/utilities/juce_AudioProcessorParameters.cpp b/source/modules/juce_audio_processors/utilities/juce_AudioProcessorParameters.cpp deleted file mode 100644 index 88da76bc0..000000000 --- a/source/modules/juce_audio_processors/utilities/juce_AudioProcessorParameters.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -// This file contains the implementations of the various AudioParameter[XYZ] classes.. - - -AudioProcessorParameterWithID::AudioProcessorParameterWithID (const String& idToUse, - const String& nameToUse, - const String& labelToUse, - AudioProcessorParameter::Category categoryToUse) - : paramID (idToUse), name (nameToUse), label (labelToUse), category (categoryToUse) {} -AudioProcessorParameterWithID::~AudioProcessorParameterWithID() {} - -String AudioProcessorParameterWithID::getName (int maximumStringLength) const { return name.substring (0, maximumStringLength); } -String AudioProcessorParameterWithID::getLabel() const { return label; } -AudioProcessorParameter::Category AudioProcessorParameterWithID::getCategory() const { return category; } - - -//============================================================================== -AudioParameterFloat::AudioParameterFloat (const String& idToUse, const String& nameToUse, - NormalisableRange r, float def, - const String& labelToUse, Category categoryToUse) - : AudioProcessorParameterWithID (idToUse, nameToUse, labelToUse, categoryToUse), - range (r), value (def), defaultValue (def) -{ -} - -AudioParameterFloat::AudioParameterFloat (String pid, String nm, float minValue, float maxValue, float def) - : AudioProcessorParameterWithID (pid, nm), range (minValue, maxValue), value (def), defaultValue (def) -{ -} - -AudioParameterFloat::~AudioParameterFloat() {} - -float AudioParameterFloat::getValue() const { return range.convertTo0to1 (value); } -void AudioParameterFloat::setValue (float newValue) { value = range.convertFrom0to1 (newValue); } -float AudioParameterFloat::getDefaultValue() const { return range.convertTo0to1 (defaultValue); } -int AudioParameterFloat::getNumSteps() const { return AudioProcessorParameterWithID::getNumSteps(); } -float AudioParameterFloat::getValueForText (const String& text) const { return range.convertTo0to1 (text.getFloatValue()); } - -String AudioParameterFloat::getText (float v, int length) const -{ - String asText (range.convertFrom0to1 (v), 2); - return length > 0 ? asText.substring (0, length) : asText; -} - -AudioParameterFloat& AudioParameterFloat::operator= (float newValue) -{ - if (value != newValue) - setValueNotifyingHost (range.convertTo0to1 (newValue)); - - return *this; -} - -//============================================================================== -AudioParameterInt::AudioParameterInt (const String& idToUse, const String& nameToUse, - int mn, int mx, int def, - const String& labelToUse) - : AudioProcessorParameterWithID (idToUse, nameToUse, labelToUse), - minValue (mn), maxValue (mx), - value ((float) def), - defaultValue (convertTo0to1 (def)) -{ - jassert (minValue < maxValue); // must have a non-zero range of values! -} - -AudioParameterInt::~AudioParameterInt() {} - -int AudioParameterInt::limitRange (int v) const noexcept { return jlimit (minValue, maxValue, v); } -float AudioParameterInt::convertTo0to1 (int v) const noexcept { return (limitRange (v) - minValue) / (float) (maxValue - minValue); } -int AudioParameterInt::convertFrom0to1 (float v) const noexcept { return limitRange (roundToInt ((v * (float) (maxValue - minValue)) + minValue)); } - -float AudioParameterInt::getValue() const { return convertTo0to1 (roundToInt (value)); } -void AudioParameterInt::setValue (float newValue) { value = (float) convertFrom0to1 (newValue); } -float AudioParameterInt::getDefaultValue() const { return defaultValue; } -int AudioParameterInt::getNumSteps() const { return AudioProcessorParameterWithID::getNumSteps(); } -float AudioParameterInt::getValueForText (const String& text) const { return convertTo0to1 (text.getIntValue()); } -String AudioParameterInt::getText (float v, int /*length*/) const { return String (convertFrom0to1 (v)); } - -AudioParameterInt& AudioParameterInt::operator= (int newValue) -{ - if (get() != newValue) - setValueNotifyingHost (convertTo0to1 (newValue)); - - return *this; -} - - -//============================================================================== -AudioParameterBool::AudioParameterBool (const String& idToUse, const String& nameToUse, - bool def, const String& labelToUse) - : AudioProcessorParameterWithID (idToUse, nameToUse, labelToUse), - value (def ? 1.0f : 0.0f), - defaultValue (value) -{ -} - -AudioParameterBool::~AudioParameterBool() {} - -float AudioParameterBool::getValue() const { return value; } -void AudioParameterBool::setValue (float newValue) { value = newValue; } -float AudioParameterBool::getDefaultValue() const { return defaultValue; } -int AudioParameterBool::getNumSteps() const { return 2; } -bool AudioParameterBool::isDiscrete() const { return true; } -float AudioParameterBool::getValueForText (const String& text) const { return text.getIntValue() != 0 ? 1.0f : 0.0f; } -String AudioParameterBool::getText (float v, int /*length*/) const { return String ((int) (v > 0.5f ? 1 : 0)); } - -AudioParameterBool& AudioParameterBool::operator= (bool newValue) -{ - if (get() != newValue) - setValueNotifyingHost (newValue ? 1.0f : 0.0f); - - return *this; -} - - -//============================================================================== -AudioParameterChoice::AudioParameterChoice (const String& idToUse, const String& nameToUse, - const StringArray& c, int def, const String& labelToUse) - : AudioProcessorParameterWithID (idToUse, nameToUse, labelToUse), choices (c), - value ((float) def), - defaultValue (convertTo0to1 (def)) -{ - jassert (choices.size() > 0); // you must supply an actual set of items to choose from! -} - -AudioParameterChoice::~AudioParameterChoice() {} - -int AudioParameterChoice::limitRange (int v) const noexcept { return jlimit (0, choices.size() - 1, v); } -float AudioParameterChoice::convertTo0to1 (int v) const noexcept { return jlimit (0.0f, 1.0f, (v + 0.5f) / (float) choices.size()); } -int AudioParameterChoice::convertFrom0to1 (float v) const noexcept { return limitRange ((int) (v * (float) choices.size())); } - -float AudioParameterChoice::getValue() const { return convertTo0to1 (roundToInt (value)); } -void AudioParameterChoice::setValue (float newValue) { value = (float) convertFrom0to1 (newValue); } -float AudioParameterChoice::getDefaultValue() const { return defaultValue; } -int AudioParameterChoice::getNumSteps() const { return choices.size(); } -bool AudioParameterChoice::isDiscrete() const { return true; } -float AudioParameterChoice::getValueForText (const String& text) const { return convertTo0to1 (choices.indexOf (text)); } -String AudioParameterChoice::getText (float v, int /*length*/) const { return choices [convertFrom0to1 (v)]; } - -AudioParameterChoice& AudioParameterChoice::operator= (int newValue) -{ - if (getIndex() != newValue) - setValueNotifyingHost (convertTo0to1 (newValue)); - - return *this; -} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp b/source/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp deleted file mode 100644 index 055b1566c..000000000 --- a/source/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -struct AudioProcessorValueTreeState::Parameter : public AudioProcessorParameterWithID, - private ValueTree::Listener -{ - Parameter (AudioProcessorValueTreeState& s, - const String& parameterID, const String& paramName, const String& labelText, - NormalisableRange r, float defaultVal, - std::function valueToText, - std::function textToValue, - bool meta, - bool automatable, - bool discrete) - : AudioProcessorParameterWithID (parameterID, paramName, labelText), - owner (s), valueToTextFunction (valueToText), textToValueFunction (textToValue), - range (r), value (defaultVal), defaultValue (defaultVal), - listenersNeedCalling (true), - isMetaParam (meta), - isAutomatableParam (automatable), - isDiscreteParam (discrete) - { - state.addListener (this); - needsUpdate.set (1); - } - - ~Parameter() - { - // should have detached all callbacks before destroying the parameters! - jassert (listeners.size() <= 1); - } - - float getValue() const override { return range.convertTo0to1 (value); } - float getDefaultValue() const override { return range.convertTo0to1 (defaultValue); } - - float getValueForText (const String& text) const override - { - return range.convertTo0to1 (textToValueFunction != nullptr ? textToValueFunction (text) - : text.getFloatValue()); - } - - String getText (float v, int length) const override - { - return valueToTextFunction != nullptr ? valueToTextFunction (range.convertFrom0to1 (v)) - : AudioProcessorParameter::getText (v, length); - } - - int getNumSteps() const override - { - if (range.interval > 0) - return (static_cast ((range.end - range.start) / range.interval) + 1); - - return AudioProcessor::getDefaultNumParameterSteps(); - } - - void setValue (float newValue) override - { - newValue = range.snapToLegalValue (range.convertFrom0to1 (newValue)); - - if (value != newValue || listenersNeedCalling) - { - value = newValue; - - listeners.call (&AudioProcessorValueTreeState::Listener::parameterChanged, paramID, value); - listenersNeedCalling = false; - - needsUpdate.set (1); - } - } - - void setNewState (const ValueTree& v) - { - state = v; - updateFromValueTree(); - } - - void setUnnormalisedValue (float newUnnormalisedValue) - { - if (value != newUnnormalisedValue) - { - const float newValue = range.convertTo0to1 (newUnnormalisedValue); - setValueNotifyingHost (newValue); - } - } - - void updateFromValueTree() - { - setUnnormalisedValue (state.getProperty (owner.valuePropertyID, defaultValue)); - } - - void copyValueToValueTree() - { - if (state.isValid()) - state.setPropertyExcludingListener (this, owner.valuePropertyID, value, owner.undoManager); - } - - void valueTreePropertyChanged (ValueTree&, const Identifier& property) override - { - if (property == owner.valuePropertyID) - updateFromValueTree(); - } - - void valueTreeChildAdded (ValueTree&, ValueTree&) override {} - void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {} - void valueTreeChildOrderChanged (ValueTree&, int, int) override {} - void valueTreeParentChanged (ValueTree&) override {} - - static Parameter* getParameterForID (AudioProcessor& processor, StringRef paramID) noexcept - { - const int numParams = processor.getParameters().size(); - - for (int i = 0; i < numParams; ++i) - { - AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i); - - // When using this class, you must allow it to manage all the parameters in your AudioProcessor, and - // not add any parameter objects of other types! - jassert (dynamic_cast (ap) != nullptr); - - Parameter* const p = static_cast (ap); - - if (paramID == p->paramID) - return p; - } - - return nullptr; - } - - bool isMetaParameter() const override { return isMetaParam; } - bool isAutomatable() const override { return isAutomatableParam; } - bool isDiscrete() const override { return isDiscreteParam; } - - AudioProcessorValueTreeState& owner; - ValueTree state; - ListenerList listeners; - std::function valueToTextFunction; - std::function textToValueFunction; - NormalisableRange range; - float value, defaultValue; - Atomic needsUpdate; - bool listenersNeedCalling; - const bool isMetaParam, isAutomatableParam, isDiscreteParam; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Parameter) -}; - -//============================================================================== -AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& p, UndoManager* um) - : processor (p), - undoManager (um), - valueType ("PARAM"), - valuePropertyID ("value"), - idPropertyID ("id"), - updatingConnections (false) -{ - startTimerHz (10); - state.addListener (this); -} - -AudioProcessorValueTreeState::~AudioProcessorValueTreeState() {} - -AudioProcessorParameterWithID* AudioProcessorValueTreeState::createAndAddParameter (const String& paramID, const String& paramName, - const String& labelText, NormalisableRange r, - float defaultVal, std::function valueToTextFunction, - std::function textToValueFunction, - bool isMetaParameter, - bool isAutomatableParameter, - bool isDiscreteParameter) -{ - // All parameters must be created before giving this manager a ValueTree state! - jassert (! state.isValid()); - #if ! JUCE_LINUX - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - #endif - - Parameter* p = new Parameter (*this, paramID, paramName, labelText, r, - defaultVal, valueToTextFunction, textToValueFunction, - isMetaParameter, isAutomatableParameter, - isDiscreteParameter); - processor.addParameter (p); - return p; -} - -void AudioProcessorValueTreeState::addParameterListener (StringRef paramID, Listener* listener) -{ - if (Parameter* p = Parameter::getParameterForID (processor, paramID)) - p->listeners.add (listener); -} - -void AudioProcessorValueTreeState::removeParameterListener (StringRef paramID, Listener* listener) -{ - if (Parameter* p = Parameter::getParameterForID (processor, paramID)) - p->listeners.remove (listener); -} - -Value AudioProcessorValueTreeState::getParameterAsValue (StringRef paramID) const -{ - if (Parameter* p = Parameter::getParameterForID (processor, paramID)) - return p->state.getPropertyAsValue (valuePropertyID, undoManager); - - return Value(); -} - -NormalisableRange AudioProcessorValueTreeState::getParameterRange (StringRef paramID) const noexcept -{ - if (Parameter* p = Parameter::getParameterForID (processor, paramID)) - return p->range; - - return NormalisableRange(); -} - -AudioProcessorParameterWithID* AudioProcessorValueTreeState::getParameter (StringRef paramID) const noexcept -{ - return Parameter::getParameterForID (processor, paramID); -} - -float* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept -{ - if (Parameter* p = Parameter::getParameterForID (processor, paramID)) - return &(p->value); - - return nullptr; -} - -ValueTree AudioProcessorValueTreeState::getOrCreateChildValueTree (const String& paramID) -{ - ValueTree v (state.getChildWithProperty (idPropertyID, paramID)); - - if (! v.isValid()) - { - v = ValueTree (valueType); - v.setProperty (idPropertyID, paramID, undoManager); - state.addChild (v, -1, undoManager); - } - - return v; -} - -void AudioProcessorValueTreeState::updateParameterConnectionsToChildTrees() -{ - if (! updatingConnections) - { - ScopedValueSetter svs (updatingConnections, true, false); - - const int numParams = processor.getParameters().size(); - - for (int i = 0; i < numParams; ++i) - { - AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i); - jassert (dynamic_cast (ap) != nullptr); - - Parameter* p = static_cast (ap); - p->setNewState (getOrCreateChildValueTree (p->paramID)); - } - } -} - -void AudioProcessorValueTreeState::valueTreePropertyChanged (ValueTree& tree, const Identifier& property) -{ - if (property == idPropertyID && tree.hasType (valueType) && tree.getParent() == state) - updateParameterConnectionsToChildTrees(); -} - -void AudioProcessorValueTreeState::valueTreeChildAdded (ValueTree& parent, ValueTree& tree) -{ - if (parent == state && tree.hasType (valueType)) - updateParameterConnectionsToChildTrees(); -} - -void AudioProcessorValueTreeState::valueTreeChildRemoved (ValueTree& parent, ValueTree& tree, int) -{ - if (parent == state && tree.hasType (valueType)) - updateParameterConnectionsToChildTrees(); -} - -void AudioProcessorValueTreeState::valueTreeRedirected (ValueTree& v) -{ - if (v == state) - updateParameterConnectionsToChildTrees(); -} - -void AudioProcessorValueTreeState::valueTreeChildOrderChanged (ValueTree&, int, int) {} -void AudioProcessorValueTreeState::valueTreeParentChanged (ValueTree&) {} - -void AudioProcessorValueTreeState::timerCallback() -{ - const int numParams = processor.getParameters().size(); - bool anythingUpdated = false; - - for (int i = 0; i < numParams; ++i) - { - AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i); - jassert (dynamic_cast (ap) != nullptr); - - Parameter* p = static_cast (ap); - - if (p->needsUpdate.compareAndSetBool (0, 1)) - { - p->copyValueToValueTree(); - anythingUpdated = true; - } - } - - startTimer (anythingUpdated ? 1000 / 50 - : jlimit (50, 500, getTimerInterval() + 20)); -} - -AudioProcessorValueTreeState::Listener::Listener() {} -AudioProcessorValueTreeState::Listener::~Listener() {} - -//============================================================================== -struct AttachedControlBase : public AudioProcessorValueTreeState::Listener, - public AsyncUpdater -{ - AttachedControlBase (AudioProcessorValueTreeState& s, const String& p) - : state (s), paramID (p), lastValue (0) - { - state.addParameterListener (paramID, this); - } - - void removeListener() - { - state.removeParameterListener (paramID, this); - } - - void setNewUnnormalisedValue (float newUnnormalisedValue) - { - if (AudioProcessorParameter* p = state.getParameter (paramID)) - { - const float newValue = state.getParameterRange (paramID) - .convertTo0to1 (newUnnormalisedValue); - - if (p->getValue() != newValue) - p->setValueNotifyingHost (newValue); - } - } - - void sendInitialUpdate() - { - if (float* v = state.getRawParameterValue (paramID)) - parameterChanged (paramID, *v); - } - - void parameterChanged (const String&, float newValue) override - { - lastValue = newValue; - - if (MessageManager::getInstance()->isThisTheMessageThread()) - { - cancelPendingUpdate(); - setValue (newValue); - } - else - { - triggerAsyncUpdate(); - } - } - - void beginParameterChange() - { - if (AudioProcessorParameter* p = state.getParameter (paramID)) - p->beginChangeGesture(); - } - - void endParameterChange() - { - if (AudioProcessorParameter* p = state.getParameter (paramID)) - p->endChangeGesture(); - } - - void handleAsyncUpdate() override - { - setValue (lastValue); - } - - virtual void setValue (float) = 0; - - AudioProcessorValueTreeState& state; - String paramID; - float lastValue; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AttachedControlBase) -}; - -//============================================================================== -struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private AttachedControlBase, - private Slider::Listener -{ - Pimpl (AudioProcessorValueTreeState& s, const String& p, Slider& sl) - : AttachedControlBase (s, p), slider (sl), ignoreCallbacks (false) - { - NormalisableRange range (s.getParameterRange (paramID)); - slider.setRange (range.start, range.end, range.interval); - slider.setSkewFactor (range.skew, range.symmetricSkew); - - if (AudioProcessorParameter* param = state.getParameter (paramID)) - slider.setDoubleClickReturnValue (true, range.convertFrom0to1 (param->getDefaultValue())); - - sendInitialUpdate(); - slider.addListener (this); - } - - ~Pimpl() - { - slider.removeListener (this); - removeListener(); - } - - void setValue (float newValue) override - { - const ScopedLock selfCallbackLock (selfCallbackMutex); - - { - ScopedValueSetter svs (ignoreCallbacks, true); - slider.setValue (newValue, sendNotificationSync); - } - } - - void sliderValueChanged (Slider* s) override - { - const ScopedLock selfCallbackLock (selfCallbackMutex); - - if ((! ignoreCallbacks) && (! ModifierKeys::getCurrentModifiers().isRightButtonDown())) - setNewUnnormalisedValue ((float) s->getValue()); - } - - void sliderDragStarted (Slider*) override { beginParameterChange(); } - void sliderDragEnded (Slider*) override { endParameterChange(); } - - Slider& slider; - bool ignoreCallbacks; - CriticalSection selfCallbackMutex; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) -}; - -AudioProcessorValueTreeState::SliderAttachment::SliderAttachment (AudioProcessorValueTreeState& s, const String& p, Slider& sl) - : pimpl (new Pimpl (s, p, sl)) -{ -} - -AudioProcessorValueTreeState::SliderAttachment::~SliderAttachment() {} - -//============================================================================== -struct AudioProcessorValueTreeState::ComboBoxAttachment::Pimpl : private AttachedControlBase, - private ComboBox::Listener -{ - Pimpl (AudioProcessorValueTreeState& s, const String& p, ComboBox& c) - : AttachedControlBase (s, p), combo (c), ignoreCallbacks (false) - { - sendInitialUpdate(); - combo.addListener (this); - } - - ~Pimpl() - { - combo.removeListener (this); - removeListener(); - } - - void setValue (float newValue) override - { - const ScopedLock selfCallbackLock (selfCallbackMutex); - - { - ScopedValueSetter svs (ignoreCallbacks, true); - combo.setSelectedItemIndex (roundToInt (newValue), sendNotificationSync); - } - } - - void comboBoxChanged (ComboBox* comboBox) override - { - const ScopedLock selfCallbackLock (selfCallbackMutex); - - if (! ignoreCallbacks) - { - beginParameterChange(); - setNewUnnormalisedValue ((float) comboBox->getSelectedId() - 1.0f); - endParameterChange(); - } - } - - ComboBox& combo; - bool ignoreCallbacks; - CriticalSection selfCallbackMutex; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) -}; - -AudioProcessorValueTreeState::ComboBoxAttachment::ComboBoxAttachment (AudioProcessorValueTreeState& s, const String& p, ComboBox& c) - : pimpl (new Pimpl (s, p, c)) -{ -} - -AudioProcessorValueTreeState::ComboBoxAttachment::~ComboBoxAttachment() {} - -//============================================================================== -struct AudioProcessorValueTreeState::ButtonAttachment::Pimpl : private AttachedControlBase, - private Button::Listener -{ - Pimpl (AudioProcessorValueTreeState& s, const String& p, Button& b) - : AttachedControlBase (s, p), button (b), ignoreCallbacks (false) - { - sendInitialUpdate(); - button.addListener (this); - } - - ~Pimpl() - { - button.removeListener (this); - removeListener(); - } - - void setValue (float newValue) override - { - const ScopedLock selfCallbackLock (selfCallbackMutex); - - { - ScopedValueSetter svs (ignoreCallbacks, true); - button.setToggleState (newValue >= 0.5f, sendNotificationSync); - } - } - - void buttonClicked (Button* b) override - { - const ScopedLock selfCallbackLock (selfCallbackMutex); - - if (! ignoreCallbacks) - { - beginParameterChange(); - setNewUnnormalisedValue (b->getToggleState() ? 1.0f : 0.0f); - endParameterChange(); - } - } - - Button& button; - bool ignoreCallbacks; - CriticalSection selfCallbackMutex; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) -}; - -AudioProcessorValueTreeState::ButtonAttachment::ButtonAttachment (AudioProcessorValueTreeState& s, const String& p, Button& b) - : pimpl (new Pimpl (s, p, b)) -{ -} - -AudioProcessorValueTreeState::ButtonAttachment::~ButtonAttachment() {} - -} // namespace juce diff --git a/source/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h b/source/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h deleted file mode 100644 index 13ace9595..000000000 --- a/source/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - 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 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-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 -{ - -/** - This class contains a ValueTree which is used to manage an AudioProcessor's entire state. - - It has its own internal class of parameter object which are linked to values - within its ValueTree, and which are each identified by a string ID. - - You can get access to the underlying ValueTree object via the state member variable, - so you can add extra properties to it as necessary. - - It also provides some utility child classes for connecting parameters directly to - GUI controls like sliders. - - To use: - 1) Create an AudioProcessorValueTreeState, and give it some parameters using createAndAddParameter(). - 2) Initialise the state member variable with a type name. -*/ -class JUCE_API AudioProcessorValueTreeState : private Timer, - private ValueTree::Listener -{ -public: - /** Creates a state object for a given processor. - - The UndoManager is optional and can be a nullptr. - After creating your state object, you should add parameters with the - createAndAddParameter() method. Note that each AudioProcessorValueTreeState - should be attached to only one processor, and must have the same lifetime as the - processor, as they will have dependencies on each other. - */ - AudioProcessorValueTreeState (AudioProcessor& processorToConnectTo, - UndoManager* undoManagerToUse); - - /** Destructor. */ - ~AudioProcessorValueTreeState(); - - /** Creates and returns a new parameter object for controlling a parameter - with the given ID. - - Calling this will create and add a special type of AudioProcessorParameter to the - AudioProcessor to which this state is attached. - - @param parameterID A unique string ID for the new parameter - @param parameterName The name that the parameter will return from AudioProcessorParameter::getName() - @param labelText The label that the parameter will return from AudioProcessorParameter::getLabel() - @param valueRange A mapping that will be used to determine the value range which this parameter uses - @param defaultValue A default value for the parameter (in non-normalised units) - @param valueToTextFunction A function that will convert a non-normalised value to a string for the - AudioProcessorParameter::getText() method. This can be nullptr to use the - default implementation - @param textToValueFunction The inverse of valueToTextFunction - @param isMetaParameter Set this value to true if this should be a meta parameter - @param isAutomatableParameter Set this value to false if this parameter should not be automatable - @param isDiscrete Set this value to true to make this parameter take discrete values in a host. - @see AudioProcessorParameter::isDiscrete - - @returns the parameter object that was created - */ - AudioProcessorParameterWithID* createAndAddParameter (const String& parameterID, - const String& parameterName, - const String& labelText, - NormalisableRange valueRange, - float defaultValue, - std::function valueToTextFunction, - std::function textToValueFunction, - bool isMetaParameter = false, - bool isAutomatableParameter = true, - bool isDiscrete = false); - - /** Returns a parameter by its ID string. */ - AudioProcessorParameterWithID* getParameter (StringRef parameterID) const noexcept; - - /** Returns a pointer to a floating point representation of a particular - parameter which a realtime process can read to find out its current value. - */ - float* getRawParameterValue (StringRef parameterID) const noexcept; - - /** A listener class that can be attached to an AudioProcessorValueTreeState. - Use AudioProcessorValueTreeState::addParameterListener() to register a callback. - */ - struct JUCE_API Listener - { - Listener(); - virtual ~Listener(); - - /** This callback method is called by the AudioProcessorValueTreeState when a parameter changes. */ - virtual void parameterChanged (const String& parameterID, float newValue) = 0; - }; - - /** Attaches a callback to one of the parameters, which will be called when the parameter changes. */ - void addParameterListener (StringRef parameterID, Listener* listener); - - /** Removes a callback that was previously added with addParameterCallback(). */ - void removeParameterListener (StringRef parameterID, Listener* listener); - - /** Returns a Value object that can be used to control a particular parameter. */ - Value getParameterAsValue (StringRef parameterID) const; - - /** Returns the range that was set when the given parameter was created. */ - NormalisableRange getParameterRange (StringRef parameterID) const noexcept; - - /** A reference to the processor with which this state is associated. */ - AudioProcessor& processor; - - /** The state of the whole processor. - - This must be initialised after all calls to createAndAddParameter(). - You can replace this with your own ValueTree object, and can add properties and - children to the tree. This class will automatically add children for each of the - parameter objects that are created by createAndAddParameter(). - */ - ValueTree state; - - /** Provides access to the undo manager that this object is using. */ - UndoManager* const undoManager; - - //============================================================================== - /** An object of this class maintains a connection between a Slider and a parameter - in an AudioProcessorValueTreeState. - - During the lifetime of this SliderAttachment object, it keeps the two things in - sync, making it easy to connect a slider to a parameter. When this object is - deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState - and Slider aren't deleted before this object! - */ - class JUCE_API SliderAttachment - { - public: - SliderAttachment (AudioProcessorValueTreeState& stateToControl, - const String& parameterID, - Slider& sliderToControl); - ~SliderAttachment(); - - private: - struct Pimpl; - friend struct ContainerDeletePolicy; - ScopedPointer pimpl; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderAttachment) - }; - - //============================================================================== - /** An object of this class maintains a connection between a ComboBox and a parameter - in an AudioProcessorValueTreeState. - - During the lifetime of this ComboBoxAttachment object, it keeps the two things in - sync, making it easy to connect a combo box to a parameter. When this object is - deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState - and ComboBox aren't deleted before this object! - */ - class JUCE_API ComboBoxAttachment - { - public: - ComboBoxAttachment (AudioProcessorValueTreeState& stateToControl, - const String& parameterID, - ComboBox& comboBoxToControl); - ~ComboBoxAttachment(); - - private: - struct Pimpl; - friend struct ContainerDeletePolicy; - ScopedPointer pimpl; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComboBoxAttachment) - }; - - //============================================================================== - /** An object of this class maintains a connection between a Button and a parameter - in an AudioProcessorValueTreeState. - - During the lifetime of this ButtonAttachment object, it keeps the two things in - sync, making it easy to connect a button to a parameter. When this object is - deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState - and Button aren't deleted before this object! - */ - class JUCE_API ButtonAttachment - { - public: - ButtonAttachment (AudioProcessorValueTreeState& stateToControl, - const String& parameterID, - Button& buttonToControl); - ~ButtonAttachment(); - - private: - struct Pimpl; - friend struct ContainerDeletePolicy; - ScopedPointer pimpl; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonAttachment) - }; - -private: - //============================================================================== - struct Parameter; - friend struct Parameter; - - ValueTree getOrCreateChildValueTree (const String&); - void timerCallback() override; - - void valueTreePropertyChanged (ValueTree&, const Identifier&) override; - void valueTreeChildAdded (ValueTree&, ValueTree&) override; - void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override; - void valueTreeChildOrderChanged (ValueTree&, int, int) override; - void valueTreeParentChanged (ValueTree&) override; - void valueTreeRedirected (ValueTree&) override; - void updateParameterConnectionsToChildTrees(); - - Identifier valueType, valuePropertyID, idPropertyID; - bool updatingConnections; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorValueTreeState) -}; - -} // namespace juce