| @@ -29,7 +29,13 @@ | |||||
| ============================================================================== | ============================================================================== | ||||
| */ | */ | ||||
| /** Creates a floating carbon window that can be used to hold a carbon UI. | |||||
| #ifndef __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__ | |||||
| #define __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__ | |||||
| //============================================================================== | |||||
| /** | |||||
| Creates a floating carbon window that can be used to hold a carbon UI. | |||||
| This is a handy class that's designed to be inlined where needed, e.g. | This is a handy class that's designed to be inlined where needed, e.g. | ||||
| in the audio plugin hosting code. | in the audio plugin hosting code. | ||||
| @@ -106,6 +112,8 @@ public: | |||||
| setOurSizeToEmbeddedViewSize(); | setOurSizeToEmbeddedViewSize(); | ||||
| setEmbeddedWindowToOurSize(); | setEmbeddedWindowToOurSize(); | ||||
| creationTime = Time::getCurrentTime(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -203,6 +211,11 @@ public: | |||||
| void timerCallback() | void timerCallback() | ||||
| { | { | ||||
| setOurSizeToEmbeddedViewSize(); | setOurSizeToEmbeddedViewSize(); | ||||
| // To avoid strange overpainting problems when the UI is first opened, we'll | |||||
| // repaint it a few times during the first second that it's on-screen.. | |||||
| if ((Time::getCurrentTime() - creationTime).inMilliseconds() < 1000) | |||||
| HIViewSetNeedsDisplay (embeddedView, true); | |||||
| } | } | ||||
| OSStatus carbonEventHandler (EventHandlerCallRef nextHandlerRef, | OSStatus carbonEventHandler (EventHandlerCallRef nextHandlerRef, | ||||
| @@ -222,6 +235,8 @@ public: | |||||
| SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult, | SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult, | ||||
| sizeof (ClickActivationResult), &howToHandleClick); | sizeof (ClickActivationResult), &howToHandleClick); | ||||
| HIViewSetNeedsDisplay (embeddedView, true); | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -239,6 +254,9 @@ protected: | |||||
| WindowRef wrapperWindow; | WindowRef wrapperWindow; | ||||
| HIViewRef embeddedView; | HIViewRef embeddedView; | ||||
| bool recursiveResize; | bool recursiveResize; | ||||
| Time creationTime; | |||||
| EventHandlerRef eventHandlerRef; | EventHandlerRef eventHandlerRef; | ||||
| }; | }; | ||||
| #endif // __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__ | |||||
| @@ -181,11 +181,14 @@ public: | |||||
| MenuBarModel* currentModel; | MenuBarModel* currentModel; | ||||
| void addMenuItem (PopupMenu::MenuItemIterator& iter, NSMenu* menuToAddTo, | |||||
| void addMenuItem (PopupMenu::MenuItemIterator& iter, NSMenu* menuToAddTo, | |||||
| const int topLevelMenuId, const int topLevelIndex) | const int topLevelMenuId, const int topLevelIndex) | ||||
| { | { | ||||
| NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | ||||
| if (text == 0) | |||||
| text = @""; | |||||
| if (iter.isSeparator) | if (iter.isSeparator) | ||||
| { | { | ||||
| [menuToAddTo addItem: [NSMenuItem separatorItem]]; | [menuToAddTo addItem: [NSMenuItem separatorItem]]; | ||||
| @@ -320,7 +323,7 @@ END_JUCE_NAMESPACE | |||||
| BEGIN_JUCE_NAMESPACE | BEGIN_JUCE_NAMESPACE | ||||
| //============================================================================== | //============================================================================== | ||||
| static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName, | |||||
| static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName, | |||||
| const PopupMenu* extraItems) | const PopupMenu* extraItems) | ||||
| { | { | ||||
| if (extraItems != 0 && JuceMainMenuHandler::instance != 0 && extraItems->getNumItems() > 0) | if (extraItems != 0 && JuceMainMenuHandler::instance != 0 && extraItems->getNumItems() > 0) | ||||
| @@ -329,7 +332,7 @@ static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName, | |||||
| while (iter.next()) | while (iter.next()) | ||||
| JuceMainMenuHandler::instance->addMenuItem (iter, menu, 0, -1); | JuceMainMenuHandler::instance->addMenuItem (iter, menu, 0, -1); | ||||
| [menu addItem: [NSMenuItem separatorItem]]; | [menu addItem: [NSMenuItem separatorItem]]; | ||||
| } | } | ||||
| @@ -415,7 +418,7 @@ void MenuBarModel::setMacMainMenu (MenuBarModel* newMenuBarModel, | |||||
| delete JuceMainMenuHandler::instance; | delete JuceMainMenuHandler::instance; | ||||
| jassert (JuceMainMenuHandler::instance == 0); // should be zeroed in the destructor | jassert (JuceMainMenuHandler::instance == 0); // should be zeroed in the destructor | ||||
| jassert (extraAppleMenuItems == 0); // you can't specify some extra items without also supplying a model | jassert (extraAppleMenuItems == 0); // you can't specify some extra items without also supplying a model | ||||
| extraAppleMenuItems = 0; | extraAppleMenuItems = 0; | ||||
| } | } | ||||
| else | else | ||||
| @@ -1347,8 +1347,8 @@ void NSViewComponentPeer::redirectMovedOrResized() | |||||
| //============================================================================== | //============================================================================== | ||||
| void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | ||||
| { | { | ||||
| // Very annoyingly, this function has to use the old SetSystemUIMode function, | |||||
| // which is in Carbon.framework. But, because there's no Cocoa equivalent, it | |||||
| // Very annoyingly, this function has to use the old SetSystemUIMode function, | |||||
| // which is in Carbon.framework. But, because there's no Cocoa equivalent, it | |||||
| // is apparently still available in 64-bit apps.. | // is apparently still available in 64-bit apps.. | ||||
| if (enableOrDisable) | if (enableOrDisable) | ||||
| { | { | ||||
| @@ -62,10 +62,12 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| const String getName() const { return "Internal"; } | const String getName() const { return "Internal"; } | ||||
| bool fileMightContainThisPluginType (const File&) { return false; } | |||||
| bool fileMightContainThisPluginType (const String&) { return false; } | |||||
| const FileSearchPath getDefaultLocationsToSearch() { return FileSearchPath(); } | const FileSearchPath getDefaultLocationsToSearch() { return FileSearchPath(); } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>&, const File&) {} | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>&, const String&) {} | |||||
| bool doesPluginStillExist (const PluginDescription&) { return true; } | bool doesPluginStillExist (const PluginDescription&) { return true; } | ||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||||
| const StringArray searchPathsForPlugins (const FileSearchPath&, const bool) { return StringArray(); } | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -779,8 +779,8 @@ protected: | |||||
| UInt8 inData1, | UInt8 inData1, | ||||
| UInt8 inData2, | UInt8 inData2, | ||||
| #if defined(MAC_OS_X_VERSION_10_5) | #if defined(MAC_OS_X_VERSION_10_5) | ||||
| UInt32 inStartFrame | |||||
| #else | |||||
| UInt32 inStartFrame) | |||||
| #else | |||||
| long inStartFrame) | long inStartFrame) | ||||
| #endif | #endif | ||||
| { | { | ||||
| @@ -796,6 +796,14 @@ protected: | |||||
| return noErr; | return noErr; | ||||
| } | } | ||||
| OSStatus HandleSysEx (const UInt8* inData, UInt32 inLength) | |||||
| { | |||||
| #if JucePlugin_WantsMidiInput | |||||
| midiEvents.addEvent (inData, inLength, 0); | |||||
| #endif | |||||
| return noErr; | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| ComponentResult GetPresets (CFArrayRef* outData) const | ComponentResult GetPresets (CFArrayRef* outData) const | ||||
| { | { | ||||
| @@ -952,7 +960,7 @@ private: | |||||
| - (NSString*) description | - (NSString*) description | ||||
| { | { | ||||
| return [NSString stringWithString: @JucePlugin_Name]; | |||||
| return [NSString stringWithString: @JucePlugin_Name]; | |||||
| } | } | ||||
| - (NSView*) uiViewForAudioUnit: (AudioUnit) inAudioUnit | - (NSView*) uiViewForAudioUnit: (AudioUnit) inAudioUnit | ||||
| @@ -27836,8 +27836,8 @@ public: | |||||
| /** Either the file containing the plugin module, or some other unique way | /** Either the file containing the plugin module, or some other unique way | ||||
| of identifying it. | of identifying it. | ||||
| E.g. for an AU, this would be the component ID, because not all AUs actually | |||||
| live in a file... | |||||
| E.g. for an AU, this would be an ID string that the component manager | |||||
| could use to retrieve the plugin. For a VST, it's the file path. | |||||
| */ | */ | ||||
| String fileOrIdentifier; | String fileOrIdentifier; | ||||
| @@ -27965,7 +27965,7 @@ public: | |||||
| subtypes, so in that case, each subtype is returned as a separate object. | subtypes, so in that case, each subtype is returned as a separate object. | ||||
| */ | */ | ||||
| virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results, | virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results, | ||||
| const File& file) = 0; | |||||
| const String& fileOrIdentifier) = 0; | |||||
| /** Tries to recreate a type from a previously generated PluginDescription. | /** Tries to recreate a type from a previously generated PluginDescription. | ||||
| @@ -27979,7 +27979,11 @@ public: | |||||
| This is for searching for potential files, so it shouldn't actually try to | This is for searching for potential files, so it shouldn't actually try to | ||||
| load the plugin or do anything time-consuming. | load the plugin or do anything time-consuming. | ||||
| */ | */ | ||||
| virtual bool fileMightContainThisPluginType (const File& file) = 0; | |||||
| virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0; | |||||
| /** Returns a readable version of the name of the plugin that this identifier refers to. | |||||
| */ | |||||
| virtual const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0; | |||||
| /** Checks whether this plugin could possibly be loaded. | /** Checks whether this plugin could possibly be loaded. | ||||
| @@ -27988,6 +27992,14 @@ public: | |||||
| */ | */ | ||||
| virtual bool doesPluginStillExist (const PluginDescription& desc) = 0; | virtual bool doesPluginStillExist (const PluginDescription& desc) = 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. | |||||
| */ | |||||
| virtual const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, | |||||
| const bool recursive) = 0; | |||||
| /** Returns the typical places to look for this kind of plugin. | /** 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 | Note that if this returns no paths, it means that the format can't be scanned-for | ||||
| @@ -28541,7 +28553,7 @@ public: | |||||
| /** Looks for a type in the list which comes from this file. | /** Looks for a type in the list which comes from this file. | ||||
| */ | */ | ||||
| PluginDescription* getTypeForFile (const File& file) const throw(); | |||||
| PluginDescription* getTypeForFile (const String& fileOrIdentifier) const throw(); | |||||
| /** Looks for a type in the list which matches a plugin type ID. | /** Looks for a type in the list which matches a plugin type ID. | ||||
| @@ -28568,14 +28580,15 @@ public: | |||||
| file (even if it was already known and hasn't been re-scanned) get returned | file (even if it was already known and hasn't been re-scanned) get returned | ||||
| in the array. | in the array. | ||||
| */ | */ | ||||
| bool scanAndAddFile (const File& possiblePluginFile, | |||||
| bool scanAndAddFile (const String& possiblePluginFileOrIdentifier, | |||||
| const bool dontRescanIfAlreadyInList, | const bool dontRescanIfAlreadyInList, | ||||
| OwnedArray <PluginDescription>& typesFound); | |||||
| OwnedArray <PluginDescription>& typesFound, | |||||
| AudioPluginFormat& formatToUse); | |||||
| /** Returns true if the specified file is already known about and if it | /** Returns true if the specified file is already known about and if it | ||||
| hasn't been modified since our entry was created. | hasn't been modified since our entry was created. | ||||
| */ | */ | ||||
| bool isListingUpToDate (const File& possiblePluginFile) const throw(); | |||||
| bool isListingUpToDate (const String& possiblePluginFileOrIdentifier) const throw(); | |||||
| /** Scans and adds a bunch of files that might have been dragged-and-dropped. | /** Scans and adds a bunch of files that might have been dragged-and-dropped. | ||||
| @@ -34678,9 +34691,11 @@ public: | |||||
| ~AudioUnitPluginFormat(); | ~AudioUnitPluginFormat(); | ||||
| const String getName() const { return "AudioUnit"; } | const String getName() const { return "AudioUnit"; } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| bool fileMightContainThisPluginType (const File& file); | |||||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); | |||||
| const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); | |||||
| bool doesPluginStillExist (const PluginDescription& desc); | bool doesPluginStillExist (const PluginDescription& desc); | ||||
| const FileSearchPath getDefaultLocationsToSearch(); | const FileSearchPath getDefaultLocationsToSearch(); | ||||
| @@ -34718,9 +34733,10 @@ public: | |||||
| ~DirectXPluginFormat(); | ~DirectXPluginFormat(); | ||||
| const String getName() const { return "DirectX"; } | const String getName() const { return "DirectX"; } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| bool fileMightContainThisPluginType (const File& file); | |||||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||||
| const FileSearchPath getDefaultLocationsToSearch(); | const FileSearchPath getDefaultLocationsToSearch(); | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -34757,9 +34773,10 @@ public: | |||||
| ~LADSPAPluginFormat(); | ~LADSPAPluginFormat(); | ||||
| const String getName() const { return "LADSPA"; } | const String getName() const { return "LADSPA"; } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| bool fileMightContainThisPluginType (const File& file); | |||||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||||
| const FileSearchPath getDefaultLocationsToSearch(); | const FileSearchPath getDefaultLocationsToSearch(); | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -34794,9 +34811,11 @@ public: | |||||
| ~VSTPluginFormat(); | ~VSTPluginFormat(); | ||||
| const String getName() const { return "VST"; } | const String getName() const { return "VST"; } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| bool fileMightContainThisPluginType (const File& file); | |||||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); | |||||
| const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); | |||||
| bool doesPluginStillExist (const PluginDescription& desc); | bool doesPluginStillExist (const PluginDescription& desc); | ||||
| const FileSearchPath getDefaultLocationsToSearch(); | const FileSearchPath getDefaultLocationsToSearch(); | ||||
| @@ -34805,6 +34824,8 @@ public: | |||||
| private: | private: | ||||
| VSTPluginFormat (const VSTPluginFormat&); | VSTPluginFormat (const VSTPluginFormat&); | ||||
| const VSTPluginFormat& operator= (const VSTPluginFormat&); | const VSTPluginFormat& operator= (const VSTPluginFormat&); | ||||
| void recursiveFileSearch (StringArray& results, const File& dir, const bool recursive); | |||||
| }; | }; | ||||
| #endif | #endif | ||||
| @@ -34884,12 +34905,13 @@ public: | |||||
| */ | */ | ||||
| bool scanNextFile (const bool dontRescanIfAlreadyInList); | bool scanNextFile (const bool dontRescanIfAlreadyInList); | ||||
| /** Returns the file that will be scanned during the next call to scanNextFile(). | |||||
| /** 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 | This is handy if you want to show the user which file is currently getting | ||||
| scanned. | scanned. | ||||
| */ | */ | ||||
| const File getNextPluginFileThatWillBeScanned() const throw(); | |||||
| const String getNextPluginFileThatWillBeScanned() const throw(); | |||||
| /** Returns the estimated progress, between 0 and 1. | /** Returns the estimated progress, between 0 and 1. | ||||
| */ | */ | ||||
| @@ -34905,13 +34927,12 @@ public: | |||||
| private: | private: | ||||
| KnownPluginList& list; | KnownPluginList& list; | ||||
| AudioPluginFormat& format; | AudioPluginFormat& format; | ||||
| OwnedArray <File> filesToScan; | |||||
| StringArray filesOrIdentifiersToScan; | |||||
| File deadMansPedalFile; | File deadMansPedalFile; | ||||
| StringArray failedFiles; | StringArray failedFiles; | ||||
| int nextIndex; | int nextIndex; | ||||
| float progress; | float progress; | ||||
| void recursiveFileSearch (const File& dir, const bool recursive); | |||||
| const StringArray getDeadMansPedalFile() throw(); | const StringArray getDeadMansPedalFile() throw(); | ||||
| void setDeadMansPedalFile (const StringArray& newContents) throw(); | void setDeadMansPedalFile (const StringArray& newContents) throw(); | ||||
| @@ -510,7 +510,7 @@ void AudioThumbnail::drawChannel (Graphics& g, | |||||
| const float vscale = verticalZoomFactor * h / 256.0f; | const float vscale = verticalZoomFactor * h / 256.0f; | ||||
| const Rectangle clip (g.getClipBounds()); | const Rectangle clip (g.getClipBounds()); | ||||
| const int skipLeft = clip.getX() - x; | |||||
| const int skipLeft = jlimit (0, w, clip.getX() - x); | |||||
| w -= skipLeft; | w -= skipLeft; | ||||
| x += skipLeft; | x += skipLeft; | ||||
| @@ -49,9 +49,11 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| const String getName() const { return "AudioUnit"; } | const String getName() const { return "AudioUnit"; } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| bool fileMightContainThisPluginType (const File& file); | |||||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); | |||||
| const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); | |||||
| bool doesPluginStillExist (const PluginDescription& desc); | bool doesPluginStillExist (const PluginDescription& desc); | ||||
| const FileSearchPath getDefaultLocationsToSearch(); | const FileSearchPath getDefaultLocationsToSearch(); | ||||
| @@ -81,6 +81,129 @@ BEGIN_JUCE_NAMESPACE | |||||
| static int insideCallback = 0; | static int insideCallback = 0; | ||||
| //============================================================================== | |||||
| static const String osTypeToString (OSType type) throw() | |||||
| { | |||||
| char s[4]; | |||||
| s[0] = (char) (((uint32) type) >> 24); | |||||
| s[1] = (char) (((uint32) type) >> 16); | |||||
| s[2] = (char) (((uint32) type) >> 8); | |||||
| s[3] = (char) ((uint32) type); | |||||
| return String (s, 4); | |||||
| } | |||||
| static OSType stringToOSType (const String& s1) throw() | |||||
| { | |||||
| const String s (s1 + " "); | |||||
| 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 tchar* auIdentifierPrefix = T("AudioUnit:"); | |||||
| static const String createAUPluginIdentifier (const ComponentDescription& desc) | |||||
| { | |||||
| jassert (osTypeToString ('abcd') == T("abcd")); // agh, must have got the endianness wrong.. | |||||
| jassert (stringToOSType ("abcd") == (OSType) 'abcd'); // ditto | |||||
| 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/"; | |||||
| s << osTypeToString (desc.componentType) | |||||
| << T(",") | |||||
| << osTypeToString (desc.componentSubType) | |||||
| << T(",") | |||||
| << osTypeToString (desc.componentManufacturer); | |||||
| return s; | |||||
| } | |||||
| static void getAUDetails (ComponentRecord* comp, String& name, String& manufacturer) | |||||
| { | |||||
| Handle componentNameHandle = NewHandle (sizeof (void*)); | |||||
| Handle componentInfoHandle = NewHandle (sizeof (void*)); | |||||
| if (componentNameHandle != 0 && componentInfoHandle != 0) | |||||
| { | |||||
| ComponentDescription desc; | |||||
| if (GetComponentInfo (comp, &desc, componentNameHandle, componentInfoHandle, 0) == noErr) | |||||
| { | |||||
| ConstStr255Param nameString = (ConstStr255Param) (*componentNameHandle); | |||||
| ConstStr255Param infoString = (ConstStr255Param) (*componentInfoHandle); | |||||
| if (nameString != 0 && nameString[0] != 0) | |||||
| { | |||||
| const String all ((const char*) nameString + 1, nameString[0]); | |||||
| DBG ("name: "+ all); | |||||
| manufacturer = all.upToFirstOccurrenceOf (T(":"), false, false).trim(); | |||||
| name = all.fromFirstOccurrenceOf (T(":"), false, false).trim(); | |||||
| } | |||||
| if (infoString != 0 && infoString[0] != 0) | |||||
| { | |||||
| const String all ((const char*) infoString + 1, infoString[0]); | |||||
| DBG ("info: " + all); | |||||
| } | |||||
| if (name.isEmpty()) | |||||
| name = "<Unknown>"; | |||||
| } | |||||
| DisposeHandle (componentNameHandle); | |||||
| DisposeHandle (componentInfoHandle); | |||||
| } | |||||
| } | |||||
| static bool getComponentDescFromIdentifier (const String& fileOrIdentifier, ComponentDescription& desc, | |||||
| String& name, String& version, String& manufacturer) | |||||
| { | |||||
| zerostruct (desc); | |||||
| if (fileOrIdentifier.startsWithIgnoreCase (auIdentifierPrefix)) | |||||
| { | |||||
| String s (fileOrIdentifier.substring (jmax (fileOrIdentifier.lastIndexOfChar (T(':')), | |||||
| fileOrIdentifier.lastIndexOfChar (T('/'))) + 1)); | |||||
| StringArray tokens; | |||||
| tokens.addTokens (s, T(","), 0); | |||||
| tokens.trim(); | |||||
| tokens.removeEmptyStrings(); | |||||
| if (tokens.size() == 3) | |||||
| { | |||||
| desc.componentType = stringToOSType (tokens[0]); | |||||
| desc.componentSubType = stringToOSType (tokens[1]); | |||||
| desc.componentManufacturer = stringToOSType (tokens[2]); | |||||
| ComponentRecord* comp = FindNextComponent (0, &desc); | |||||
| if (comp != 0) | |||||
| { | |||||
| getAUDetails (comp, name, manufacturer); | |||||
| return true; | |||||
| } | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| class AudioUnitPluginWindowCarbon; | class AudioUnitPluginWindowCarbon; | ||||
| class AudioUnitPluginWindowCocoa; | class AudioUnitPluginWindowCocoa; | ||||
| @@ -98,11 +221,11 @@ public: | |||||
| void fillInPluginDescription (PluginDescription& desc) const | void fillInPluginDescription (PluginDescription& desc) const | ||||
| { | { | ||||
| desc.name = pluginName; | desc.name = pluginName; | ||||
| desc.file = file; | |||||
| desc.fileOrIdentifier = createAUPluginIdentifier (componentDesc); | |||||
| desc.uid = ((int) componentDesc.componentType) | desc.uid = ((int) componentDesc.componentType) | ||||
| ^ ((int) componentDesc.componentSubType) | ^ ((int) componentDesc.componentSubType) | ||||
| ^ ((int) componentDesc.componentManufacturer); | ^ ((int) componentDesc.componentManufacturer); | ||||
| desc.lastFileModTime = file.getLastModificationTime(); | |||||
| desc.lastFileModTime = 0; | |||||
| desc.pluginFormatName = "AudioUnit"; | desc.pluginFormatName = "AudioUnit"; | ||||
| desc.category = getCategory(); | desc.category = getCategory(); | ||||
| desc.manufacturerName = manufacturer; | desc.manufacturerName = manufacturer; | ||||
| @@ -163,7 +286,7 @@ private: | |||||
| ComponentDescription componentDesc; | ComponentDescription componentDesc; | ||||
| String pluginName, manufacturer, version; | String pluginName, manufacturer, version; | ||||
| File file; | |||||
| String fileOrIdentifier; | |||||
| CriticalSection lock; | CriticalSection lock; | ||||
| bool initialised, wantsMidiMessages, wasPlaying; | bool initialised, wantsMidiMessages, wasPlaying; | ||||
| @@ -175,7 +298,7 @@ private: | |||||
| Array <int> parameterIds; | Array <int> parameterIds; | ||||
| //============================================================================== | //============================================================================== | ||||
| bool getComponentDescFromFile (const File& file); | |||||
| bool getComponentDescFromFile (const String& fileOrIdentifier); | |||||
| void initialise(); | void initialise(); | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -257,12 +380,12 @@ private: | |||||
| const String getCategory() const; | const String getCategory() const; | ||||
| //============================================================================== | //============================================================================== | ||||
| AudioUnitPluginInstance (const File& file); | |||||
| AudioUnitPluginInstance (const String& fileOrIdentifier); | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| AudioUnitPluginInstance::AudioUnitPluginInstance (const File& file_) | |||||
| : file (file_), | |||||
| AudioUnitPluginInstance::AudioUnitPluginInstance (const String& fileOrIdentifier) | |||||
| : fileOrIdentifier (fileOrIdentifier), | |||||
| initialised (false), | initialised (false), | ||||
| wantsMidiMessages (false), | wantsMidiMessages (false), | ||||
| audioUnit (0), | audioUnit (0), | ||||
| @@ -273,9 +396,9 @@ AudioUnitPluginInstance::AudioUnitPluginInstance (const File& file_) | |||||
| { | { | ||||
| ++insideCallback; | ++insideCallback; | ||||
| log (T("Opening AU: ") + file.getFullPathName()); | |||||
| log (T("Opening AU: ") + fileOrIdentifier); | |||||
| if (getComponentDescFromFile (file)) | |||||
| if (getComponentDescFromFile (fileOrIdentifier)) | |||||
| { | { | ||||
| ComponentRecord* const comp = FindNextComponent (0, &componentDesc); | ComponentRecord* const comp = FindNextComponent (0, &componentDesc); | ||||
| @@ -314,15 +437,18 @@ AudioUnitPluginInstance::~AudioUnitPluginInstance() | |||||
| juce_free (outputBufferList); | juce_free (outputBufferList); | ||||
| } | } | ||||
| bool AudioUnitPluginInstance::getComponentDescFromFile (const File& file) | |||||
| bool AudioUnitPluginInstance::getComponentDescFromFile (const String& fileOrIdentifier) | |||||
| { | { | ||||
| zerostruct (componentDesc); | zerostruct (componentDesc); | ||||
| if (getComponentDescFromIdentifier (fileOrIdentifier, componentDesc, pluginName, version, manufacturer)) | |||||
| return true; | |||||
| const File file (fileOrIdentifier); | |||||
| if (! file.hasFileExtension (T(".component"))) | if (! file.hasFileExtension (T(".component"))) | ||||
| return false; | return false; | ||||
| const String filename (file.getFullPathName()); | |||||
| const char* const utf8 = filename.toUTF8(); | |||||
| const char* const utf8 = fileOrIdentifier.toUTF8(); | |||||
| CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, | CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, | ||||
| strlen (utf8), file.isDirectory()); | strlen (utf8), file.isDirectory()); | ||||
| if (url != 0) | if (url != 0) | ||||
| @@ -730,15 +856,24 @@ public: | |||||
| ~AudioUnitPluginWindowCocoa() | ~AudioUnitPluginWindowCocoa() | ||||
| { | { | ||||
| const bool wasValid = isValid(); | |||||
| wrapper->setView (0); | wrapper->setView (0); | ||||
| activeWindows.removeValue (this); | activeWindows.removeValue (this); | ||||
| if (isValid()) | |||||
| if (wasValid) | |||||
| plugin.editorBeingDeleted (this); | plugin.editorBeingDeleted (this); | ||||
| delete wrapper; | delete wrapper; | ||||
| } | } | ||||
| bool isValid() const { return wrapper->getView() != 0; } | bool isValid() const { return wrapper->getView() != 0; } | ||||
| void paint (Graphics& g) | |||||
| { | |||||
| g.fillAll (Colours::white); | |||||
| } | |||||
| void resized() | void resized() | ||||
| { | { | ||||
| wrapper->setSize (getWidth(), getHeight()); | wrapper->setSize (getWidth(), getHeight()); | ||||
| @@ -794,6 +929,11 @@ private: | |||||
| juce_free (info); | juce_free (info); | ||||
| wrapper->setView (pluginView); | wrapper->setView (pluginView); | ||||
| if (pluginView != 0) | |||||
| setSize ([pluginView frame].size.width, | |||||
| [pluginView frame].size.height); | |||||
| return pluginView != 0; | return pluginView != 0; | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -1264,13 +1404,13 @@ AudioUnitPluginFormat::~AudioUnitPluginFormat() | |||||
| } | } | ||||
| void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results, | void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results, | ||||
| const File& file) | |||||
| const String& fileOrIdentifier) | |||||
| { | { | ||||
| if (! fileMightContainThisPluginType (file)) | |||||
| if (! fileMightContainThisPluginType (fileOrIdentifier)) | |||||
| return; | return; | ||||
| PluginDescription desc; | PluginDescription desc; | ||||
| desc.file = file; | |||||
| desc.fileOrIdentifier = fileOrIdentifier; | |||||
| desc.uid = 0; | desc.uid = 0; | ||||
| AudioUnitPluginInstance* instance = dynamic_cast <AudioUnitPluginInstance*> (createInstanceFromDescription (desc)); | AudioUnitPluginInstance* instance = dynamic_cast <AudioUnitPluginInstance*> (createInstanceFromDescription (desc)); | ||||
| @@ -1295,9 +1435,9 @@ AudioPluginInstance* AudioUnitPluginFormat::createInstanceFromDescription (const | |||||
| { | { | ||||
| AudioUnitPluginInstance* result = 0; | AudioUnitPluginInstance* result = 0; | ||||
| if (fileMightContainThisPluginType (desc.file)) | |||||
| if (fileMightContainThisPluginType (desc.fileOrIdentifier)) | |||||
| { | { | ||||
| result = new AudioUnitPluginInstance (desc.file); | |||||
| result = new AudioUnitPluginInstance (desc.fileOrIdentifier); | |||||
| if (result->audioUnit != 0) | if (result->audioUnit != 0) | ||||
| { | { | ||||
| @@ -1312,15 +1452,73 @@ AudioPluginInstance* AudioUnitPluginFormat::createInstanceFromDescription (const | |||||
| return result; | return result; | ||||
| } | } | ||||
| bool AudioUnitPluginFormat::fileMightContainThisPluginType (const File& f) | |||||
| const StringArray AudioUnitPluginFormat::searchPathsForPlugins (const FileSearchPath& /*directoriesToSearch*/, | |||||
| const bool /*recursive*/) | |||||
| { | { | ||||
| StringArray result; | |||||
| ComponentRecord* comp = 0; | |||||
| ComponentDescription desc; | |||||
| zerostruct (desc); | |||||
| for (;;) | |||||
| { | |||||
| zerostruct (desc); | |||||
| comp = FindNextComponent (comp, &desc); | |||||
| if (comp == 0) | |||||
| break; | |||||
| GetComponentInfo (comp, &desc, 0, 0, 0); | |||||
| if (desc.componentType == kAudioUnitType_MusicDevice | |||||
| || desc.componentType == kAudioUnitType_MusicEffect | |||||
| || desc.componentType == kAudioUnitType_Effect | |||||
| || desc.componentType == kAudioUnitType_Generator | |||||
| || desc.componentType == kAudioUnitType_Panner) | |||||
| { | |||||
| const String s (createAUPluginIdentifier (desc)); | |||||
| DBG (s); | |||||
| result.add (s); | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| bool AudioUnitPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) | |||||
| { | |||||
| ComponentDescription desc; | |||||
| String name, version, manufacturer; | |||||
| if (getComponentDescFromIdentifier (fileOrIdentifier, desc, name, version, manufacturer)) | |||||
| return FindNextComponent (0, &desc) != 0; | |||||
| const File f (fileOrIdentifier); | |||||
| return f.hasFileExtension (T(".component")) | return f.hasFileExtension (T(".component")) | ||||
| && f.isDirectory(); | && f.isDirectory(); | ||||
| } | } | ||||
| const String AudioUnitPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) | |||||
| { | |||||
| ComponentDescription desc; | |||||
| String name, version, manufacturer; | |||||
| getComponentDescFromIdentifier (fileOrIdentifier, desc, name, version, manufacturer); | |||||
| if (name.isEmpty()) | |||||
| name = fileOrIdentifier; | |||||
| return name; | |||||
| } | |||||
| bool AudioUnitPluginFormat::doesPluginStillExist (const PluginDescription& desc) | |||||
| { | |||||
| return File (desc.fileOrIdentifier).exists(); | |||||
| } | |||||
| const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | ||||
| { | { | ||||
| return FileSearchPath ("~/Library/Audio/Plug-Ins/Components;/Library/Audio/Plug-Ins/Components"); | |||||
| return FileSearchPath ("(Default AudioUnit locations)"); | |||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -53,9 +53,10 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| const String getName() const { return "DirectX"; } | const String getName() const { return "DirectX"; } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| bool fileMightContainThisPluginType (const File& file); | |||||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||||
| const FileSearchPath getDefaultLocationsToSearch(); | const FileSearchPath getDefaultLocationsToSearch(); | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -53,9 +53,10 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| const String getName() const { return "LADSPA"; } | const String getName() const { return "LADSPA"; } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| bool fileMightContainThisPluginType (const File& file); | |||||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||||
| const FileSearchPath getDefaultLocationsToSearch(); | const FileSearchPath getDefaultLocationsToSearch(); | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -2892,13 +2892,13 @@ VSTPluginFormat::~VSTPluginFormat() | |||||
| } | } | ||||
| void VSTPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results, | void VSTPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results, | ||||
| const File& file) | |||||
| const String& fileOrIdentifier) | |||||
| { | { | ||||
| if (! fileMightContainThisPluginType (file)) | |||||
| if (! fileMightContainThisPluginType (fileOrIdentifier)) | |||||
| return; | return; | ||||
| PluginDescription desc; | PluginDescription desc; | ||||
| desc.fileOrIdentifier = file.getFullPathName(); | |||||
| desc.fileOrIdentifier = fileOrIdentifier; | |||||
| desc.uid = 0; | desc.uid = 0; | ||||
| VSTPluginInstance* instance = dynamic_cast <VSTPluginInstance*> (createInstanceFromDescription (desc)); | VSTPluginInstance* instance = dynamic_cast <VSTPluginInstance*> (createInstanceFromDescription (desc)); | ||||
| @@ -2976,10 +2976,10 @@ AudioPluginInstance* VSTPluginFormat::createInstanceFromDescription (const Plugi | |||||
| { | { | ||||
| VSTPluginInstance* result = 0; | VSTPluginInstance* result = 0; | ||||
| File file (desc.fileOrIdentifier); | |||||
| if (fileMightContainThisPluginType (file)) | |||||
| if (fileMightContainThisPluginType (desc.fileOrIdentifier)) | |||||
| { | { | ||||
| File file (desc.fileOrIdentifier); | |||||
| const File previousWorkingDirectory (File::getCurrentWorkingDirectory()); | const File previousWorkingDirectory (File::getCurrentWorkingDirectory()); | ||||
| file.getParentDirectory().setAsCurrentWorkingDirectory(); | file.getParentDirectory().setAsCurrentWorkingDirectory(); | ||||
| @@ -3008,8 +3008,10 @@ AudioPluginInstance* VSTPluginFormat::createInstanceFromDescription (const Plugi | |||||
| return result; | return result; | ||||
| } | } | ||||
| bool VSTPluginFormat::fileMightContainThisPluginType (const File& f) | |||||
| bool VSTPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) | |||||
| { | { | ||||
| const File f (fileOrIdentifier); | |||||
| #if JUCE_MAC | #if JUCE_MAC | ||||
| if (f.isDirectory() && f.hasFileExtension (T(".vst"))) | if (f.isDirectory() && f.hasFileExtension (T(".vst"))) | ||||
| return true; | return true; | ||||
| @@ -3041,11 +3043,48 @@ bool VSTPluginFormat::fileMightContainThisPluginType (const File& f) | |||||
| #endif | #endif | ||||
| } | } | ||||
| const String VSTPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) | |||||
| { | |||||
| return fileOrIdentifier; | |||||
| } | |||||
| bool VSTPluginFormat::doesPluginStillExist (const PluginDescription& desc) | bool VSTPluginFormat::doesPluginStillExist (const PluginDescription& desc) | ||||
| { | { | ||||
| return File (desc.fileOrIdentifier).exists(); | return File (desc.fileOrIdentifier).exists(); | ||||
| } | } | ||||
| const StringArray VSTPluginFormat::searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive) | |||||
| { | |||||
| 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()) | |||||
| { | |||||
| 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); | |||||
| } | |||||
| } | |||||
| const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() | const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() | ||||
| { | { | ||||
| #if JUCE_MAC | #if JUCE_MAC | ||||
| @@ -3059,6 +3098,7 @@ const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() | |||||
| #endif | #endif | ||||
| } | } | ||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| #endif | #endif | ||||
| @@ -50,9 +50,11 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| const String getName() const { return "VST"; } | const String getName() const { return "VST"; } | ||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | ||||
| bool fileMightContainThisPluginType (const File& file); | |||||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); | |||||
| const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); | |||||
| bool doesPluginStillExist (const PluginDescription& desc); | bool doesPluginStillExist (const PluginDescription& desc); | ||||
| const FileSearchPath getDefaultLocationsToSearch(); | const FileSearchPath getDefaultLocationsToSearch(); | ||||
| @@ -62,6 +64,8 @@ public: | |||||
| private: | private: | ||||
| VSTPluginFormat (const VSTPluginFormat&); | VSTPluginFormat (const VSTPluginFormat&); | ||||
| const VSTPluginFormat& operator= (const VSTPluginFormat&); | const VSTPluginFormat& operator= (const VSTPluginFormat&); | ||||
| void recursiveFileSearch (StringArray& results, const File& dir, const bool recursive); | |||||
| }; | }; | ||||
| @@ -68,7 +68,7 @@ public: | |||||
| subtypes, so in that case, each subtype is returned as a separate object. | subtypes, so in that case, each subtype is returned as a separate object. | ||||
| */ | */ | ||||
| virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results, | virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results, | ||||
| const File& file) = 0; | |||||
| const String& fileOrIdentifier) = 0; | |||||
| /** Tries to recreate a type from a previously generated PluginDescription. | /** Tries to recreate a type from a previously generated PluginDescription. | ||||
| @@ -82,7 +82,11 @@ public: | |||||
| This is for searching for potential files, so it shouldn't actually try to | This is for searching for potential files, so it shouldn't actually try to | ||||
| load the plugin or do anything time-consuming. | load the plugin or do anything time-consuming. | ||||
| */ | */ | ||||
| virtual bool fileMightContainThisPluginType (const File& file) = 0; | |||||
| virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0; | |||||
| /** Returns a readable version of the name of the plugin that this identifier refers to. | |||||
| */ | |||||
| virtual const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0; | |||||
| /** Checks whether this plugin could possibly be loaded. | /** Checks whether this plugin could possibly be loaded. | ||||
| @@ -91,6 +95,13 @@ public: | |||||
| */ | */ | ||||
| virtual bool doesPluginStillExist (const PluginDescription& desc) = 0; | virtual bool doesPluginStillExist (const PluginDescription& desc) = 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. | |||||
| */ | |||||
| virtual const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, | |||||
| const bool recursive) = 0; | |||||
| /** Returns the typical places to look for this kind of plugin. | /** Returns the typical places to look for this kind of plugin. | ||||
| @@ -79,14 +79,14 @@ void AudioPluginFormatManager::addDefaultFormats() | |||||
| } | } | ||||
| #endif | #endif | ||||
| #if JUCE_PLUGINHOST_VST | |||||
| formats.add (new VSTPluginFormat()); | |||||
| #endif | |||||
| #if JUCE_PLUGINHOST_AU && JUCE_MAC | #if JUCE_PLUGINHOST_AU && JUCE_MAC | ||||
| formats.add (new AudioUnitPluginFormat()); | formats.add (new AudioUnitPluginFormat()); | ||||
| #endif | #endif | ||||
| #if JUCE_PLUGINHOST_VST | |||||
| formats.add (new VSTPluginFormat()); | |||||
| #endif | |||||
| #if JUCE_PLUGINHOST_DX && JUCE_WIN32 | #if JUCE_PLUGINHOST_DX && JUCE_WIN32 | ||||
| formats.add (new DirectXPluginFormat()); | formats.add (new DirectXPluginFormat()); | ||||
| #endif | #endif | ||||
| @@ -55,10 +55,10 @@ void KnownPluginList::clear() | |||||
| } | } | ||||
| } | } | ||||
| PluginDescription* KnownPluginList::getTypeForFile (const File& file) const throw() | |||||
| PluginDescription* KnownPluginList::getTypeForFile (const String& fileOrIdentifier) const throw() | |||||
| { | { | ||||
| for (int i = 0; i < types.size(); ++i) | for (int i = 0; i < types.size(); ++i) | ||||
| if (types.getUnchecked(i)->fileOrIdentifier == file.getFullPathName()) | |||||
| if (types.getUnchecked(i)->fileOrIdentifier == fileOrIdentifier) | |||||
| return types.getUnchecked(i); | return types.getUnchecked(i); | ||||
| return 0; | return 0; | ||||
| @@ -99,17 +99,33 @@ void KnownPluginList::removeType (const int index) throw() | |||||
| sendChangeMessage (this); | sendChangeMessage (this); | ||||
| } | } | ||||
| bool KnownPluginList::isListingUpToDate (const File& possiblePluginFile) const throw() | |||||
| static Time getFileModTime (const String& fileOrIdentifier) throw() | |||||
| { | { | ||||
| if (getTypeForFile (possiblePluginFile) == 0) | |||||
| if (fileOrIdentifier.startsWithChar (T('/')) | |||||
| || fileOrIdentifier[1] == T(':')) | |||||
| { | |||||
| return File (fileOrIdentifier).getLastModificationTime(); | |||||
| } | |||||
| return Time (0); | |||||
| } | |||||
| static bool timesAreDifferent (const Time& t1, const Time& t2) throw() | |||||
| { | |||||
| return t1 != t2 || t1 == Time (0); | |||||
| } | |||||
| bool KnownPluginList::isListingUpToDate (const String& fileOrIdentifier) const throw() | |||||
| { | |||||
| if (getTypeForFile (fileOrIdentifier) == 0) | |||||
| return false; | return false; | ||||
| for (int i = types.size(); --i >= 0;) | for (int i = types.size(); --i >= 0;) | ||||
| { | { | ||||
| const PluginDescription* const d = types.getUnchecked(i); | const PluginDescription* const d = types.getUnchecked(i); | ||||
| if (d->fileOrIdentifier == possiblePluginFile.getFullPathName() | |||||
| && d->lastFileModTime != possiblePluginFile.getLastModificationTime()) | |||||
| if (d->fileOrIdentifier == fileOrIdentifier | |||||
| && timesAreDifferent (d->lastFileModTime, getFileModTime (fileOrIdentifier))) | |||||
| { | { | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -118,14 +134,15 @@ bool KnownPluginList::isListingUpToDate (const File& possiblePluginFile) const t | |||||
| return true; | return true; | ||||
| } | } | ||||
| bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile, | |||||
| bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier, | |||||
| const bool dontRescanIfAlreadyInList, | const bool dontRescanIfAlreadyInList, | ||||
| OwnedArray <PluginDescription>& typesFound) | |||||
| OwnedArray <PluginDescription>& typesFound, | |||||
| AudioPluginFormat& format) | |||||
| { | { | ||||
| bool addedOne = false; | bool addedOne = false; | ||||
| if (dontRescanIfAlreadyInList | if (dontRescanIfAlreadyInList | ||||
| && getTypeForFile (possiblePluginFile) != 0) | |||||
| && getTypeForFile (fileOrIdentifier) != 0) | |||||
| { | { | ||||
| bool needsRescanning = false; | bool needsRescanning = false; | ||||
| @@ -133,9 +150,9 @@ bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile, | |||||
| { | { | ||||
| const PluginDescription* const d = types.getUnchecked(i); | const PluginDescription* const d = types.getUnchecked(i); | ||||
| if (d->fileOrIdentifier == possiblePluginFile.getFullPathName()) | |||||
| if (d->fileOrIdentifier == fileOrIdentifier) | |||||
| { | { | ||||
| if (d->lastFileModTime != possiblePluginFile.getLastModificationTime()) | |||||
| if (timesAreDifferent (d->lastFileModTime, getFileModTime (fileOrIdentifier))) | |||||
| needsRescanning = true; | needsRescanning = true; | ||||
| else | else | ||||
| typesFound.add (new PluginDescription (*d)); | typesFound.add (new PluginDescription (*d)); | ||||
| @@ -146,23 +163,18 @@ bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile, | |||||
| return false; | 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); | |||||
| OwnedArray <PluginDescription> found; | |||||
| format.findAllTypesForFile (found, fileOrIdentifier); | |||||
| for (int i = 0; i < found.size(); ++i) | |||||
| { | |||||
| PluginDescription* const desc = found.getUnchecked(i); | |||||
| jassert (desc != 0); | |||||
| for (int i = 0; i < found.size(); ++i) | |||||
| { | |||||
| PluginDescription* const desc = found.getUnchecked(i); | |||||
| jassert (desc != 0); | |||||
| if (addType (*desc)) | |||||
| addedOne = true; | |||||
| if (addType (*desc)) | |||||
| addedOne = true; | |||||
| typesFound.add (new PluginDescription (*desc)); | |||||
| } | |||||
| typesFound.add (new PluginDescription (*desc)); | |||||
| } | } | ||||
| return addedOne; | return addedOne; | ||||
| @@ -173,10 +185,20 @@ void KnownPluginList::scanAndAddDragAndDroppedFiles (const StringArray& files, | |||||
| { | { | ||||
| for (int i = 0; i < files.size(); ++i) | for (int i = 0; i < files.size(); ++i) | ||||
| { | { | ||||
| const File f (files [i]); | |||||
| bool loaded = false; | |||||
| for (int j = 0; j < AudioPluginFormatManager::getInstance()->getNumFormats(); ++j) | |||||
| { | |||||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (j); | |||||
| if (scanAndAddFile (files[i], true, typesFound, *format)) | |||||
| loaded = true; | |||||
| } | |||||
| if (! scanAndAddFile (f, true, typesFound)) | |||||
| if (! loaded) | |||||
| { | { | ||||
| const File f (files[i]); | |||||
| if (f.isDirectory()) | if (f.isDirectory()) | ||||
| { | { | ||||
| StringArray s; | StringArray s; | ||||
| @@ -350,7 +372,13 @@ public: | |||||
| PopupMenu subMenu; | PopupMenu subMenu; | ||||
| sub->addToMenu (subMenu, allPlugins); | sub->addToMenu (subMenu, allPlugins); | ||||
| #if JUCE_MAC | |||||
| // avoid the special AU formatting nonsense on Mac.. | |||||
| m.addSubMenu (sub->folder.fromFirstOccurrenceOf (T(":"), false, false), subMenu); | |||||
| #else | |||||
| m.addSubMenu (sub->folder, subMenu); | m.addSubMenu (sub->folder, subMenu); | ||||
| #endif | |||||
| } | } | ||||
| for (i = 0; i < plugins.size(); ++i) | for (i = 0; i < plugins.size(); ++i) | ||||
| @@ -74,7 +74,7 @@ public: | |||||
| /** Looks for a type in the list which comes from this file. | /** Looks for a type in the list which comes from this file. | ||||
| */ | */ | ||||
| PluginDescription* getTypeForFile (const File& file) const throw(); | |||||
| PluginDescription* getTypeForFile (const String& fileOrIdentifier) const throw(); | |||||
| /** Looks for a type in the list which matches a plugin type ID. | /** Looks for a type in the list which matches a plugin type ID. | ||||
| @@ -101,14 +101,15 @@ public: | |||||
| file (even if it was already known and hasn't been re-scanned) get returned | file (even if it was already known and hasn't been re-scanned) get returned | ||||
| in the array. | in the array. | ||||
| */ | */ | ||||
| bool scanAndAddFile (const File& possiblePluginFile, | |||||
| bool scanAndAddFile (const String& possiblePluginFileOrIdentifier, | |||||
| const bool dontRescanIfAlreadyInList, | const bool dontRescanIfAlreadyInList, | ||||
| OwnedArray <PluginDescription>& typesFound); | |||||
| OwnedArray <PluginDescription>& typesFound, | |||||
| AudioPluginFormat& formatToUse); | |||||
| /** Returns true if the specified file is already known about and if it | /** Returns true if the specified file is already known about and if it | ||||
| hasn't been modified since our entry was created. | hasn't been modified since our entry was created. | ||||
| */ | */ | ||||
| bool isListingUpToDate (const File& possiblePluginFile) const throw(); | |||||
| bool isListingUpToDate (const String& possiblePluginFileOrIdentifier) const throw(); | |||||
| /** Scans and adds a bunch of files that might have been dragged-and-dropped. | /** Scans and adds a bunch of files that might have been dragged-and-dropped. | ||||
| @@ -75,10 +75,10 @@ public: | |||||
| String version; | String version; | ||||
| /** Either the file containing the plugin module, or some other unique way | /** Either the file containing the plugin module, or some other unique way | ||||
| of identifying it. | |||||
| E.g. for an AU, this would be the component ID, because not all AUs actually | |||||
| live in a file... | |||||
| of identifying it. | |||||
| E.g. for an AU, this would be an ID string that the component manager | |||||
| could use to retrieve the plugin. For a VST, it's the file path. | |||||
| */ | */ | ||||
| String fileOrIdentifier; | String fileOrIdentifier; | ||||
| @@ -52,8 +52,7 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, | |||||
| { | { | ||||
| directoriesToSearch.removeRedundantPaths(); | directoriesToSearch.removeRedundantPaths(); | ||||
| for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j) | |||||
| recursiveFileSearch (directoriesToSearch [j], recursive); | |||||
| filesOrIdentifiersToScan = format.searchPathsForPlugins (directoriesToSearch, recursive); | |||||
| // If any plugins have crashed recently when being loaded, move them to the | // 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.. | // end of the list to give the others a chance to load correctly.. | ||||
| @@ -61,33 +60,11 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, | |||||
| for (int i = 0; i < crashedPlugins.size(); ++i) | for (int i = 0; i < crashedPlugins.size(); ++i) | ||||
| { | { | ||||
| const File f (crashedPlugins[i]); | |||||
| const String 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; | |||||
| if (format.fileMightContainThisPluginType (f)) | |||||
| { | |||||
| isPlugin = true; | |||||
| filesToScan.add (new File (f)); | |||||
| } | |||||
| if (recursive && (! isPlugin) && f.isDirectory()) | |||||
| recursiveFileSearch (f, true); | |||||
| for (int j = filesOrIdentifiersToScan.size(); --j >= 0;) | |||||
| if (f == filesOrIdentifiersToScan[j]) | |||||
| filesOrIdentifiersToScan.move (j, -1); | |||||
| } | } | ||||
| } | } | ||||
| @@ -96,49 +73,45 @@ PluginDirectoryScanner::~PluginDirectoryScanner() | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| const File PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const throw() | |||||
| const String PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const throw() | |||||
| { | { | ||||
| File* const file = filesToScan [nextIndex]; | |||||
| if (file != 0) | |||||
| return *file; | |||||
| return File::nonexistent; | |||||
| return format.getNameOfPluginFromIdentifier (filesOrIdentifiersToScan [nextIndex]); | |||||
| } | } | ||||
| bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList) | bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList) | ||||
| { | { | ||||
| File* const file = filesToScan [nextIndex]; | |||||
| String file (filesOrIdentifiersToScan [nextIndex]); | |||||
| if (file != 0) | |||||
| if (file.isNotEmpty()) | |||||
| { | { | ||||
| if (! list.isListingUpToDate (*file)) | |||||
| if (! list.isListingUpToDate (file)) | |||||
| { | { | ||||
| OwnedArray <PluginDescription> typesFound; | OwnedArray <PluginDescription> typesFound; | ||||
| // Add this plugin to the end of the dead-man's pedal list in case it crashes... | // Add this plugin to the end of the dead-man's pedal list in case it crashes... | ||||
| StringArray crashedPlugins (getDeadMansPedalFile()); | StringArray crashedPlugins (getDeadMansPedalFile()); | ||||
| crashedPlugins.removeString (file->getFullPathName()); | |||||
| crashedPlugins.add (file->getFullPathName()); | |||||
| crashedPlugins.removeString (file); | |||||
| crashedPlugins.add (file); | |||||
| setDeadMansPedalFile (crashedPlugins); | setDeadMansPedalFile (crashedPlugins); | ||||
| list.scanAndAddFile (*file, | |||||
| list.scanAndAddFile (file, | |||||
| dontRescanIfAlreadyInList, | dontRescanIfAlreadyInList, | ||||
| typesFound); | |||||
| typesFound, | |||||
| format); | |||||
| // Managed to load without crashing, so remove it from the dead-man's-pedal.. | // Managed to load without crashing, so remove it from the dead-man's-pedal.. | ||||
| crashedPlugins.removeString (file->getFullPathName()); | |||||
| crashedPlugins.removeString (file); | |||||
| setDeadMansPedalFile (crashedPlugins); | setDeadMansPedalFile (crashedPlugins); | ||||
| if (typesFound.size() == 0) | if (typesFound.size() == 0) | ||||
| failedFiles.add (file->getFullPathName()); | |||||
| failedFiles.add (file); | |||||
| } | } | ||||
| ++nextIndex; | ++nextIndex; | ||||
| progress = nextIndex / (float) filesToScan.size(); | |||||
| progress = nextIndex / (float) filesOrIdentifiersToScan.size(); | |||||
| } | } | ||||
| return nextIndex < filesToScan.size(); | |||||
| return nextIndex < filesOrIdentifiersToScan.size(); | |||||
| } | } | ||||
| const StringArray PluginDirectoryScanner::getDeadMansPedalFile() throw() | const StringArray PluginDirectoryScanner::getDeadMansPedalFile() throw() | ||||
| @@ -89,12 +89,13 @@ public: | |||||
| */ | */ | ||||
| bool scanNextFile (const bool dontRescanIfAlreadyInList); | bool scanNextFile (const bool dontRescanIfAlreadyInList); | ||||
| /** Returns the file that will be scanned during the next call to scanNextFile(). | |||||
| /** 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 | This is handy if you want to show the user which file is currently getting | ||||
| scanned. | scanned. | ||||
| */ | */ | ||||
| const File getNextPluginFileThatWillBeScanned() const throw(); | |||||
| const String getNextPluginFileThatWillBeScanned() const throw(); | |||||
| /** Returns the estimated progress, between 0 and 1. | /** Returns the estimated progress, between 0 and 1. | ||||
| */ | */ | ||||
| @@ -111,13 +112,12 @@ public: | |||||
| private: | private: | ||||
| KnownPluginList& list; | KnownPluginList& list; | ||||
| AudioPluginFormat& format; | AudioPluginFormat& format; | ||||
| OwnedArray <File> filesToScan; | |||||
| StringArray filesOrIdentifiersToScan; | |||||
| File deadMansPedalFile; | File deadMansPedalFile; | ||||
| StringArray failedFiles; | StringArray failedFiles; | ||||
| int nextIndex; | int nextIndex; | ||||
| float progress; | float progress; | ||||
| void recursiveFileSearch (const File& dir, const bool recursive); | |||||
| const StringArray getDeadMansPedalFile() throw(); | const StringArray getDeadMansPedalFile() throw(); | ||||
| void setDeadMansPedalFile (const StringArray& newContents) throw(); | void setDeadMansPedalFile (const StringArray& newContents) throw(); | ||||
| @@ -279,7 +279,7 @@ void PluginListComponent::scanFor (AudioPluginFormat* format) | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| aw.setMessage (TRANS("Testing:\n\n") | aw.setMessage (TRANS("Testing:\n\n") | ||||
| + scanner.getNextPluginFileThatWillBeScanned().getFileName()); | |||||
| + scanner.getNextPluginFileThatWillBeScanned()); | |||||
| MessageManager::getInstance()->runDispatchLoopUntil (20); | MessageManager::getInstance()->runDispatchLoopUntil (20); | ||||
| @@ -181,8 +181,8 @@ public: | |||||
| The component must already be on the desktop for this method to work. It will | The component must already be on the desktop for this method to work. It will | ||||
| be resized to completely fill the screen and any extraneous taskbars, menu bars, | be resized to completely fill the screen and any extraneous taskbars, menu bars, | ||||
| etc will be hidden. | etc will be hidden. | ||||
| To exit kiosk mode, just call setKioskModeComponent (0). When this is called, | |||||
| To exit kiosk mode, just call setKioskModeComponent (0). When this is called, | |||||
| the component that's currently being used will be resized back to the size | the component that's currently being used will be resized back to the size | ||||
| and position it was in before being put into this mode. | and position it was in before being put into this mode. | ||||
| */ | */ | ||||
| @@ -149,9 +149,9 @@ public: | |||||
| not to delete a model while it is being used. | not to delete a model while it is being used. | ||||
| An optional extra menu can be specified, containing items to add to the top of | An optional extra menu can be specified, containing items to add to the top of | ||||
| the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of | |||||
| an apple, it's the one next to it, with your application's name at the top | |||||
| and the services menu etc on it). When one of these items is selected, the | |||||
| the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of | |||||
| an apple, it's the one next to it, with your application's name at the top | |||||
| and the services menu etc on it). When one of these items is selected, the | |||||
| menu bar model will be used to invoke it, and in the menuItemSelected() callback | menu bar model will be used to invoke it, and in the menuItemSelected() callback | ||||
| the topLevelMenuIndex parameter will be -1. If you pass in an extraAppleMenuItems | the topLevelMenuIndex parameter will be -1. If you pass in an extraAppleMenuItems | ||||
| object then newMenuBarModel must be non-null. | object then newMenuBarModel must be non-null. | ||||
| @@ -113,7 +113,7 @@ public: | |||||
| { | { | ||||
| Component* const over = dynamic_cast <Component*> (currentlyOver); | Component* const over = dynamic_cast <Component*> (currentlyOver); | ||||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||||
| // a modal loop and deletes this object before the method completes) | // a modal loop and deletes this object before the method completes) | ||||
| const String dragDescLocal (dragDesc); | const String dragDescLocal (dragDesc); | ||||
| @@ -163,7 +163,7 @@ public: | |||||
| hit = hit->getComponentAt (rx, ry); | hit = hit->getComponentAt (rx, ry); | ||||
| } | } | ||||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||||
| // a modal loop and deletes this object before the method completes) | // a modal loop and deletes this object before the method completes) | ||||
| const String dragDescLocal (dragDesc); | const String dragDescLocal (dragDesc); | ||||
| @@ -234,7 +234,7 @@ public: | |||||
| if (dropAccepted && ddt != 0) | if (dropAccepted && ddt != 0) | ||||
| { | { | ||||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||||
| // a modal loop and deletes this object before the method completes) | // a modal loop and deletes this object before the method completes) | ||||
| const String dragDescLocal (dragDesc); | const String dragDescLocal (dragDesc); | ||||
| @@ -247,7 +247,7 @@ public: | |||||
| void updateLocation (const bool canDoExternalDrag, int x, int y) | void updateLocation (const bool canDoExternalDrag, int x, int y) | ||||
| { | { | ||||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||||
| // a modal loop and deletes this object before it returns) | // a modal loop and deletes this object before it returns) | ||||
| const String dragDescLocal (dragDesc); | const String dragDescLocal (dragDesc); | ||||