| @@ -1,131 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../../juce.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| #include "formats/juce_VSTPluginFormat.h" | |||
| #include "formats/juce_AudioUnitPluginFormat.h" | |||
| #include "formats/juce_DirectXPluginFormat.h" | |||
| #include "formats/juce_LADSPAPluginFormat.h" | |||
| //============================================================================== | |||
| AudioPluginFormatManager::AudioPluginFormatManager() throw() | |||
| { | |||
| } | |||
| AudioPluginFormatManager::~AudioPluginFormatManager() throw() | |||
| { | |||
| } | |||
| juce_ImplementSingleton_SingleThreaded (AudioPluginFormatManager); | |||
| //============================================================================== | |||
| void AudioPluginFormatManager::addDefaultFormats() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| // you should only call this method once! | |||
| for (int i = formats.size(); --i >= 0;) | |||
| { | |||
| #if JUCE_PLUGINHOST_VST | |||
| jassert (dynamic_cast <VSTPluginFormat*> (formats[i]) == 0); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_AU && JUCE_MAC | |||
| jassert (dynamic_cast <AudioUnitPluginFormat*> (formats[i]) == 0); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_DX && JUCE_WIN32 | |||
| jassert (dynamic_cast <DirectXPluginFormat*> (formats[i]) == 0); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_LADSPA && JUCE_LINUX | |||
| jassert (dynamic_cast <LADSPAPluginFormat*> (formats[i]) == 0); | |||
| #endif | |||
| } | |||
| #endif | |||
| #if JUCE_PLUGINHOST_VST | |||
| formats.add (new VSTPluginFormat()); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_AU && JUCE_MAC | |||
| formats.add (new AudioUnitPluginFormat()); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_DX && JUCE_WIN32 | |||
| formats.add (new DirectXPluginFormat()); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_LADSPA && JUCE_LINUX | |||
| formats.add (new LADSPAPluginFormat()); | |||
| #endif | |||
| } | |||
| int AudioPluginFormatManager::getNumFormats() throw() | |||
| { | |||
| return formats.size(); | |||
| } | |||
| AudioPluginFormat* AudioPluginFormatManager::getFormat (const int index) throw() | |||
| { | |||
| return formats [index]; | |||
| } | |||
| void AudioPluginFormatManager::addFormat (AudioPluginFormat* const format) throw() | |||
| { | |||
| formats.add (format); | |||
| } | |||
| AudioPluginInstance* AudioPluginFormatManager::createInstance (const PluginDescription& description, | |||
| String& errorMessage) const | |||
| { | |||
| AudioPluginInstance* result = 0; | |||
| for (int i = 0; i < formats.size(); ++i) | |||
| { | |||
| result = formats.getUnchecked(i)->createInstanceFromDescription (*this); | |||
| if (result != 0) | |||
| break; | |||
| } | |||
| if (result == 0) | |||
| { | |||
| if (file != File::nonexistent && ! file.exists()) | |||
| errorMessage = TRANS ("This plug-in file no longer exists"); | |||
| else | |||
| errorMessage = TRANS ("This plug-in failed to load correctly"); | |||
| } | |||
| return result; | |||
| } | |||
| @@ -1,171 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ | |||
| #define __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ | |||
| #include "juce_AudioPluginInstance.h" | |||
| class PluginDescription; | |||
| // XXX temporary place for these flags... | |||
| #define JUCE_PLUGINHOST_VST 1 | |||
| #define JUCE_PLUGINHOST_AU 1 | |||
| //============================================================================== | |||
| /** | |||
| The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc. | |||
| Use the static getNumFormats() and getFormat() calls to find the types | |||
| of format that are available. | |||
| */ | |||
| class AudioPluginFormat | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Destructor. */ | |||
| virtual ~AudioPluginFormat() {} | |||
| //============================================================================== | |||
| /** Returns the format name. | |||
| E.g. "VST", "AudioUnit", etc. | |||
| */ | |||
| virtual const 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 <PluginDescription>& results, | |||
| const File& file) = 0; | |||
| /** Tries to recreate a type from a previously generated PluginDescription. | |||
| @see PluginDescription::createInstance | |||
| */ | |||
| virtual AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc) = 0; | |||
| /** 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 File& file) = 0; | |||
| /** Returns the typical places to look for this kind of plugin. | |||
| Note that if this returns no paths, it means that the format can't be scanned-for | |||
| (i.e. it's an internal format that doesn't live in files) | |||
| */ | |||
| virtual const FileSearchPath getDefaultLocationsToSearch() = 0; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| AudioPluginFormat() throw() {} | |||
| }; | |||
| //============================================================================== | |||
| /** | |||
| This simply maintains a list of known AudioPluginFormats. | |||
| @see AudioPluginFormat | |||
| */ | |||
| class AudioPluginFormatManager : public DeletedAtShutdown | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| AudioPluginFormatManager() throw(); | |||
| /** Destructor. */ | |||
| ~AudioPluginFormatManager() throw(); | |||
| juce_DeclareSingleton_SingleThreaded (AudioPluginFormatManager, false); | |||
| //============================================================================== | |||
| /** 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() throw(); | |||
| /** Returns one of the available formats. | |||
| @see getNumFormats | |||
| */ | |||
| AudioPluginFormat* getFormat (const int index) throw(); | |||
| //============================================================================== | |||
| /** Adds a format to the list. | |||
| The object passed in will be owned and deleted by the manager. | |||
| */ | |||
| void addFormat (AudioPluginFormat* const format) throw(); | |||
| //============================================================================== | |||
| /** 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 0 and leaves a message in the | |||
| errorMessage string. | |||
| */ | |||
| AudioPluginInstance* createInstance (const PluginDescription& description, | |||
| String& errorMessage) const; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| OwnedArray <AudioPluginFormat> formats; | |||
| }; | |||
| #endif // __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ | |||
| @@ -1,45 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #define JUCE_PLUGIN_HOST 1 | |||
| #include "../../../../juce.h" | |||
| #include "juce_AudioPluginInstance.h" | |||
| //============================================================================== | |||
| AudioPluginInstance::AudioPluginInstance() | |||
| { | |||
| } | |||
| AudioPluginInstance::~AudioPluginInstance() | |||
| { | |||
| } | |||
| @@ -1,110 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ | |||
| #define __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ | |||
| //============================================================================== | |||
| /** | |||
| 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. | |||
| @see AudioProcessor, AudioPluginFormat | |||
| */ | |||
| class AudioPluginInstance : public AudioProcessor | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Destructor. | |||
| Make sure that you delete any UI components that belong to this plugin before | |||
| deleting the plugin. | |||
| */ | |||
| virtual ~AudioPluginInstance(); | |||
| //============================================================================== | |||
| /** Returns the plugin's name. */ | |||
| virtual const String getName() const = 0; | |||
| /** Asks the plugin to supply a manufacturer name. */ | |||
| virtual const String getManufacturer() const = 0; | |||
| /** Asks the plugin for its version number. */ | |||
| virtual const String getVersion() const = 0; | |||
| /** Returns true if the plugin is an instrument rather than an effect. */ | |||
| virtual bool isInstrument() const = 0; | |||
| /** Returns a category description for the plugin. | |||
| E.g. "Dynamics", "Reverbs", etc. | |||
| */ | |||
| virtual const String getCategory() const = 0; | |||
| /** Returns the class of plugin to which this belongs. | |||
| E.g. "VST", "AU", etc | |||
| */ | |||
| virtual const String getFormatName() const = 0; | |||
| /** Returns the binary file containing the plugin. | |||
| This is normally the DLL or bundle file. | |||
| */ | |||
| virtual const File getFile() const = 0; | |||
| /** Returns a unique identifier for the plugin. | |||
| (Note that this may not be unique across different plugin formats). | |||
| */ | |||
| virtual int getUID() const = 0; | |||
| //============================================================================== | |||
| /** Returns true if the plugin wants midi messages. */ | |||
| virtual bool acceptsMidi() const = 0; | |||
| /** Returns true if the plugin produces midi messages. */ | |||
| virtual bool producesMidi() const = 0; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| AudioPluginInstance(); | |||
| }; | |||
| #endif // __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ | |||
| @@ -1,425 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../../juce.h" | |||
| #include "juce_KnownPluginList.h" | |||
| //============================================================================== | |||
| KnownPluginList::KnownPluginList() | |||
| { | |||
| } | |||
| KnownPluginList::~KnownPluginList() | |||
| { | |||
| } | |||
| void KnownPluginList::clear() | |||
| { | |||
| if (types.size() > 0) | |||
| { | |||
| types.clear(); | |||
| sendChangeMessage (this); | |||
| } | |||
| } | |||
| PluginDescription* KnownPluginList::getTypeForFile (const File& file) const throw() | |||
| { | |||
| for (int i = 0; i < types.size(); ++i) | |||
| if (types.getUnchecked(i)->file == file) | |||
| return types.getUnchecked(i); | |||
| return 0; | |||
| } | |||
| PluginDescription* KnownPluginList::getTypeForIdentifierString (const String& identifierString) const throw() | |||
| { | |||
| for (int i = 0; i < types.size(); ++i) | |||
| if (types.getUnchecked(i)->createIdentifierString() == identifierString) | |||
| return types.getUnchecked(i); | |||
| return 0; | |||
| } | |||
| bool KnownPluginList::addType (const PluginDescription& type) | |||
| { | |||
| for (int i = types.size(); --i >= 0;) | |||
| { | |||
| if (types.getUnchecked(i)->isDuplicateOf (type)) | |||
| { | |||
| // strange - found a duplicate plugin with different info.. | |||
| jassert (types.getUnchecked(i)->name == type.name); | |||
| jassert (types.getUnchecked(i)->isInstrument == type.isInstrument); | |||
| *types.getUnchecked(i) = type; | |||
| return false; | |||
| } | |||
| } | |||
| types.add (new PluginDescription (type)); | |||
| sendChangeMessage (this); | |||
| return true; | |||
| } | |||
| void KnownPluginList::removeType (const int index) throw() | |||
| { | |||
| types.remove (index); | |||
| sendChangeMessage (this); | |||
| } | |||
| bool KnownPluginList::isListingUpToDate (const File& possiblePluginFile) const throw() | |||
| { | |||
| if (getTypeForFile (possiblePluginFile) == 0) | |||
| return false; | |||
| for (int i = types.size(); --i >= 0;) | |||
| { | |||
| const PluginDescription* const d = types.getUnchecked(i); | |||
| if (d->file == possiblePluginFile | |||
| && d->lastFileModTime != possiblePluginFile.getLastModificationTime()) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile, | |||
| const bool dontRescanIfAlreadyInList, | |||
| OwnedArray <PluginDescription>& typesFound) | |||
| { | |||
| bool addedOne = false; | |||
| if (dontRescanIfAlreadyInList | |||
| && getTypeForFile (possiblePluginFile) != 0) | |||
| { | |||
| bool needsRescanning = false; | |||
| for (int i = types.size(); --i >= 0;) | |||
| { | |||
| const PluginDescription* const d = types.getUnchecked(i); | |||
| if (d->file == possiblePluginFile) | |||
| { | |||
| if (d->lastFileModTime != possiblePluginFile.getLastModificationTime()) | |||
| needsRescanning = true; | |||
| else | |||
| typesFound.add (new PluginDescription (*d)); | |||
| } | |||
| } | |||
| if (! needsRescanning) | |||
| return false; | |||
| } | |||
| for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); | |||
| OwnedArray <PluginDescription> found; | |||
| format->findAllTypesForFile (found, possiblePluginFile); | |||
| for (int i = 0; i < found.size(); ++i) | |||
| { | |||
| PluginDescription* const desc = found.getUnchecked(i); | |||
| jassert (desc != 0); | |||
| if (addType (*desc)) | |||
| addedOne = true; | |||
| typesFound.add (new PluginDescription (*desc)); | |||
| } | |||
| } | |||
| return addedOne; | |||
| } | |||
| void KnownPluginList::scanAndAddDragAndDroppedFiles (const StringArray& files, | |||
| OwnedArray <PluginDescription>& typesFound) | |||
| { | |||
| for (int i = 0; i < files.size(); ++i) | |||
| { | |||
| const File f (files [i]); | |||
| if (! scanAndAddFile (f, true, typesFound)) | |||
| { | |||
| if (f.isDirectory()) | |||
| { | |||
| StringArray s; | |||
| { | |||
| OwnedArray <File> subFiles; | |||
| f.findChildFiles (subFiles, File::findFilesAndDirectories, false); | |||
| for (int j = 0; j < subFiles.size(); ++j) | |||
| s.add (subFiles.getUnchecked (j)->getFullPathName()); | |||
| } | |||
| scanAndAddDragAndDroppedFiles (s, typesFound); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| //============================================================================== | |||
| class PluginSorter | |||
| { | |||
| public: | |||
| KnownPluginList::SortMethod method; | |||
| PluginSorter() throw() {} | |||
| int compareElements (const PluginDescription* const first, | |||
| const PluginDescription* const second) const throw() | |||
| { | |||
| int diff = 0; | |||
| if (method == KnownPluginList::sortByCategory) | |||
| diff = first->category.compareLexicographically (second->category); | |||
| else if (method == KnownPluginList::sortByManufacturer) | |||
| diff = first->manufacturerName.compareLexicographically (second->manufacturerName); | |||
| else if (method == KnownPluginList::sortByFileSystemLocation) | |||
| diff = first->file.getParentDirectory().getFullPathName().compare (second->file.getParentDirectory().getFullPathName()); | |||
| if (diff == 0) | |||
| diff = first->name.compareLexicographically (second->name); | |||
| return diff; | |||
| } | |||
| }; | |||
| void KnownPluginList::sort (const SortMethod method) | |||
| { | |||
| if (method != defaultOrder) | |||
| { | |||
| PluginSorter sorter; | |||
| sorter.method = method; | |||
| types.sort (sorter, true); | |||
| sendChangeMessage (this); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| XmlElement* KnownPluginList::createXml() const | |||
| { | |||
| XmlElement* const e = new XmlElement (T("KNOWNPLUGINS")); | |||
| for (int i = 0; i < types.size(); ++i) | |||
| e->addChildElement (types.getUnchecked(i)->createXml()); | |||
| return e; | |||
| } | |||
| void KnownPluginList::recreateFromXml (const XmlElement& xml) | |||
| { | |||
| clear(); | |||
| if (xml.hasTagName (T("KNOWNPLUGINS"))) | |||
| { | |||
| forEachXmlChildElement (xml, e) | |||
| { | |||
| PluginDescription info; | |||
| if (info.loadFromXml (*e)) | |||
| addType (info); | |||
| } | |||
| } | |||
| } | |||
| //============================================================================== | |||
| const int menuIdBase = 0x324503f4; | |||
| // This is used to turn a bunch of paths into a nested menu structure. | |||
| struct PluginFilesystemTree | |||
| { | |||
| private: | |||
| String folder; | |||
| OwnedArray <PluginFilesystemTree> subFolders; | |||
| Array <PluginDescription*> plugins; | |||
| void addPlugin (PluginDescription* const pd, const String& path) | |||
| { | |||
| if (path.isEmpty()) | |||
| { | |||
| plugins.add (pd); | |||
| } | |||
| else | |||
| { | |||
| const String firstSubFolder (path.upToFirstOccurrenceOf (T("/"), false, false)); | |||
| const String remainingPath (path.fromFirstOccurrenceOf (T("/"), false, false)); | |||
| for (int i = subFolders.size(); --i >= 0;) | |||
| { | |||
| if (subFolders.getUnchecked(i)->folder.equalsIgnoreCase (firstSubFolder)) | |||
| { | |||
| subFolders.getUnchecked(i)->addPlugin (pd, remainingPath); | |||
| return; | |||
| } | |||
| } | |||
| PluginFilesystemTree* const newFolder = new PluginFilesystemTree(); | |||
| newFolder->folder = firstSubFolder; | |||
| subFolders.add (newFolder); | |||
| newFolder->addPlugin (pd, remainingPath); | |||
| } | |||
| } | |||
| // removes any deeply nested folders that don't contain any actual plugins | |||
| void optimise() | |||
| { | |||
| for (int i = subFolders.size(); --i >= 0;) | |||
| { | |||
| PluginFilesystemTree* const sub = subFolders.getUnchecked(i); | |||
| sub->optimise(); | |||
| if (sub->plugins.size() == 0) | |||
| { | |||
| for (int j = 0; j < sub->subFolders.size(); ++j) | |||
| subFolders.add (sub->subFolders.getUnchecked(j)); | |||
| sub->subFolders.clear (false); | |||
| subFolders.remove (i); | |||
| } | |||
| } | |||
| } | |||
| public: | |||
| void buildTree (const Array <PluginDescription*>& allPlugins) | |||
| { | |||
| for (int i = 0; i < allPlugins.size(); ++i) | |||
| { | |||
| String path (allPlugins.getUnchecked(i)->file.getParentDirectory().getFullPathName()); | |||
| if (path.substring (1, 2) == T(":")) | |||
| path = path.substring (2); | |||
| path = path.replaceCharacter (T('\\'), T('/')); | |||
| addPlugin (allPlugins.getUnchecked(i), path); | |||
| } | |||
| optimise(); | |||
| } | |||
| void addToMenu (PopupMenu& m, const OwnedArray <PluginDescription>& allPlugins) const | |||
| { | |||
| int i; | |||
| for (i = 0; i < subFolders.size(); ++i) | |||
| { | |||
| const PluginFilesystemTree* const sub = subFolders.getUnchecked(i); | |||
| PopupMenu subMenu; | |||
| sub->addToMenu (subMenu, allPlugins); | |||
| m.addSubMenu (sub->folder, subMenu); | |||
| } | |||
| for (i = 0; i < plugins.size(); ++i) | |||
| { | |||
| PluginDescription* const plugin = plugins.getUnchecked(i); | |||
| m.addItem (allPlugins.indexOf (plugin) + menuIdBase, | |||
| plugin->name, true, false); | |||
| } | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| void KnownPluginList::addToMenu (PopupMenu& menu, const SortMethod sortMethod) const | |||
| { | |||
| Array <PluginDescription*> sorted; | |||
| { | |||
| PluginSorter sorter; | |||
| sorter.method = sortMethod; | |||
| for (int i = 0; i < types.size(); ++i) | |||
| sorted.addSorted (sorter, types.getUnchecked(i)); | |||
| } | |||
| if (sortMethod == sortByCategory | |||
| || sortMethod == sortByManufacturer) | |||
| { | |||
| String lastSubMenuName; | |||
| PopupMenu sub; | |||
| for (int i = 0; i < sorted.size(); ++i) | |||
| { | |||
| const PluginDescription* const pd = sorted.getUnchecked(i); | |||
| String thisSubMenuName (sortMethod == sortByCategory ? pd->category | |||
| : pd->manufacturerName); | |||
| if (thisSubMenuName.trim().isEmpty()) | |||
| thisSubMenuName = T("Other"); | |||
| if (thisSubMenuName != lastSubMenuName) | |||
| { | |||
| if (sub.getNumItems() > 0) | |||
| { | |||
| menu.addSubMenu (lastSubMenuName, sub); | |||
| sub.clear(); | |||
| } | |||
| lastSubMenuName = thisSubMenuName; | |||
| } | |||
| sub.addItem (types.indexOf (pd) + menuIdBase, pd->name, true, false); | |||
| } | |||
| if (sub.getNumItems() > 0) | |||
| menu.addSubMenu (lastSubMenuName, sub); | |||
| } | |||
| else if (sortMethod == sortByFileSystemLocation) | |||
| { | |||
| PluginFilesystemTree root; | |||
| root.buildTree (sorted); | |||
| root.addToMenu (menu, types); | |||
| } | |||
| else | |||
| { | |||
| for (int i = 0; i < sorted.size(); ++i) | |||
| { | |||
| const PluginDescription* const pd = sorted.getUnchecked(i); | |||
| menu.addItem (types.indexOf (pd) + menuIdBase, pd->name, true, false); | |||
| } | |||
| } | |||
| } | |||
| int KnownPluginList::getIndexChosenByMenu (const int menuResultCode) const | |||
| { | |||
| const int i = menuResultCode - menuIdBase; | |||
| return (((unsigned int) i) < (unsigned int) types.size()) ? i : -1; | |||
| } | |||
| @@ -1,171 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ | |||
| #define __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ | |||
| #include "juce_PluginDescription.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| /** | |||
| 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 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 throw() { return types.size(); } | |||
| /** Returns one of the types. | |||
| @see getNumTypes | |||
| */ | |||
| PluginDescription* getType (const int index) const throw() { return types [index]; } | |||
| /** Looks for a type in the list which comes from this file. | |||
| */ | |||
| PluginDescription* getTypeForFile (const File& file) const throw(); | |||
| /** 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 throw(); | |||
| /** Adds a type manually from its description. */ | |||
| bool addType (const PluginDescription& type); | |||
| /** Removes a type. */ | |||
| void removeType (const int index) throw(); | |||
| /** 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 File& possiblePluginFile, | |||
| const bool dontRescanIfAlreadyInList, | |||
| OwnedArray <PluginDescription>& typesFound); | |||
| /** 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 File& possiblePluginFile) const throw(); | |||
| /** 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 (const StringArray& filenames, | |||
| OwnedArray <PluginDescription>& typesFound); | |||
| //============================================================================== | |||
| /** Sort methods used to change the order of the plugins in the list. | |||
| */ | |||
| enum SortMethod | |||
| { | |||
| defaultOrder = 0, | |||
| sortAlphabetically, | |||
| sortByCategory, | |||
| sortByManufacturer, | |||
| sortByFileSystemLocation | |||
| }; | |||
| //============================================================================== | |||
| /** 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, | |||
| const SortMethod sortMethod) 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 (const int menuResultCode) const; | |||
| //============================================================================== | |||
| /** Sorts the list. */ | |||
| void sort (const SortMethod method); | |||
| //============================================================================== | |||
| /** 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); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| OwnedArray <PluginDescription> types; | |||
| }; | |||
| #endif // __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ | |||
| @@ -1,133 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../../juce.h" | |||
| #include "juce_PluginDescription.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| PluginDescription::PluginDescription() throw() | |||
| : uid (0), | |||
| isInstrument (false), | |||
| numInputChannels (0), | |||
| numOutputChannels (0) | |||
| { | |||
| } | |||
| PluginDescription::~PluginDescription() throw() | |||
| { | |||
| } | |||
| PluginDescription::PluginDescription (const PluginDescription& other) throw() | |||
| : name (other.name), | |||
| pluginFormatName (other.pluginFormatName), | |||
| category (other.category), | |||
| manufacturerName (other.manufacturerName), | |||
| version (other.version), | |||
| file (other.file), | |||
| uid (other.uid), | |||
| isInstrument (other.isInstrument), | |||
| lastFileModTime (other.lastFileModTime), | |||
| numInputChannels (other.numInputChannels), | |||
| numOutputChannels (other.numOutputChannels) | |||
| { | |||
| } | |||
| const PluginDescription& PluginDescription::operator= (const PluginDescription& other) throw() | |||
| { | |||
| name = other.name; | |||
| pluginFormatName = other.pluginFormatName; | |||
| category = other.category; | |||
| manufacturerName = other.manufacturerName; | |||
| version = other.version; | |||
| file = other.file; | |||
| uid = other.uid; | |||
| isInstrument = other.isInstrument; | |||
| lastFileModTime = other.lastFileModTime; | |||
| numInputChannels = other.numInputChannels; | |||
| numOutputChannels = other.numOutputChannels; | |||
| return *this; | |||
| } | |||
| bool PluginDescription::isDuplicateOf (const PluginDescription& other) const | |||
| { | |||
| return file == other.file | |||
| && uid == other.uid; | |||
| } | |||
| const String PluginDescription::createIdentifierString() const throw() | |||
| { | |||
| return pluginFormatName | |||
| + T("/") + pluginName | |||
| + T("/") + String::toHexString (file.getFileName().hashCode()); | |||
| } | |||
| XmlElement* PluginDescription::createXml() const | |||
| { | |||
| XmlElement* const e = new XmlElement (T("PLUGIN")); | |||
| e->setAttribute (T("name"), name); | |||
| e->setAttribute (T("format"), pluginFormatName); | |||
| e->setAttribute (T("category"), category); | |||
| e->setAttribute (T("manufacturer"), manufacturerName); | |||
| e->setAttribute (T("version"), version); | |||
| e->setAttribute (T("file"), file.getFullPathName()); | |||
| e->setAttribute (T("uid"), String::toHexString (uid)); | |||
| e->setAttribute (T("isInstrument"), isInstrument); | |||
| e->setAttribute (T("fileTime"), String::toHexString (lastFileModTime.toMilliseconds())); | |||
| e->setAttribute (T("numInputs"), numInputChannels); | |||
| e->setAttribute (T("numOutputs"), numOutputChannels); | |||
| return e; | |||
| } | |||
| bool PluginDescription::loadFromXml (const XmlElement& xml) | |||
| { | |||
| if (xml.hasTagName (T("PLUGIN"))) | |||
| { | |||
| name = xml.getStringAttribute (T("name")); | |||
| pluginFormatName = xml.getStringAttribute (T("format")); | |||
| category = xml.getStringAttribute (T("category")); | |||
| manufacturerName = xml.getStringAttribute (T("manufacturer")); | |||
| version = xml.getStringAttribute (T("version")); | |||
| file = File (xml.getStringAttribute (T("file"))); | |||
| uid = xml.getStringAttribute (T("uid")).getHexValue32(); | |||
| isInstrument = xml.getBoolAttribute (T("isInstrument"), false); | |||
| lastFileModTime = Time (xml.getStringAttribute (T("fileTime")).getHexValue64()); | |||
| numInputChannels = xml.getIntAttribute (T("numInputs")); | |||
| numOutputChannels = xml.getIntAttribute (T("numOutputs")); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| @@ -1,146 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ | |||
| #define __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ | |||
| #include "juce_AudioPluginInstance.h" | |||
| //============================================================================== | |||
| /** | |||
| A small class to represent some facts about a particular type of plugin. | |||
| This class is for storing and managing the details about a plugin without | |||
| actually having to load an instance of it. | |||
| A KnownPluginList contains a list of PluginDescription objects. | |||
| @see KnownPluginList | |||
| */ | |||
| class PluginDescription | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| PluginDescription() throw(); | |||
| PluginDescription (const PluginDescription& other) throw(); | |||
| const PluginDescription& operator= (const PluginDescription& other) throw(); | |||
| ~PluginDescription() throw(); | |||
| //============================================================================== | |||
| /** The name of the plugin. */ | |||
| String name; | |||
| /** The plugin 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; | |||
| /** The binary module file containing the plugin. */ | |||
| File file; | |||
| /** The last time the plugin file was changed. | |||
| This is handy when scanning for new or changed plugins. | |||
| */ | |||
| Time lastFileModTime; | |||
| /** A unique ID for the plugin. | |||
| 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 plugin identifies itself as a synthesiser. */ | |||
| bool isInstrument; | |||
| /** The number of inputs. */ | |||
| int numInputChannels; | |||
| /** The number of outputs. */ | |||
| int numOutputChannels; | |||
| /** Returns true if the two descriptions refer the the same plugin. | |||
| This isn't quite as simple as them just having the same file (because of | |||
| shell plugins). | |||
| */ | |||
| bool isDuplicateOf (const PluginDescription& other) const; | |||
| //============================================================================== | |||
| /** Fills in this description based on the given plugin. | |||
| Returns true if it worked, false if it couldn't get the info. | |||
| */ | |||
| void fillInFromInstance (AudioPluginInstance& instance) throw(); | |||
| //============================================================================== | |||
| /** 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 plugin description. | |||
| */ | |||
| bool loadFromXml (const XmlElement& xml); | |||
| //============================================================================== | |||
| /** 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 | |||
| plugin's file location, so can be used to store a plugin ID for use | |||
| across different machines. | |||
| */ | |||
| const String createIdentifierString() const throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| }; | |||
| #endif // __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ | |||
| @@ -1,161 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../../juce.h" | |||
| #include "juce_PluginDirectoryScanner.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, | |||
| FileSearchPath directoriesToSearch, | |||
| const bool recursive, | |||
| const File& deadMansPedalFile_) | |||
| : list (listToAddTo), | |||
| deadMansPedalFile (deadMansPedalFile_), | |||
| nextIndex (0), | |||
| progress (0) | |||
| { | |||
| directoriesToSearch.removeRedundantPaths(); | |||
| for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j) | |||
| recursiveFileSearch (directoriesToSearch [j], recursive); | |||
| // 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.. | |||
| const StringArray crashedPlugins (getDeadMansPedalFile()); | |||
| for (int i = 0; i < crashedPlugins.size(); ++i) | |||
| { | |||
| const File f (crashedPlugins[i]); | |||
| for (int j = filesToScan.size(); --j >= 0;) | |||
| if (f == *filesToScan.getUnchecked (j)) | |||
| filesToScan.move (j, -1); | |||
| } | |||
| } | |||
| void PluginDirectoryScanner::recursiveFileSearch (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()) | |||
| { | |||
| const File f (iter.getFile()); | |||
| bool isPlugin = false; | |||
| for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); | |||
| if (format->fileMightContainThisPluginType (f)) | |||
| { | |||
| isPlugin = true; | |||
| filesToScan.add (new File (f)); | |||
| break; | |||
| } | |||
| } | |||
| if (recursive && (! isPlugin) && f.isDirectory()) | |||
| recursiveFileSearch (f, true); | |||
| } | |||
| } | |||
| PluginDirectoryScanner::~PluginDirectoryScanner() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| const File PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const throw() | |||
| { | |||
| File* const file = filesToScan [nextIndex]; | |||
| if (file != 0) | |||
| return *file; | |||
| return File::nonexistent; | |||
| } | |||
| bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList) | |||
| { | |||
| File* const file = filesToScan [nextIndex]; | |||
| if (file != 0) | |||
| { | |||
| if (! list.isListingUpToDate (*file)) | |||
| { | |||
| OwnedArray <PluginDescription> typesFound; | |||
| // Add this plugin to the end of the dead-man's pedal list in case it crashes... | |||
| StringArray crashedPlugins (getDeadMansPedalFile()); | |||
| crashedPlugins.removeString (file->getFullPathName()); | |||
| crashedPlugins.add (file->getFullPathName()); | |||
| setDeadMansPedalFile (crashedPlugins); | |||
| list.scanAndAddFile (*file, | |||
| dontRescanIfAlreadyInList, | |||
| typesFound); | |||
| // Managed to load without crashing, so remove it from the dead-man's-pedal.. | |||
| crashedPlugins.removeString (file->getFullPathName()); | |||
| setDeadMansPedalFile (crashedPlugins); | |||
| if (typesFound.size() == 0) | |||
| failedFiles.add (file->getFullPathName()); | |||
| } | |||
| ++nextIndex; | |||
| progress = nextIndex / (float) filesToScan.size(); | |||
| } | |||
| return nextIndex < filesToScan.size(); | |||
| } | |||
| const StringArray PluginDirectoryScanner::getDeadMansPedalFile() throw() | |||
| { | |||
| StringArray lines; | |||
| if (deadMansPedalFile != File::nonexistent) | |||
| { | |||
| lines.addLines (deadMansPedalFile.loadFileAsString()); | |||
| lines.removeEmptyStrings(); | |||
| } | |||
| return lines; | |||
| } | |||
| void PluginDirectoryScanner::setDeadMansPedalFile (const StringArray& newContents) throw() | |||
| { | |||
| if (deadMansPedalFile != File::nonexistent) | |||
| deadMansPedalFile.replaceWithText (newContents.joinIntoString ("\n"), true, true); | |||
| } | |||
| @@ -1,122 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ | |||
| #define __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ | |||
| #include "juce_KnownPluginList.h" | |||
| //============================================================================== | |||
| /** | |||
| 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 PluginDirectoryScanner | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** | |||
| Creates a scanner. | |||
| @param listToAddResultsTo this will get the new types added to it. | |||
| @param directoriesToSearch the path to search | |||
| @param searchRecursively true to search recursively | |||
| @param deadMansPedalFile if this isn't File::nonexistent, 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. | |||
| */ | |||
| PluginDirectoryScanner (KnownPluginList& listToAddResultsTo, | |||
| FileSearchPath directoriesToSearch, | |||
| const bool searchRecursively, | |||
| const File& deadMansPedalFile); | |||
| /** 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. | |||
| Returns false when there are no more files to try. | |||
| */ | |||
| bool scanNextFile (const bool dontRescanIfAlreadyInList); | |||
| /** Returns the file 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. | |||
| */ | |||
| const File getNextPluginFileThatWillBeScanned() const throw(); | |||
| /** 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 throw() { return failedFiles; } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| KnownPluginList& list; | |||
| OwnedArray <File> filesToScan; | |||
| File deadMansPedalFile; | |||
| StringArray failedFiles; | |||
| int nextIndex; | |||
| float progress; | |||
| void recursiveFileSearch (const File& dir, const bool recursive); | |||
| const StringArray getDeadMansPedalFile() throw(); | |||
| void setDeadMansPedalFile (const StringArray& newContents) throw(); | |||
| }; | |||
| #endif // __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ | |||
| @@ -1,296 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../../juce.h" | |||
| #include "juce_PluginListComponent.h" | |||
| #include "juce_PluginDirectoryScanner.h" | |||
| //============================================================================== | |||
| PluginListComponent::PluginListComponent (KnownPluginList& listToEdit, | |||
| const File& deadMansPedalFile_, | |||
| PropertiesFile* const propertiesToUse_) | |||
| : list (listToEdit), | |||
| deadMansPedalFile (deadMansPedalFile_), | |||
| propertiesToUse (propertiesToUse_) | |||
| { | |||
| addAndMakeVisible (listBox = new ListBox (String::empty, this)); | |||
| addAndMakeVisible (optionsButton = new TextButton ("Options...")); | |||
| optionsButton->addButtonListener (this); | |||
| optionsButton->setTriggeredOnMouseDown (true); | |||
| setSize (400, 600); | |||
| list.addChangeListener (this); | |||
| } | |||
| PluginListComponent::~PluginListComponent() | |||
| { | |||
| list.removeChangeListener (this); | |||
| deleteAllChildren(); | |||
| } | |||
| void PluginListComponent::resized() | |||
| { | |||
| listBox->setBounds (0, 0, getWidth(), getHeight() - 30); | |||
| optionsButton->changeWidthToFitText (24); | |||
| optionsButton->setTopLeftPosition (8, getHeight() - 28); | |||
| } | |||
| void PluginListComponent::changeListenerCallback (void*) | |||
| { | |||
| listBox->updateContent(); | |||
| listBox->repaint(); | |||
| } | |||
| int PluginListComponent::getNumRows() | |||
| { | |||
| return list.getNumTypes(); | |||
| } | |||
| void PluginListComponent::paintListBoxItem (int row, | |||
| Graphics& g, | |||
| int width, int height, | |||
| bool rowIsSelected) | |||
| { | |||
| if (rowIsSelected) | |||
| g.fillAll (findColour (TextEditor::highlightColourId)); | |||
| const PluginDescription* const pd = list.getType (row); | |||
| if (pd != 0) | |||
| { | |||
| GlyphArrangement ga; | |||
| ga.addCurtailedLineOfText (Font (height * 0.7f, Font::bold), pd->name, 8.0f, height * 0.8f, width - 10.0f, true); | |||
| g.setColour (Colours::black); | |||
| ga.draw (g); | |||
| float x, y, r, b; | |||
| ga.getBoundingBox (0, -1, x, y, r, b, false); | |||
| String desc; | |||
| desc << pd->pluginFormatName | |||
| << (pd->isInstrument ? " instrument" : " effect") | |||
| << " - " | |||
| << pd->numInputChannels << (pd->numInputChannels == 1 ? " in" : " ins") | |||
| << " / " | |||
| << pd->numOutputChannels << (pd->numOutputChannels == 1 ? " out" : " outs"); | |||
| if (pd->manufacturerName.isNotEmpty()) | |||
| desc << " - " << pd->manufacturerName; | |||
| if (pd->version.isNotEmpty()) | |||
| desc << " - " << pd->version; | |||
| if (pd->category.isNotEmpty()) | |||
| desc << " - category: '" << pd->category << '\''; | |||
| g.setColour (Colours::grey); | |||
| ga.clear(); | |||
| ga.addCurtailedLineOfText (Font (height * 0.6f), desc, r + 10.0f, height * 0.8f, width - r - 12.0f, true); | |||
| ga.draw (g); | |||
| } | |||
| } | |||
| void PluginListComponent::deleteKeyPressed (int lastRowSelected) | |||
| { | |||
| list.removeType (lastRowSelected); | |||
| } | |||
| void PluginListComponent::buttonClicked (Button* b) | |||
| { | |||
| if (optionsButton == b) | |||
| { | |||
| PopupMenu menu; | |||
| menu.addItem (1, TRANS("Clear list")); | |||
| menu.addItem (5, TRANS("Remove selected plugin from list"), listBox->getNumSelectedRows() > 0); | |||
| menu.addItem (6, TRANS("Show folder containing selected plugin"), listBox->getNumSelectedRows() > 0); | |||
| menu.addItem (7, TRANS("Remove any plugins whose files no longer exist")); | |||
| menu.addSeparator(); | |||
| menu.addItem (2, TRANS("Sort alphabetically")); | |||
| menu.addItem (3, TRANS("Sort by category")); | |||
| menu.addItem (4, TRANS("Sort by manufacturer")); | |||
| menu.addSeparator(); | |||
| for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); | |||
| if (format->getDefaultLocationsToSearch().getNumPaths() > 0) | |||
| menu.addItem (10 + i, "Scan for new or updated " + format->getName() + " plugins..."); | |||
| } | |||
| const int r = menu.showAt (optionsButton); | |||
| if (r == 1) | |||
| { | |||
| list.clear(); | |||
| } | |||
| else if (r == 2) | |||
| { | |||
| list.sort (KnownPluginList::sortAlphabetically); | |||
| } | |||
| else if (r == 3) | |||
| { | |||
| list.sort (KnownPluginList::sortByCategory); | |||
| } | |||
| else if (r == 4) | |||
| { | |||
| list.sort (KnownPluginList::sortByManufacturer); | |||
| } | |||
| else if (r == 5) | |||
| { | |||
| const SparseSet <int> selected (listBox->getSelectedRows()); | |||
| for (int i = list.getNumTypes(); --i >= 0;) | |||
| if (selected.contains (i)) | |||
| list.removeType (i); | |||
| } | |||
| else if (r == 6) | |||
| { | |||
| const PluginDescription* const desc = list.getType (listBox->getSelectedRow()); | |||
| if (desc != 0) | |||
| desc->file.getParentDirectory().startAsProcess(); | |||
| } | |||
| else if (r == 7) | |||
| { | |||
| for (int i = list.getNumTypes(); --i >= 0;) | |||
| { | |||
| if (list.getType (i)->file != File::nonexistent | |||
| && ! list.getType (i)->file.exists()) | |||
| { | |||
| list.removeType (i); | |||
| } | |||
| } | |||
| } | |||
| else if (r != 0) | |||
| { | |||
| typeToScan = r - 10; | |||
| startTimer (1); | |||
| } | |||
| } | |||
| } | |||
| void PluginListComponent::timerCallback() | |||
| { | |||
| stopTimer(); | |||
| scanFor (AudioPluginFormatManager::getInstance()->getFormat (typeToScan)); | |||
| } | |||
| bool PluginListComponent::isInterestedInFileDrag (const StringArray& /*files*/) | |||
| { | |||
| return true; | |||
| } | |||
| void PluginListComponent::filesDropped (const StringArray& files, int, int) | |||
| { | |||
| OwnedArray <PluginDescription> typesFound; | |||
| list.scanAndAddDragAndDroppedFiles (files, typesFound); | |||
| } | |||
| void PluginListComponent::scanFor (AudioPluginFormat* format) | |||
| { | |||
| if (format == 0) | |||
| return; | |||
| FileSearchPath path (format->getDefaultLocationsToSearch()); | |||
| if (propertiesToUse != 0) | |||
| path = propertiesToUse->getValue ("lastPluginScanPath_" + format->getName(), path.toString()); | |||
| { | |||
| AlertWindow aw (TRANS("Select folders to scan..."), String::empty, AlertWindow::NoIcon); | |||
| FileSearchPathListComponent pathList; | |||
| pathList.setSize (500, 300); | |||
| pathList.setPath (path); | |||
| aw.addCustomComponent (&pathList); | |||
| aw.addButton (TRANS("Scan"), 1, KeyPress::returnKey); | |||
| aw.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); | |||
| if (aw.runModalLoop() == 0) | |||
| return; | |||
| path = pathList.getPath(); | |||
| } | |||
| if (propertiesToUse != 0) | |||
| { | |||
| propertiesToUse->setValue ("lastPluginScanPath_" + format->getName(), path.toString()); | |||
| propertiesToUse->saveIfNeeded(); | |||
| } | |||
| double progress = 0.0; | |||
| AlertWindow aw (TRANS("Scanning for plugins..."), | |||
| TRANS("Searching for all possible plugin files..."), AlertWindow::NoIcon); | |||
| aw.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); | |||
| aw.addProgressBarComponent (progress); | |||
| aw.enterModalState(); | |||
| MessageManager::getInstance()->dispatchPendingMessages(); | |||
| PluginDirectoryScanner scanner (list, path, true, deadMansPedalFile); | |||
| for (;;) | |||
| { | |||
| aw.setMessage (TRANS("Testing:\n\n") | |||
| + scanner.getNextPluginFileThatWillBeScanned().getFileName()); | |||
| MessageManager::getInstance()->dispatchPendingMessages (500); | |||
| if (! scanner.scanNextFile (true)) | |||
| break; | |||
| if (! aw.isCurrentlyModal()) | |||
| break; | |||
| progress = scanner.getProgress(); | |||
| } | |||
| if (scanner.getFailedFiles().size() > 0) | |||
| { | |||
| StringArray shortNames; | |||
| for (int i = 0; i < scanner.getFailedFiles().size(); ++i) | |||
| shortNames.add (File (scanner.getFailedFiles()[i]).getFileName()); | |||
| AlertWindow::showMessageBox (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 (", ")); | |||
| } | |||
| } | |||
| @@ -1,101 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ | |||
| #define __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ | |||
| #include "juce_KnownPluginList.h" | |||
| #include "juce_AudioPluginFormat.h" | |||
| //============================================================================== | |||
| /** | |||
| A component displaying a list of plugins, with options to scan for them, | |||
| add, remove and sort them. | |||
| */ | |||
| class PluginListComponent : public Component, | |||
| public ListBoxModel, | |||
| public ChangeListener, | |||
| public ButtonListener, | |||
| public Timer | |||
| { | |||
| 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 (KnownPluginList& listToRepresent, | |||
| const File& deadMansPedalFile, | |||
| PropertiesFile* const propertiesToUse); | |||
| /** Destructor. */ | |||
| ~PluginListComponent(); | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void resized(); | |||
| /** @internal */ | |||
| bool isInterestedInFileDrag (const StringArray& files); | |||
| /** @internal */ | |||
| void filesDropped (const StringArray& files, int, int); | |||
| /** @internal */ | |||
| int getNumRows(); | |||
| /** @internal */ | |||
| void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected); | |||
| /** @internal */ | |||
| void deleteKeyPressed (int lastRowSelected); | |||
| /** @internal */ | |||
| void buttonClicked (Button* b); | |||
| /** @internal */ | |||
| void changeListenerCallback (void*); | |||
| /** @internal */ | |||
| void timerCallback(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| KnownPluginList& list; | |||
| File deadMansPedalFile; | |||
| ListBox* listBox; | |||
| TextButton* optionsButton; | |||
| PropertiesFile* propertiesToUse; | |||
| int typeToScan; | |||
| void scanFor (AudioPluginFormat* format); | |||
| }; | |||
| #endif // __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ | |||