diff --git a/docs/JUCE changelist.txt b/docs/JUCE changelist.txt index d111620344..50ec205ec1 100644 --- a/docs/JUCE changelist.txt +++ b/docs/JUCE changelist.txt @@ -7,6 +7,8 @@ Changelist for version 1.46 - new class: ScopedTryLock +- added AudioUnit support to the audio hosting code + ============================================================================== Changelist for version 1.45 diff --git a/extras/audio plugin host/src/host/MainHostWindow.cpp b/extras/audio plugin host/src/host/MainHostWindow.cpp index db6b5c0740..49161de786 100644 --- a/extras/audio plugin host/src/host/MainHostWindow.cpp +++ b/extras/audio plugin host/src/host/MainHostWindow.cpp @@ -233,6 +233,7 @@ const PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const St sortTypeMenu.addItem (201, "List plugins in alphabetical order", true, pluginSortMethod == KnownPluginList::sortAlphabetically); sortTypeMenu.addItem (202, "List plugins by category", true, pluginSortMethod == KnownPluginList::sortByCategory); sortTypeMenu.addItem (203, "List plugins by manufacturer", true, pluginSortMethod == KnownPluginList::sortByManufacturer); + sortTypeMenu.addItem (204, "List plugins based on the directory structure", true, pluginSortMethod == KnownPluginList::sortByFileSystemLocation); menu.addSubMenu ("Plugin menu type", sortTypeMenu); menu.addSeparator(); @@ -273,6 +274,8 @@ void MainHostWindow::menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/ pluginSortMethod = KnownPluginList::sortByCategory; else if (menuItemID == 203) pluginSortMethod = KnownPluginList::sortByManufacturer; + else if (menuItemID == 204) + pluginSortMethod = KnownPluginList::sortByFileSystemLocation; ApplicationProperties::getInstance()->getUserSettings() ->setValue (T("pluginSortMethod"), (int) pluginSortMethod); diff --git a/extras/audio plugin host/src/plugins/formats/juce_VSTPluginFormat.cpp b/extras/audio plugin host/src/plugins/formats/juce_VSTPluginFormat.cpp index 4e7bd23b29..5a051b779a 100644 --- a/extras/audio plugin host/src/plugins/formats/juce_VSTPluginFormat.cpp +++ b/extras/audio plugin host/src/plugins/formats/juce_VSTPluginFormat.cpp @@ -887,7 +887,10 @@ void VSTPluginInstance::initialise() dispatch (effIdentify, 0, 0, 0, 0); - { + // this code would ask the plugin for its name, but so few plugins + // actually bother implementing this correctly, that it's better to + // just ignore it and use the file name instead. +/* { char buffer [256]; zerostruct (buffer); dispatch (effGetEffectName, 0, 0, buffer, 0); @@ -896,9 +899,13 @@ void VSTPluginInstance::initialise() if (name.isEmpty()) name = module->pluginName; } +*/ - dispatch (effSetSampleRate, 0, 0, 0, (float) getSampleRate()); - dispatch (effSetBlockSize, 0, jmax (32, getBlockSize()), 0, 0); + if (getSampleRate() > 0) + dispatch (effSetSampleRate, 0, 0, 0, (float) getSampleRate()); + + if (getBlockSize() > 0) + dispatch (effSetBlockSize, 0, jmax (32, getBlockSize()), 0, 0); dispatch (effOpen, 0, 0, 0, 0); @@ -961,7 +968,7 @@ void VSTPluginInstance::prepareToPlay (double sampleRate_, dispatch (effSetSampleRate, 0, 0, 0, (float) sampleRate_); dispatch (effSetBlockSize, 0, jmax (16, samplesPerBlockExpected), 0, 0); - tempBuffer.setSize (effect->numOutputs, samplesPerBlockExpected); + tempBuffer.setSize (jmax (1, effect->numOutputs), samplesPerBlockExpected); if (! isPowerOn) setPower (true); @@ -2266,7 +2273,7 @@ static VstIntPtr handleGeneralCallback (VstInt32 opcode, VstInt32 index, VstInt3 return 1; case audioMasterGetVendorVersion: - return 1; + return 0x0101; case audioMasterGetVendorString: case audioMasterGetProductString: JUCEApplication::getInstance() diff --git a/extras/audio plugin host/src/plugins/juce_KnownPluginList.cpp b/extras/audio plugin host/src/plugins/juce_KnownPluginList.cpp index e33f6d9fd3..754efcfa79 100644 --- a/extras/audio plugin host/src/plugins/juce_KnownPluginList.cpp +++ b/extras/audio plugin host/src/plugins/juce_KnownPluginList.cpp @@ -199,6 +199,8 @@ public: 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); @@ -249,6 +251,103 @@ void KnownPluginList::recreateFromXml (const XmlElement& xml) //============================================================================== const int menuIdBase = 0x324503f4; +// This is used to turn a bunch of paths into a nested menu structure. +struct PluginFilesystemTree +{ +private: + String folder; + OwnedArray subFolders; + Array 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 & 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 & 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 sorted; @@ -262,7 +361,7 @@ void KnownPluginList::addToMenu (PopupMenu& menu, const SortMethod sortMethod) c } if (sortMethod == sortByCategory - || sortMethod == KnownPluginList::sortByManufacturer) + || sortMethod == sortByManufacturer) { String lastSubMenuName; PopupMenu sub; @@ -293,6 +392,12 @@ void KnownPluginList::addToMenu (PopupMenu& menu, const SortMethod sortMethod) c 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) diff --git a/extras/audio plugin host/src/plugins/juce_KnownPluginList.h b/extras/audio plugin host/src/plugins/juce_KnownPluginList.h index 507e69a0ff..b2d4bb7bc7 100644 --- a/extras/audio plugin host/src/plugins/juce_KnownPluginList.h +++ b/extras/audio plugin host/src/plugins/juce_KnownPluginList.h @@ -116,7 +116,8 @@ public: defaultOrder = 0, sortAlphabetically, sortByCategory, - sortByManufacturer + sortByManufacturer, + sortByFileSystemLocation }; //============================================================================== diff --git a/extras/audio plugin host/src/plugins/juce_PluginDirectoryScanner.cpp b/extras/audio plugin host/src/plugins/juce_PluginDirectoryScanner.cpp index 2e067fb77a..13f1c340df 100644 --- a/extras/audio plugin host/src/plugins/juce_PluginDirectoryScanner.cpp +++ b/extras/audio plugin host/src/plugins/juce_PluginDirectoryScanner.cpp @@ -129,6 +129,9 @@ bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList) // 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; diff --git a/extras/audio plugin host/src/plugins/juce_PluginDirectoryScanner.h b/extras/audio plugin host/src/plugins/juce_PluginDirectoryScanner.h index 36077bb327..ae39e7e00e 100644 --- a/extras/audio plugin host/src/plugins/juce_PluginDirectoryScanner.h +++ b/extras/audio plugin host/src/plugins/juce_PluginDirectoryScanner.h @@ -97,6 +97,10 @@ public: */ 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 @@ -105,6 +109,7 @@ private: KnownPluginList& list; OwnedArray filesToScan; File deadMansPedalFile; + StringArray failedFiles; int nextIndex; float progress; diff --git a/extras/audio plugin host/src/plugins/juce_PluginListComponent.cpp b/extras/audio plugin host/src/plugins/juce_PluginListComponent.cpp index 7cc45d7672..446e88d06d 100644 --- a/extras/audio plugin host/src/plugins/juce_PluginListComponent.cpp +++ b/extras/audio plugin host/src/plugins/juce_PluginListComponent.cpp @@ -196,11 +196,18 @@ void PluginListComponent::buttonClicked (Button* b) } else if (r != 0) { - scanFor (AudioPluginFormatManager::getInstance()->getFormat (r - 10)); + typeToScan = r - 10; + startTimer (1); } } } +void PluginListComponent::timerCallback() +{ + stopTimer(); + scanFor (AudioPluginFormatManager::getInstance()->getFormat (typeToScan)); +} + bool PluginListComponent::isInterestedInFileDrag (const StringArray& /*files*/) { return true; @@ -273,4 +280,17 @@ void PluginListComponent::scanFor (AudioPluginFormat* format) 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 (", ")); + } } diff --git a/extras/audio plugin host/src/plugins/juce_PluginListComponent.h b/extras/audio plugin host/src/plugins/juce_PluginListComponent.h index 9a952ae914..e2bf517457 100644 --- a/extras/audio plugin host/src/plugins/juce_PluginListComponent.h +++ b/extras/audio plugin host/src/plugins/juce_PluginListComponent.h @@ -44,7 +44,8 @@ class PluginListComponent : public Component, public ListBoxModel, public ChangeListener, - public ButtonListener + public ButtonListener, + public Timer { public: //============================================================================== @@ -79,6 +80,8 @@ public: void buttonClicked (Button* b); /** @internal */ void changeListenerCallback (void*); + /** @internal */ + void timerCallback(); //============================================================================== juce_UseDebuggingNewOperator @@ -89,6 +92,7 @@ private: ListBox* listBox; TextButton* optionsButton; PropertiesFile* propertiesToUse; + int typeToScan; void scanFor (AudioPluginFormat* format); };