diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2009-01-28 15:09:36 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2009-01-28 15:09:36 +0000 |
commit | d56085060908f50be5f49021b04093596004b777 (patch) | |
tree | 857756b48bc94c9c4bf74c3ef72c96bbbe80ffaa /libs | |
parent | 7e456076abb8ec0757aa0bee6054303a52e1007a (diff) |
AU state handling, including changes to PathScanner so that it can now do recursive searches. Note that AU state handling is not built by default, and public binaries for OS X will not include it. If you build Ardour on OS X yourself, add AU_STATE=1 to your scons arguments
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@4456 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/SConscript | 3 | ||||
-rw-r--r-- | libs/ardour/ardour/audio_unit.h | 15 | ||||
-rw-r--r-- | libs/ardour/ardour/plugin.h | 3 | ||||
-rw-r--r-- | libs/ardour/audio_unit.cc | 613 | ||||
-rw-r--r-- | libs/ardour/plugin.cc | 2 | ||||
-rw-r--r-- | libs/pbd/pathscanner.cc | 86 | ||||
-rw-r--r-- | libs/pbd/pbd/pathscanner.h | 104 |
7 files changed, 741 insertions, 85 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 1610130327..100986b5db 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -23,6 +23,7 @@ ardour.Append(POTFILE = domain + '.pot') if ardour['IS_OSX']: ardour.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048") + # # explicitly reference the control protocol LGPL library for includes # @@ -253,6 +254,8 @@ if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Headers/Cor if conf.CheckCHeader('/System/Library/Frameworks/AudioUnit.framework/Headers/AudioUnit.h') and ardour['AUDIOUNITS']: ardour.Append(CXXFLAGS="-DHAVE_AUDIOUNITS") ardour.Append(LINKFLAGS="-framework AudioUnit") + if ardour['AUSTATE']: + ardour.Append(CXXFLAGS="-DAU_STATE_SUPPORT") extra_sources += audiounit_files if ardour['COREAUDIO']: diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h index 07986782e2..b100ae05ab 100644 --- a/libs/ardour/ardour/audio_unit.h +++ b/libs/ardour/ardour/audio_unit.h @@ -28,6 +28,7 @@ #include <set> #include <string> #include <vector> +#include <map> #include <ardour/plugin.h> @@ -96,7 +97,8 @@ class AUPlugin : public ARDOUR::Plugin bool save_preset (string name); bool load_preset (const string preset_label); std::vector<std::string> get_presets (); - + std::string current_preset() const; + bool has_editor () const; int32_t can_do (int32_t in, int32_t& out); @@ -115,13 +117,18 @@ class AUPlugin : public ARDOUR::Plugin private: boost::shared_ptr<CAComponent> comp; boost::shared_ptr<CAAudioUnit> unit; - + bool initialized; int32_t input_channels; int32_t output_channels; std::vector<std::pair<int,int> > io_configs; AudioBufferList* buffers; - + + /* XXX this should really be shared across all AUPlugin instances */ + + typedef std::map<std::string,std::string> PresetMap; + PresetMap preset_map; + UInt32 global_elements; UInt32 output_elements; UInt32 input_elements; @@ -167,7 +174,7 @@ class AUPluginInfo : public PluginInfo { private: boost::shared_ptr<CAComponentDescription> descriptor; UInt32 version; - + static void discover_music (PluginInfoList&); static void discover_fx (PluginInfoList&); static void discover_by_description (PluginInfoList&, CAComponentDescription&); diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index abf2867dec..c983afd4fe 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -138,6 +138,9 @@ class Plugin : public PBD::StatefulDestructible virtual bool save_preset(string name) = 0; virtual bool load_preset (const string preset_label); virtual std::vector<std::string> get_presets(); + virtual std::string current_preset() const { return std::string(); } + + static sigc::signal<bool> PresetFileExists; virtual bool has_editor() const = 0; diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc index 5d9a2d82e7..df6e13edf4 100644 --- a/libs/ardour/audio_unit.cc +++ b/libs/ardour/audio_unit.cc @@ -18,10 +18,13 @@ */ #include <sstream> +#include <errno.h> +#include <string.h> #include <pbd/transmitter.h> #include <pbd/xml++.h> #include <pbd/whitespace.h> +#include <pbd/pathscanner.h> #include <glibmm/thread.h> #include <glibmm/fileutils.h> @@ -37,6 +40,7 @@ #include <appleutility/CAAudioUnit.h> #include <appleutility/CAAUParameter.h> +#include <CoreFoundation/CoreFoundation.h> #include <CoreServices/CoreServices.h> #include <AudioUnit/AudioUnit.h> @@ -46,8 +50,19 @@ using namespace std; using namespace PBD; using namespace ARDOUR; +#ifndef AU_STATE_SUPPORT +static bool seen_get_state_message = false; +static bool seen_set_state_message = false; +static bool seen_loading_message = false; +static bool seen_saving_message = false; +#endif + AUPluginInfo::CachedInfoMap AUPluginInfo::cached_info; +static string preset_search_path = "/Library/Audio/Presets:/Network/Library/Audio/Presets"; +static string preset_suffix = ".aupreset"; +static bool preset_search_path_initialized = false; + static OSStatus _render_callback(void *userData, AudioUnitRenderActionFlags *ioActionFlags, @@ -59,6 +74,212 @@ _render_callback(void *userData, return ((AUPlugin*)userData)->render_callback (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); } +static int +save_property_list (CFPropertyListRef propertyList, Glib::ustring path) + +{ + CFDataRef xmlData; + int fd; + + // Convert the property list into XML data. + + xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, propertyList); + + if (!xmlData) { + error << _("Could not create XML version of property list") << endmsg; + return -1; + } + + // Write the XML data to the file. + + fd = open (path.c_str(), O_WRONLY|O_CREAT|O_EXCL, 0664); + while (fd < 0) { + if (errno == EEXIST) { + /* tell any UI's that this file already exists and ask them what to do */ + bool overwrite = Plugin::PresetFileExists(); // EMIT SIGNAL + if (overwrite) { + fd = open (path.c_str(), O_WRONLY, 0664); + continue; + } else { + return 0; + } + } + error << string_compose (_("Cannot open preset file %1 (%2)"), path, strerror (errno)) << endmsg; + CFRelease (xmlData); + return -1; + } + + size_t cnt = CFDataGetLength (xmlData); + + if (write (fd, CFDataGetBytePtr (xmlData), cnt) != cnt) { + CFRelease (xmlData); + close (fd); + return -1; + } + + close (fd); + return 0; +} + + +static CFPropertyListRef +load_property_list (Glib::ustring path) +{ + int fd; + CFPropertyListRef propertyList; + CFDataRef xmlData; + CFStringRef errorString; + + // Read the XML file. + + if ((fd = open (path.c_str(), O_RDONLY)) < 0) { + return propertyList; + + } + + off_t len = lseek (fd, 0, SEEK_END); + char* buf = new char[len]; + lseek (fd, 0, SEEK_SET); + + if (read (fd, buf, len) != len) { + delete [] buf; + close (fd); + return propertyList; + } + + close (fd); + + xmlData = CFDataCreateWithBytesNoCopy (kCFAllocatorDefault, (UInt8*) buf, len, kCFAllocatorNull); + + // Reconstitute the dictionary using the XML data. + + propertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, + xmlData, + kCFPropertyListImmutable, + &errorString); + + CFRelease (xmlData); + delete [] buf; + + return propertyList; +} + +//----------------------------------------------------------------------------- +static void +set_preset_name_in_plist (CFPropertyListRef plist, string preset_name) +{ + if (!plist) { + return; + } + CFStringRef pn = CFStringCreateWithCString (kCFAllocatorDefault, preset_name.c_str(), kCFStringEncodingUTF8); + + if (CFGetTypeID (plist) == CFDictionaryGetTypeID()) { + CFDictionarySetValue ((CFMutableDictionaryRef)plist, CFSTR(kAUPresetNameKey), pn); + } + + CFRelease (pn); +} + +//----------------------------------------------------------------------------- +static std::string +get_preset_name_in_plist (CFPropertyListRef plist) +{ + std::string ret; + + if (!plist) { + return ret; + } + + if (CFGetTypeID (plist) == CFDictionaryGetTypeID()) { + const void *p = CFDictionaryGetValue ((CFMutableDictionaryRef)plist, CFSTR(kAUPresetNameKey)); + if (p) { + CFStringRef str = (CFStringRef) p; + int len = CFStringGetLength(str); + len = (len * 2) + 1; + char local_buffer[len]; + if (CFStringGetCString (str, local_buffer, len, kCFStringEncodingUTF8)) { + ret = local_buffer; + } + } + } + return ret; +} + +//-------------------------------------------------------------------------- +// general implementation for ComponentDescriptionsMatch() and ComponentDescriptionsMatch_Loosely() +// if inIgnoreType is true, then the type code is ignored in the ComponentDescriptions +Boolean ComponentDescriptionsMatch_General(const ComponentDescription * inComponentDescription1, const ComponentDescription * inComponentDescription2, Boolean inIgnoreType); +Boolean ComponentDescriptionsMatch_General(const ComponentDescription * inComponentDescription1, const ComponentDescription * inComponentDescription2, Boolean inIgnoreType) +{ + if ( (inComponentDescription1 == NULL) || (inComponentDescription2 == NULL) ) + return FALSE; + + if ( (inComponentDescription1->componentSubType == inComponentDescription2->componentSubType) + && (inComponentDescription1->componentManufacturer == inComponentDescription2->componentManufacturer) ) + { + // only sub-type and manufacturer IDs need to be equal + if (inIgnoreType) + return TRUE; + // type, sub-type, and manufacturer IDs all need to be equal in order to call this a match + else if (inComponentDescription1->componentType == inComponentDescription2->componentType) + return TRUE; + } + + return FALSE; +} + +//-------------------------------------------------------------------------- +// general implementation for ComponentAndDescriptionMatch() and ComponentAndDescriptionMatch_Loosely() +// if inIgnoreType is true, then the type code is ignored in the ComponentDescriptions +Boolean ComponentAndDescriptionMatch_General(Component inComponent, const ComponentDescription * inComponentDescription, Boolean inIgnoreType); +Boolean ComponentAndDescriptionMatch_General(Component inComponent, const ComponentDescription * inComponentDescription, Boolean inIgnoreType) +{ + OSErr status; + ComponentDescription desc; + + if ( (inComponent == NULL) || (inComponentDescription == NULL) ) + return FALSE; + + // get the ComponentDescription of the input Component + status = GetComponentInfo(inComponent, &desc, NULL, NULL, NULL); + if (status != noErr) + return FALSE; + + // check if the Component's ComponentDescription matches the input ComponentDescription + return ComponentDescriptionsMatch_General(&desc, inComponentDescription, inIgnoreType); +} + +//-------------------------------------------------------------------------- +// determine if 2 ComponentDescriptions are basically equal +// (by that, I mean that the important identifying values are compared, +// but not the ComponentDescription flags) +Boolean ComponentDescriptionsMatch(const ComponentDescription * inComponentDescription1, const ComponentDescription * inComponentDescription2) +{ + return ComponentDescriptionsMatch_General(inComponentDescription1, inComponentDescription2, FALSE); +} + +//-------------------------------------------------------------------------- +// determine if 2 ComponentDescriptions have matching sub-type and manufacturer codes +Boolean ComponentDescriptionsMatch_Loose(const ComponentDescription * inComponentDescription1, const ComponentDescription * inComponentDescription2) +{ + return ComponentDescriptionsMatch_General(inComponentDescription1, inComponentDescription2, TRUE); +} + +//-------------------------------------------------------------------------- +// determine if a ComponentDescription basically matches that of a particular Component +Boolean ComponentAndDescriptionMatch(Component inComponent, const ComponentDescription * inComponentDescription) +{ + return ComponentAndDescriptionMatch_General(inComponent, inComponentDescription, FALSE); +} + +//-------------------------------------------------------------------------- +// determine if a ComponentDescription matches only the sub-type and manufacturer codes of a particular Component +Boolean ComponentAndDescriptionMatch_Loosely(Component inComponent, const ComponentDescription * inComponentDescription) +{ + return ComponentAndDescriptionMatch_General(inComponent, inComponentDescription, TRUE); +} + + AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAComponent> _comp) : Plugin (engine, session), comp (_comp), @@ -70,6 +291,14 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAC current_buffers (0), frames_processed (0) { + if (!preset_search_path_initialized) { + Glib::ustring p = Glib::get_home_dir(); + p += "/Library/Audio/Presets:"; + p += preset_search_path; + preset_search_path = p; + preset_search_path_initialized = true; + } + init (); } @@ -109,7 +338,6 @@ AUPlugin::init () err = CAAudioUnit::Open (*(comp.get()), *unit); } catch (...) { error << _("Exception thrown during AudioUnit plugin loading - plugin ignored") << endmsg; - cerr << _("Exception thrown during AudioUnit plugin loading - plugin ignored") << endl; throw failed_constructor(); } @@ -762,33 +990,406 @@ AUPlugin::parameter_is_output (uint32_t) const XMLNode& AUPlugin::get_state() { - XMLNode *root = new XMLNode (state_node_name()); LocaleGuard lg (X_("POSIX")); + XMLNode *root = new XMLNode (state_node_name()); + +#ifdef AU_STATE_SUPPORT + CFDataRef xmlData; + CFPropertyListRef propertyList; + + if (unit->GetAUPreset (propertyList) != noErr) { + return *root; + } + + // Convert the property list into XML data. + + xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, propertyList); + + if (!xmlData) { + error << _("Could not create XML version of property list") << endmsg; + return *root; + } + + /* re-parse XML bytes to create a libxml++ XMLTree that we can merge into + our state node. GACK! + */ + + XMLTree t; + + if (t.read_buffer (string ((const char*) CFDataGetBytePtr (xmlData), CFDataGetLength (xmlData)))) { + if (t.root()) { + root->add_child_copy (*t.root()); + } + } + + CFRelease (xmlData); + CFRelease (propertyList); +#else + if (!seen_get_state_message) { + info << _("Saving AudioUnit settings is not supported in this build of Ardour. Consider paying for a newer version") + << endmsg; + seen_get_state_message = true; + } +#endif + return *root; } int AUPlugin::set_state(const XMLNode& node) { - return -1; +#ifdef AU_STATE_SUPPORT + int ret = -1; + CFPropertyListRef propertyList; + LocaleGuard lg (X_("POSIX")); + + if (node.name() != state_node_name()) { + error << _("Bad node sent to AUPlugin::set_state") << endmsg; + return -1; + } + + if (node.children().empty()) { + return -1; + } + + XMLNode* top = node.children().front(); + XMLNode* copy = new XMLNode (*top); + + XMLTree t; + t.set_root (copy); + + const string& xml = t.write_buffer (); + CFDataRef xmlData = CFDataCreateWithBytesNoCopy (kCFAllocatorDefault, (UInt8*) xml.data(), xml.length(), kCFAllocatorNull); + CFStringRef errorString; + + propertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, + xmlData, + kCFPropertyListImmutable, + &errorString); + + CFRelease (xmlData); + + if (propertyList) { + if (unit->SetAUPreset (propertyList) == noErr) { + ret = 0; + } + CFRelease (propertyList); + } + + return ret; +#else + if (!seen_set_state_message) { + info << _("Restoring AudioUnit settings is not supported in this build of Ardour. Consider paying for a newer version") + << endmsg; + } + return 0; +#endif } bool -AUPlugin::save_preset (string name) +AUPlugin::load_preset (const string preset_label) { - return false; +#ifdef AU_STATE_SUPPORT + bool ret = false; + CFPropertyListRef propertyList; + Glib::ustring path; + PresetMap::iterator x = preset_map.find (preset_label); + + if (x == preset_map.end()) { + return false; + } + + if ((propertyList = load_property_list (x->second)) != 0) { + if (unit->SetAUPreset (propertyList) == noErr) { + ret = true; + } + CFRelease(propertyList); + } + + return ret; +#else + if (!seen_loading_message) { + info << _("Loading AudioUnit presets is not supported in this build of Ardour. Consider paying for a newer version") + << endmsg; + seen_loading_message = true; + } + return true; +#endif } bool -AUPlugin::load_preset (const string preset_label) +AUPlugin::save_preset (string preset_name) { +#ifdef AU_STATE_SUPPORT + CFPropertyListRef propertyList; + vector<Glib::ustring> v; + Glib::ustring user_preset_path; + bool ret = true; + + std::string m = maker(); + std::string n = name(); + + strip_whitespace_edges (m); + strip_whitespace_edges (n); + + v.push_back (Glib::get_home_dir()); + v.push_back ("Library"); + v.push_back ("Audio"); + v.push_back ("Presets"); + v.push_back (m); + v.push_back (n); + + user_preset_path = Glib::build_filename (v); + + if (g_mkdir_with_parents (user_preset_path.c_str(), 0775) < 0) { + error << string_compose (_("Cannot create user plugin presets folder (%1)"), user_preset_path) << endmsg; + return false; + } + + if (unit->GetAUPreset (propertyList) != noErr) { + return false; + } + + // add the actual preset name */ + + v.push_back (preset_name + preset_suffix); + + // rebuild + + user_preset_path = Glib::build_filename (v); + + set_preset_name_in_plist (propertyList, preset_name); + + if (save_property_list (propertyList, user_preset_path)) { + error << string_compose (_("Saving plugin state to %1 failed"), user_preset_path) << endmsg; + ret = false; + } + + CFRelease(propertyList); + + return ret; +#else + if (!seen_saving_message) { + info << _("Saving AudioUnit presets is not supported in this build of Ardour. Consider paying for a newer version") + << endmsg; + seen_saving_message = true; + } return false; +#endif +} + +//----------------------------------------------------------------------------- +// this is just a little helper function used by GetAUComponentDescriptionFromPresetFile() +static SInt32 +GetDictionarySInt32Value(CFDictionaryRef inAUStateDictionary, CFStringRef inDictionaryKey, Boolean * outSuccess) +{ + CFNumberRef cfNumber; + SInt32 numberValue = 0; + Boolean dummySuccess; + + if (outSuccess == NULL) + outSuccess = &dummySuccess; + if ( (inAUStateDictionary == NULL) || (inDictionaryKey == NULL) ) + { + *outSuccess = FALSE; + return 0; + } + + cfNumber = (CFNumberRef) CFDictionaryGetValue(inAUStateDictionary, inDictionaryKey); + if (cfNumber == NULL) + { + *outSuccess = FALSE; + return 0; + } + *outSuccess = CFNumberGetValue(cfNumber, kCFNumberSInt32Type, &numberValue); + if (*outSuccess) + return numberValue; + else + return 0; +} + +static OSStatus +GetAUComponentDescriptionFromStateData(CFPropertyListRef inAUStateData, ComponentDescription * outComponentDescription) +{ + CFDictionaryRef auStateDictionary; + ComponentDescription tempDesc = {0}; + SInt32 versionValue; + Boolean gotValue; + + if ( (inAUStateData == NULL) || (outComponentDescription == NULL) ) + return paramErr; + + // the property list for AU state data must be of the dictionary type + if (CFGetTypeID(inAUStateData) != CFDictionaryGetTypeID()) { + return kAudioUnitErr_InvalidPropertyValue; + } + + auStateDictionary = (CFDictionaryRef)inAUStateData; + + // first check to make sure that the version of the AU state data is one that we know understand + // XXX should I really do this? later versions would probably still hold these ID keys, right? + versionValue = GetDictionarySInt32Value(auStateDictionary, CFSTR(kAUPresetVersionKey), &gotValue); + + if (!gotValue) { + return kAudioUnitErr_InvalidPropertyValue; + } +#define kCurrentSavedStateVersion 0 + if (versionValue != kCurrentSavedStateVersion) { + return kAudioUnitErr_InvalidPropertyValue; + } + + // grab the ComponentDescription values from the AU state data + tempDesc.componentType = (OSType) GetDictionarySInt32Value(auStateDictionary, CFSTR(kAUPresetTypeKey), NULL); + tempDesc.componentSubType = (OSType) GetDictionarySInt32Value(auStateDictionary, CFSTR(kAUPresetSubtypeKey), NULL); + tempDesc.componentManufacturer = (OSType) GetDictionarySInt32Value(auStateDictionary, CFSTR(kAUPresetManufacturerKey), NULL); + // zero values are illegit for specific ComponentDescriptions, so zero for any value means that there was an error + if ( (tempDesc.componentType == 0) || (tempDesc.componentSubType == 0) || (tempDesc.componentManufacturer == 0) ) + return kAudioUnitErr_InvalidPropertyValue; + + *outComponentDescription = tempDesc; + return noErr; +} + + +static bool au_preset_filter (const string& str, void* arg) +{ + /* Not a dotfile, has a prefix before a period, suffix is aupreset */ + + bool ret; + + ret = (str[0] != '.' && str.length() > 9 && str.find (preset_suffix) == (str.length() - preset_suffix.length())); + + if (ret && arg) { + + /* check the preset file path name against this plugin + ID. The idea is that all preset files for this plugin + include "<manufacturer>/<plugin-name>" in their path. + */ + + Plugin* p = (Plugin *) arg; + string match = p->maker(); + match += '/'; + match += p->name(); + + ret = str.find (match) != string::npos; + + if (ret == false) { + string m = p->maker (); + string n = p->name (); + strip_whitespace_edges (m); + strip_whitespace_edges (n); + match = m; + match += '/'; + match += n; + + ret = str.find (match) != string::npos; + } + } + + return ret; +} + +bool +check_and_get_preset_name (Component component, const string& pathstr, string& preset_name) +{ + OSStatus status; + CFPropertyListRef plist; + ComponentDescription presetDesc; + bool ret = false; + + plist = load_property_list (pathstr); + + if (!plist) { + return ret; + } + + // get the ComponentDescription from the AU preset file + + status = GetAUComponentDescriptionFromStateData(plist, &presetDesc); + + if (status == noErr) { + if (ComponentAndDescriptionMatch_Loosely(component, &presetDesc)) { + + /* try to get the preset name from the property list */ + + if (CFGetTypeID(plist) == CFDictionaryGetTypeID()) { + + const void* psk = CFDictionaryGetValue ((CFMutableDictionaryRef)plist, CFSTR(kAUPresetNameKey)); + + if (psk) { + + const char* p = CFStringGetCStringPtr ((CFStringRef) psk, kCFStringEncodingUTF8); + + if (!p) { + char buf[PATH_MAX+1]; + + if (CFStringGetCString ((CFStringRef)psk, buf, sizeof (buf), kCFStringEncodingUTF8)) { + preset_name = buf; + } + } + } + } + } + } + + CFRelease (plist); + + return true; +} + +std::string +AUPlugin::current_preset() const +{ + string preset_name; + +#ifdef AU_STATE_SUPPORT + CFPropertyListRef propertyList; + + if (unit->GetAUPreset (propertyList) == noErr) { + preset_name = get_preset_name_in_plist (propertyList); + CFRelease(propertyList); + } +#endif + return preset_name; } vector<string> AUPlugin::get_presets () { + vector<string*>* preset_files; vector<string> presets; + PathScanner scanner; + + preset_files = scanner (preset_search_path, au_preset_filter, this, true, true, -1, true); + + if (!preset_files) { + return presets; + } + + for (vector<string*>::iterator x = preset_files->begin(); x != preset_files->end(); ++x) { + + string path = *(*x); + string preset_name; + + /* make an initial guess at the preset name using the path */ + + preset_name = Glib::path_get_basename (path); + preset_name = preset_name.substr (0, preset_name.find_last_of ('.')); + + /* check that this preset file really matches this plugin + and potentially get the "real" preset name from + within the file. + */ + + if (check_and_get_preset_name (get_comp()->Comp(), path, preset_name)) { + presets.push_back (preset_name); + preset_map[preset_name] = path; + } + + delete *x; + } + + delete preset_files; return presets; } diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 9fd1707176..79f17ff8ca 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -58,6 +58,8 @@ using namespace ARDOUR; using namespace PBD; +sigc::signal<bool> Plugin::PresetFileExists; + Plugin::Plugin (AudioEngine& e, Session& s) : _engine (e), _session (s) { diff --git a/libs/pbd/pathscanner.cc b/libs/pbd/pathscanner.cc index 1a9cb985c1..8f37477147 100644 --- a/libs/pbd/pathscanner.cc +++ b/libs/pbd/pathscanner.cc @@ -23,6 +23,8 @@ #include <cstring> #include <vector> #include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> #include <pbd/error.h> #include <pbd/pathscanner.h> @@ -33,7 +35,7 @@ using namespace PBD; vector<string *> * PathScanner::operator() (const string &dirpath, const string ®exp, bool match_fullpath, bool return_fullpath, - long limit) + long limit, bool recurse) { int err; @@ -58,7 +60,7 @@ PathScanner::operator() (const string &dirpath, const string ®exp, 0, match_fullpath, return_fullpath, - limit); + limit, recurse); } vector<string *> * @@ -67,10 +69,22 @@ PathScanner::run_scan (const string &dirpath, bool (*filter)(const string &, void *), void *arg, bool match_fullpath, bool return_fullpath, - long limit) - + long limit, + bool recurse) +{ + return run_scan_internal ((vector<string*>*) 0, dirpath, memberfilter, filter, arg, match_fullpath, return_fullpath, limit, recurse); +} + +vector<string *> * +PathScanner::run_scan_internal (vector<string *> *result, + const string &dirpath, + bool (PathScanner::*memberfilter)(const string &), + bool (*filter)(const string &, void *), + void *arg, + bool match_fullpath, bool return_fullpath, + long limit, + bool recurse) { - vector<string *> *result = 0; DIR *dir; struct dirent *finfo; char *pathcopy = strdup (dirpath.c_str()); @@ -86,7 +100,9 @@ PathScanner::run_scan (const string &dirpath, return 0; } - result = new vector<string *>; + if (result == 0) { + result = new vector<string *>; + } do { @@ -96,37 +112,51 @@ PathScanner::run_scan (const string &dirpath, while ((finfo = readdir (dir)) != 0) { + if ((finfo->d_name[0] == '.' && finfo->d_name[1] == '\0') || + (finfo->d_name[0] == '.' && finfo->d_name[1] == '.' && finfo->d_name[2] == '\0')) { + continue; + } + snprintf (fullpath, sizeof(fullpath), "%s/%s", thisdir, finfo->d_name); - if (match_fullpath) { - search_str = fullpath; - } else { - search_str = finfo->d_name; + struct stat statbuf; + if (stat (fullpath, &statbuf) < 0) { + continue; } - /* handle either type of function ptr */ - - if (memberfilter) { - if (!(this->*memberfilter)(search_str)) { - continue; - } + if (statbuf.st_mode & S_IFDIR && recurse) { + run_scan_internal (result, fullpath, memberfilter, filter, arg, match_fullpath, return_fullpath, limit, recurse); } else { - if (!filter(search_str, arg)) { - continue; + + if (match_fullpath) { + search_str = fullpath; + } else { + search_str = finfo->d_name; } + + /* handle either type of function ptr */ + + if (memberfilter) { + if (!(this->*memberfilter)(search_str)) { + continue; + } + } else { + if (!filter(search_str, arg)) { + continue; + } + } + + if (return_fullpath) { + newstr = new string (fullpath); + } else { + newstr = new string (finfo->d_name); + } + + result->push_back (newstr); + nfound++; } - - if (return_fullpath) { - newstr = new string (fullpath); - } else { - newstr = new string (finfo->d_name); - } - - result->push_back (newstr); - nfound++; } - closedir (dir); } while ((limit < 0 || (nfound < limit)) && (thisdir = strtok (0, ":"))); diff --git a/libs/pbd/pbd/pathscanner.h b/libs/pbd/pbd/pathscanner.h index 0a48d4d949..550aab163a 100644 --- a/libs/pbd/pbd/pathscanner.h +++ b/libs/pbd/pbd/pathscanner.h @@ -31,55 +31,65 @@ class PathScanner { public: - vector<string *> *operator() (const string &dirpath, - bool (*filter)(const string &, void *arg), - void *arg, - bool match_fullpath = true, - bool return_fullpath = true, - long limit = -1) { - return run_scan (dirpath, - (bool (PathScanner::*)(const string &)) 0, - filter, - arg, - match_fullpath, - return_fullpath, - limit); - } - - vector<string *> *operator() (const string &dirpath, - const string ®exp, - bool match_fullpath = true, - bool return_fullpath = true, - long limit = -1); - + vector<string *> *operator() (const string &dirpath, + bool (*filter)(const string &, void *arg), + void *arg, + bool match_fullpath = true, + bool return_fullpath = true, + long limit = -1, + bool recurse = false) { + return run_scan (dirpath, + (bool (PathScanner::*)(const string &)) 0, + filter, + arg, + match_fullpath, + return_fullpath, + limit, recurse); + } + + vector<string *> *operator() (const string &dirpath, + const string ®exp, + bool match_fullpath = true, + bool return_fullpath = true, + long limit = -1, + bool recurse = false); - string *find_first (const string &dirpath, - const string ®exp, - bool match_fullpath = true, - bool return_fullpath = true); - - string *find_first (const string &dirpath, - bool (*filter)(const string &, void *), - void *arg, - bool match_fullpath = true, - bool return_fullpath = true); - + string *find_first (const string &dirpath, + const string ®exp, + bool match_fullpath = true, + bool return_fullpath = true); + + string *find_first (const string &dirpath, + bool (*filter)(const string &, void *), + void *arg, + bool match_fullpath = true, + bool return_fullpath = true); + private: - regex_t compiled_pattern; - - bool regexp_filter (const string &str) { - return regexec (&compiled_pattern, str.c_str(), 0, 0, 0) == 0; - } - - vector<string *> *run_scan (const string &dirpath, - bool (PathScanner::*mfilter) (const string &), - bool (*filter)(const string &, void *), - void *arg, - bool match_fullpath, - bool return_fullpath, - long limit); - - + regex_t compiled_pattern; + + bool regexp_filter (const string &str) { + return regexec (&compiled_pattern, str.c_str(), 0, 0, 0) == 0; + } + + vector<string *> *run_scan (const string &dirpath, + bool (PathScanner::*mfilter) (const string &), + bool (*filter)(const string &, void *), + void *arg, + bool match_fullpath, + bool return_fullpath, + long limit, + bool recurse = false); + + vector<string *> *run_scan_internal (vector<string*>*, + const string &dirpath, + bool (PathScanner::*mfilter) (const string &), + bool (*filter)(const string &, void *), + void *arg, + bool match_fullpath, + bool return_fullpath, + long limit, + bool recurse = false); }; #endif // __libmisc_pathscanner_h__ |