diff --git a/SpiralSound/Plugins/LADSPAPlugin/LADSPAInfo.C b/SpiralSound/Plugins/LADSPAPlugin/LADSPAInfo.C index f809509..09405a0 100644 --- a/SpiralSound/Plugins/LADSPAPlugin/LADSPAInfo.C +++ b/SpiralSound/Plugins/LADSPAPlugin/LADSPAInfo.C @@ -1,28 +1,31 @@ -/* - LADSPAInfo.C - Class for indexing information on LADSPA Plugins - - Copyright (C) 2002 Mike Rawes - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +// +// LADSPAInfo.C - Class for indexing information on LADSPA Plugins +// +// Copyleft (C) 2002 Mike Rawes +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +#include #include #include +#include +#include #include #include -#include #include #include @@ -44,269 +47,394 @@ using namespace std; LADSPAInfo::LADSPAInfo(bool override, const char *path_list) { - if (strlen(path_list) > 0) { - m_ExtraPaths = strdup(path_list); - } else { - m_ExtraPaths = NULL; - } - m_LADSPAPathOverride = override; - -#ifdef HAVE_LIBLRDF - lrdf_init(); -#endif - - RescanPlugins(); + if (strlen(path_list) > 0) { + m_ExtraPaths = strdup(path_list); + } else { + m_ExtraPaths = NULL; + } + m_LADSPAPathOverride = override; + + RescanPlugins(); } LADSPAInfo::~LADSPAInfo() { - CleanUp(); -} - -void -LADSPAInfo::PrintInfo(void) -{ - cout << "LADSPA Plugin Info" << endl; - cout << endl; - cout << " Paths:" << endl; - for (vector::iterator p = m_Paths.begin(); p != m_Paths.end(); p++) { - cout << " " << *p << endl; - } - cout << endl; - cout << " Libraries:" << endl; - for (vector::iterator l = m_Libraries.begin(); l != m_Libraries.end(); l++) { - cout << " " << m_Paths[l->PathIndex] << l->Basename << ": " << "Refs: " << l->RefCount << endl; - } - cout << endl; - cout << " Plugins:" << endl; - for (vector::iterator p = m_Plugins.begin(); p != m_Plugins.end(); p++) { - cout << " " << m_Paths[m_Libraries[p->LibraryIndex].PathIndex] - << m_Libraries[p->LibraryIndex].Basename - << ": " << p->Index << endl; - } + CleanUp(); } void LADSPAInfo::RescanPlugins(void) { // Clear out what we've got - CleanUp(); + CleanUp(); - if (!m_LADSPAPathOverride) { - // Get $LADPSA_PATH, if available - char *ladspa_path = getenv("LADSPA_PATH"); - if (!ladspa_path) { + if (!m_LADSPAPathOverride) { + // Get $LADPSA_PATH, if available + char *ladspa_path = getenv("LADSPA_PATH"); + if (!ladspa_path) { - // Oops - cerr << "WARNING: LADSPA_PATH environment variable not set" << endl; - } + // Oops + cerr << "WARNING: LADSPA_PATH environment variable not set" << endl; + } - // Extract path elements and add path - if (ladspa_path) { - ScanPathList(ladspa_path, &LADSPAInfo::ExaminePluginLibrary); - } - } + // Extract path elements and add path + if (ladspa_path) { + ScanPathList(ladspa_path, &LADSPAInfo::ExaminePluginLibrary); + } + } // Check any supplied extra paths - if (m_ExtraPaths) { - ScanPathList(m_ExtraPaths, &LADSPAInfo::ExaminePluginLibrary); - } + if (m_ExtraPaths) { + ScanPathList(m_ExtraPaths, &LADSPAInfo::ExaminePluginLibrary); + } // Do we have any plugins now? - if (m_Plugins.size() == 0) { - cerr << "WARNING: No plugins found" << endl; - } else { - cerr << m_Plugins.size() << " plugins found in " << m_Libraries.size() << " libraries" << endl; + if (m_Plugins.size() == 0) { + cerr << "WARNING: No plugins found" << endl; + } else { + cerr << m_Plugins.size() << " plugins found in " << m_Libraries.size() << " libraries" << endl; #ifdef HAVE_LIBLRDF - // Got some plugins. Now search for RDF data - char *rdf_path = getenv("LADSPA_RDF_PATH"); - - if (!rdf_path) { - cerr << "WARNING: LADSPA_RDF_PATH environment variable set" << endl; - } else { - - // Examine rdf info - ScanPathList(rdf_path, &LADSPAInfo::ExamineRDFFile); - } + // Got some plugins. Now search for RDF data + lrdf_init(); + + char *rdf_path = getenv("LADSPA_RDF_PATH"); + + if (!rdf_path) { + cerr << "WARNING: LADSPA_RDF_PATH environment variable not set" << endl; + + } else { + + // Examine rdf info + ScanPathList(rdf_path, &LADSPAInfo::ExamineRDFFile); + } + MetadataRDFDescend(LADSPA_BASE "Plugin", 0); + + // See which plugins were not added to an rdf group, and add them + // all into the top level 'LADSPA' one + list rdf_p; + + // Get indices of plugins added to groups + for (vector::iterator ri = m_RDFURIs.begin(); ri != m_RDFURIs.end(); ri++) { + rdf_p.insert(rdf_p.begin(), ri->Plugins.begin(), ri->Plugins.end()); + } + + // Add all uncategorized plugins to top level group, subclassed by their + // library's basename. + rdf_p.unique(); + rdf_p.sort(); + unsigned long last_p = 0; + for (list::iterator p = rdf_p.begin(); p != rdf_p.end(); p++) { + if ((*p - last_p) > 1) { + for (unsigned long i = last_p + 1; i < *p; i++) { + // URI 0 is top-level "LADSPA" group + m_RDFURIs[0].Plugins.push_back(i); + } + } + last_p = *p; + } + while (++last_p < m_Plugins.size()) { + // URI 0 is top-level "LADSPA" group + m_RDFURIs[0].Plugins.push_back(last_p); + } + + lrdf_cleanup(); +#else + // No RDF. Add all plugins to top-level group + RDFURIInfo ri; + + ri.URI = ""; + ri.Label = "LADSPA"; + + m_RDFURIs.push_back(ri); + m_RDFLabelLookup["LADSPA"] = 0; + + for (unsigned long i = 0; i < m_Plugins.size(); i++) { + // Add plugin index + m_RDFURIs[0].Plugins.push_back(i); + } #endif - } - -// Sort list by name - sort(m_OrderedPluginList.begin(), m_OrderedPluginList.end(), PluginEntrySortAsc()); - -// Deal with duplicates by numbering them - for (vector::iterator i = m_OrderedPluginList.begin(); - i != m_OrderedPluginList.end(); ) { - string name = i->Name; - - i++; - unsigned long n = 2; - while ((i != m_OrderedPluginList.end()) && (i->Name == name)) { - stringstream s; - s << n; - i->Name = name + " (" + s.str() + ")"; - n++; - i++; - } - } + } } void LADSPAInfo::UnloadAllLibraries(void) { - for (vector::iterator i = m_Libraries.begin(); - i != m_Libraries.end(); i++) { - if (i->Handle) dlclose(i->Handle); - i->RefCount = 0; - } +// Blank descriptors + for (vector::iterator i = m_Plugins.begin(); + i != m_Plugins.end(); i++) { + if (i->Descriptor) i->Descriptor = NULL; + } +// Unload DLLs, + for (vector::iterator i = m_Libraries.begin(); + i != m_Libraries.end(); i++) { + if (i->Handle) { + dlclose(i->Handle); + i->Handle = NULL; + } + i->RefCount = 0; + } } const LADSPA_Descriptor * LADSPAInfo::GetDescriptorByID(unsigned long unique_id) { - if (m_IDLookup.find(unique_id) == m_IDLookup.end()) { - cerr << "LADSPA Plugin ID " << unique_id << " not found!" << endl; - return NULL; - } + if (m_IDLookup.find(unique_id) == m_IDLookup.end()) { + cerr << "LADSPA Plugin ID " << unique_id << " not found!" << endl; + return NULL; + } // Got plugin index - unsigned long plugin_index = m_IDLookup[unique_id]; - - PluginInfo *pi = &(m_Plugins[plugin_index]); - LibraryInfo *li = &(m_Libraries[pi->LibraryIndex]); + unsigned long plugin_index = m_IDLookup[unique_id]; - if (!(pi->Descriptor)) { - LADSPA_Descriptor_Function desc_func = GetDescriptorFunctionForLibrary(pi->LibraryIndex); + PluginInfo *pi = &(m_Plugins[plugin_index]); + LibraryInfo *li = &(m_Libraries[pi->LibraryIndex]); - if (desc_func) pi->Descriptor = desc_func(pi->Index); - } + if (!(pi->Descriptor)) { + LADSPA_Descriptor_Function desc_func = GetDescriptorFunctionForLibrary(pi->LibraryIndex); + if (desc_func) pi->Descriptor = desc_func(pi->Index); + } - if (pi->Descriptor) { + if (pi->Descriptor) { - // Success, so increment ref counter for library - li->RefCount++; - } + // Success, so increment ref counter for library + li->RefCount++; + } - return pi->Descriptor; + return pi->Descriptor; } void LADSPAInfo::DiscardDescriptorByID(unsigned long unique_id) { - if (m_IDLookup.find(unique_id) == m_IDLookup.end()) { - cerr << "LADSPA Plugin ID " << unique_id << " not found!" << endl; - } else { - - // Get plugin index - unsigned long plugin_index = m_IDLookup[unique_id]; - - PluginInfo *pi = &(m_Plugins[plugin_index]); - LibraryInfo *li = &(m_Libraries[pi->LibraryIndex]); - - // Decrement reference counter for library, and unload if last - if (li->RefCount > 0) { - li->RefCount--; - if (li->RefCount == 0) { - - // Unload and clear library handle - dlclose(li->Handle); - li->Handle = NULL; - } - } - } + if (m_IDLookup.find(unique_id) == m_IDLookup.end()) { + cerr << "LADSPA Plugin ID " << unique_id << " not found!" << endl; + } else { + + // Get plugin index + unsigned long plugin_index = m_IDLookup[unique_id]; + + PluginInfo *pi = &(m_Plugins[plugin_index]); + LibraryInfo *li = &(m_Libraries[pi->LibraryIndex]); + + pi->Descriptor = NULL; + + // Decrement reference counter for library, and unload if last + if (li->RefCount > 0) { + li->RefCount--; + if (li->RefCount == 0) { + + // Unload library + dlclose(li->Handle); + li->Handle = NULL; + } + } + } } +// **************************************************************************** +// ** SSM Specific Functions ** +// **************************************************************************** + unsigned long LADSPAInfo::GetIDFromFilenameAndLabel(std::string filename, std::string label) { - bool library_loaded = false; + bool library_loaded = false; - if (m_FilenameLookup.find(filename) == m_FilenameLookup.end()) { - cerr << "LADSPA Library " << filename << " not found!" << endl; - return 0; - } + if (m_FilenameLookup.find(filename) == m_FilenameLookup.end()) { + cerr << "LADSPA Library " << filename << " not found!" << endl; + return 0; + } - unsigned long library_index = m_FilenameLookup[filename]; + unsigned long library_index = m_FilenameLookup[filename]; - if (!(m_Libraries[library_index].Handle)) library_loaded = true; + if (!(m_Libraries[library_index].Handle)) library_loaded = true; - LADSPA_Descriptor_Function desc_func = GetDescriptorFunctionForLibrary(library_index); + LADSPA_Descriptor_Function desc_func = GetDescriptorFunctionForLibrary(library_index); - if (!desc_func) { - return 0; - } + if (!desc_func) { + return 0; + } // Search for label in library - const LADSPA_Descriptor *desc; - for (unsigned long i = 0; (desc = desc_func(i)) != NULL; i++) { - string l = desc->Label; - if (l == label) { - - // If we had to load the library, unload it - unsigned long id = desc->UniqueID; - if (library_loaded) { - dlclose(m_Libraries[library_index].Handle); - m_Libraries[library_index].Handle = NULL; - } - return id; - } - } - - cerr << "Plugin " << label << " not found in library " << filename << endl; - return 0; + const LADSPA_Descriptor *desc; + for (unsigned long i = 0; (desc = desc_func(i)) != NULL; i++) { + string l = desc->Label; + if (l == label) { + + // If we had to load the library, unload it + unsigned long id = desc->UniqueID; + if (library_loaded) { + dlclose(m_Libraries[library_index].Handle); + m_Libraries[library_index].Handle = NULL; + } + return id; + } + } + + cerr << "Plugin " << label << " not found in library " << filename << endl; + return 0; } const vector -LADSPAInfo::GetPluginList(void) +LADSPAInfo::GetMenuList(void) { - return m_OrderedPluginList; + m_SSMMenuList.clear(); + + DescendGroup("", "LADSPA", 1); + + return m_SSMMenuList; } unsigned long LADSPAInfo::GetPluginListEntryByID(unsigned long unique_id) { - unsigned long j = 0; - for (vector::iterator i = m_OrderedPluginList.begin(); - i != m_OrderedPluginList.end(); i++, j++) { - if (i->UniqueID == unique_id) return j; - } - return m_OrderedPluginList.size(); + unsigned long j = 0; + for (vector::iterator i = m_SSMMenuList.begin(); + i != m_SSMMenuList.end(); i++, j++) { + if (i->UniqueID == unique_id) return j; + } + return m_SSMMenuList.size(); } // **************************************************************************** // ** Private Member Functions ** // **************************************************************************** +// Build a list of plugins by group, suitable for SSM LADSPA Plugin drop-down +// The top-level "LADSPA" group is not included + +void +LADSPAInfo::DescendGroup(string prefix, + const string group, + unsigned int depth) +{ + list groups = GetSubGroups(group); + + if (prefix.length() > 0) { + // Add an explicit '/' as we're creating sub-menus from groups + prefix += "/"; + } + + for (list::iterator g = groups.begin(); g != groups.end(); g++) { + string name; + + // Escape '/' and '|' characters + unsigned int x = g->find_first_of("/|"); + if (x == string::npos) { + name = *g; + } else { + unsigned int last_x = 0; + while (x < string::npos) { + name += g->substr(last_x, x - last_x) + '\\' + (*g)[x]; + last_x = x + 1; + x = g->find_first_of("/|", x + 1); + } + name += g->substr(last_x, x - last_x); + } + + DescendGroup(prefix + name, *g, depth + 1); + } + if (m_RDFLabelLookup.find(group) != m_RDFLabelLookup.end()) { + unsigned long uri_index = m_RDFLabelLookup[group]; + + // Create group for unclassified plugins + if (prefix.length() == 0) { + prefix = "Unclassified/"; + depth = depth + 1; + } + + // Temporary list (for sorting the plugins by name) + list plugins; + + for (vector::iterator p = m_RDFURIs[uri_index].Plugins.begin(); + p != m_RDFURIs[uri_index].Plugins.end(); p++) { + + PluginInfo *pi = &(m_Plugins[*p]); + string name; + + // Escape '/' and '|' characters + unsigned int x = pi->Name.find_first_of("/|"); + if (x == string::npos) { + name = pi->Name; + } else { + unsigned int last_x = 0; + while (x < string::npos) { + name += pi->Name.substr(last_x, x - last_x) + '\\' + pi->Name[x]; + last_x = x + 1; + x = pi->Name.find_first_of("/|", x + 1); + } + name += pi->Name.substr(last_x, x - last_x); + } + + PluginEntry pe; + + pe.Depth = depth; + pe.UniqueID = pi->UniqueID; + pe.Name = prefix + name; + + plugins.push_back(pe); + } + plugins.sort(); + + // Add all ordered entries to the Menu List + // This ensures that plugins appear after groups + for (list::iterator p = plugins.begin(); p != plugins.end(); p++) { + m_SSMMenuList.push_back(*p); + } + } +} + +// Get list of groups that are within given group. The root group is +// always "LADSPA" +list +LADSPAInfo::GetSubGroups(const string group) +{ + list groups; + unsigned long uri_index; + + if (m_RDFLabelLookup.find(group) == m_RDFLabelLookup.end()) { + return groups; + } else { + uri_index = m_RDFLabelLookup[group]; + } + + for (vector::iterator sg = m_RDFURIs[uri_index].Children.begin(); + sg != m_RDFURIs[uri_index].Children.end(); sg++) { + groups.push_back(m_RDFURIs[*sg].Label); + } + + groups.sort(); + + return groups; +} + // Unload any loaded DLLs and clear vectors etc void LADSPAInfo::CleanUp(void) { - m_IDLookup.clear(); - m_FilenameLookup.clear(); - m_Plugins.clear(); + m_MaxInputPortCount = 0; -// Unload loaded dlls - for (vector::iterator i = m_Libraries.begin(); - i != m_Libraries.end(); i++) { - if (i->Handle) dlclose(i->Handle); - } + m_IDLookup.clear(); + m_Plugins.clear(); - m_Libraries.clear(); - m_Paths.clear(); +// Unload loaded dlls + for (vector::iterator i = m_Libraries.begin(); + i != m_Libraries.end(); i++) { + if (i->Handle) dlclose(i->Handle); + } -#ifdef HAVE_LIBLRDF - lrdf_cleanup(); -#endif + m_Libraries.clear(); + m_Paths.clear(); - m_OrderedPluginList.clear(); - m_MaxInputPortCount = 0; + m_RDFURILookup.clear(); + m_RDFURIs.clear(); - if (m_ExtraPaths) { - free(m_ExtraPaths); - m_ExtraPaths = NULL; - } + if (m_ExtraPaths) { + free(m_ExtraPaths); + m_ExtraPaths = NULL; + } } // Given a colon-separated list of paths, examine the contents of each @@ -320,175 +448,170 @@ LADSPAInfo::ScanPathList(const char *path_list, void (LADSPAInfo::*ExamineFunc)(const string, const string)) { - const char *start; - const char *end; - int extra; - char *path; - string basename; - DIR *dp; - struct dirent *ep; - struct stat sb; + const char *start; + const char *end; + int extra; + char *path; + string basename; + DIR *dp; + struct dirent *ep; + struct stat sb; // This does the same kind of thing as strtok, but strtok won't // like the const - start = path_list; - while (*start != '\0') { - while (*start == ':') start++; - end = start; - while (*end != ':' && *end != '\0') end++; - - if (end - start > 0) { - extra = (*(end - 1) == '/') ? 0 : 1; - path = (char *)malloc(end - start + 1 + extra); - if (path) { - strncpy(path, start, end - start); - if (extra == 1) path[end - start] = '/'; - path[end - start + extra] = '\0'; - - dp = opendir(path); - if (!dp) { - cerr << "WARNING: Could not open path " << path << endl; - } else { - while ((ep = readdir(dp))) { - - // Stat file to get type - basename = ep->d_name; - if (!stat((path + basename).c_str(), &sb)) { - - // We only want regular files - if (S_ISREG(sb.st_mode)) (*this.*ExamineFunc)(path, basename); - } - } - closedir(dp); - } - free(path); - } - } - start = end; - } + start = path_list; + while (*start != '\0') { + while (*start == ':') start++; + end = start; + while (*end != ':' && *end != '\0') end++; + + if (end - start > 0) { + extra = (*(end - 1) == '/') ? 0 : 1; + path = (char *)malloc(end - start + 1 + extra); + if (path) { + strncpy(path, start, end - start); + if (extra == 1) path[end - start] = '/'; + path[end - start + extra] = '\0'; + + dp = opendir(path); + if (!dp) { + cerr << "WARNING: Could not open path " << path << endl; + } else { + while ((ep = readdir(dp))) { + + // Stat file to get type + basename = ep->d_name; + if (!stat((path + basename).c_str(), &sb)) { + + // We only want regular files + if (S_ISREG(sb.st_mode)) (*this.*ExamineFunc)(path, basename); + } + } + closedir(dp); + } + free(path); + } + } + start = end; + } } // Check given file is a valid LADSPA Plugin library // // If so, add path, library and plugin info // to the m_Paths, m_Libraries and m_Plugins vectors. +// void LADSPAInfo::ExaminePluginLibrary(const string path, const string basename) { - void *handle; - LADSPA_Descriptor_Function desc_func; - const LADSPA_Descriptor *desc; - string fullpath = path + basename; - -// We're not fussed about resolving symbols yet, since we are just -// checking libraries. - handle = dlopen(fullpath.c_str(), RTLD_LAZY); - - if (!handle) { - cerr << "WARNING: File " << fullpath - << " could not be examined" << endl; - cerr << "dlerror() output:" << endl; - cerr << dlerror() << endl; - } else { - - // It's a DLL, so now see if it's a LADSPA plugin library - desc_func = (LADSPA_Descriptor_Function)dlsym(handle, - "ladspa_descriptor"); - if (!desc_func) { - - // Is DLL, but not a LADSPA one - cerr << "WARNING: DLL " << fullpath - << " has no ladspa_descriptor function" << endl; - cerr << "dlerror() output:" << endl; - cerr << dlerror() << endl; - } else { - - // Got ladspa_descriptor, so we can now get plugin info - bool library_added = false; - unsigned long i = 0; - desc = desc_func(i); - while (desc) { - - // First, check that it's not a dupe - if (m_IDLookup.find(desc->UniqueID) != m_IDLookup.end()) { - unsigned long plugin_index = m_IDLookup[desc->UniqueID]; - unsigned long library_index = m_Plugins[plugin_index].LibraryIndex; - unsigned long path_index = m_Libraries[library_index].PathIndex; - - cerr << "WARNING: Duplicated Plugin ID (" - << desc->UniqueID << ") found:" << endl; - - cerr << " Plugin " << m_Plugins[plugin_index].Index - << " in library: " << m_Paths[path_index] - << m_Libraries[library_index].Basename - << " [First instance found]" << endl; - cerr << " Plugin " << i << " in library: " << fullpath - << " [Duplicate not added]" << endl; - } else { - if (CheckPlugin(desc)) { - - // Add path if not already added - unsigned long path_index; - vector::iterator p = find(m_Paths.begin(), m_Paths.end(), path); - if (p == m_Paths.end()) { - path_index = m_Paths.size(); - m_Paths.push_back(path); - } else { - path_index = p - m_Paths.begin(); - } - - // Add library info if not already added - if (!library_added) { - LibraryInfo li; - li.PathIndex = path_index; - li.Basename = basename; - li.RefCount = 0; - li.Handle = NULL; - m_Libraries.push_back(li); - - library_added = true; - } - - // Add filename to lookup - m_FilenameLookup[fullpath] = m_Libraries.size() - 1; - - // Add plugin info - PluginInfo pi; - pi.LibraryIndex = m_Libraries.size() - 1; - pi.Index = i; - pi.Descriptor = NULL; - m_Plugins.push_back(pi); - - // Add to index - m_IDLookup[desc->UniqueID] = m_Plugins.size() - 1; - - // Add to ordered list - PluginEntry pe; - pe.UniqueID = desc->UniqueID; - pe.Name = desc->Name; - m_OrderedPluginList.push_back(pe); - - // Find number of input ports - unsigned long in_port_count = 0; - for (unsigned long p = 0; p < desc->PortCount; p++) { - if (LADSPA_IS_PORT_INPUT(desc->PortDescriptors[p])) { - in_port_count++; - } - } - if (in_port_count > m_MaxInputPortCount) { - m_MaxInputPortCount = in_port_count; - } - } else { - cerr << "WARNING: Plugin " << desc->UniqueID << " not added" << endl; - } - } - - desc = desc_func(++i); - } - } - dlclose(handle); - } + void *handle; + LADSPA_Descriptor_Function desc_func; + const LADSPA_Descriptor *desc; + string fullpath = path + basename; + +// We're not executing any code, so be lazy about resolving symbols + handle = dlopen(fullpath.c_str(), RTLD_LAZY); + + if (!handle) { + cerr << "WARNING: File " << fullpath + << " could not be examined" << endl; + cerr << "dlerror() output:" << endl; + cerr << dlerror() << endl; + } else { + + // It's a DLL, so now see if it's a LADSPA plugin library + desc_func = (LADSPA_Descriptor_Function)dlsym(handle, + "ladspa_descriptor"); + if (!desc_func) { + + // Is DLL, but not a LADSPA one + cerr << "WARNING: DLL " << fullpath + << " has no ladspa_descriptor function" << endl; + cerr << "dlerror() output:" << endl; + cerr << dlerror() << endl; + } else { + + // Got ladspa_descriptor, so we can now get plugin info + bool library_added = false; + unsigned long i = 0; + desc = desc_func(i); + while (desc) { + + // First, check that it's not a dupe + if (m_IDLookup.find(desc->UniqueID) != m_IDLookup.end()) { + unsigned long plugin_index = m_IDLookup[desc->UniqueID]; + unsigned long library_index = m_Plugins[plugin_index].LibraryIndex; + unsigned long path_index = m_Libraries[library_index].PathIndex; + + cerr << "WARNING: Duplicated Plugin ID (" + << desc->UniqueID << ") found:" << endl; + + cerr << " Plugin " << m_Plugins[plugin_index].Index + << " in library: " << m_Paths[path_index] + << m_Libraries[library_index].Basename + << " [First instance found]" << endl; + cerr << " Plugin " << i << " in library: " << fullpath + << " [Duplicate not added]" << endl; + } else { + if (CheckPlugin(desc)) { + + // Add path if not already added + unsigned long path_index; + vector::iterator p = find(m_Paths.begin(), m_Paths.end(), path); + if (p == m_Paths.end()) { + path_index = m_Paths.size(); + m_Paths.push_back(path); + } else { + path_index = p - m_Paths.begin(); + } + + // Add library info if not already added + if (!library_added) { + LibraryInfo li; + li.PathIndex = path_index; + li.Basename = basename; + li.RefCount = 0; + li.Handle = NULL; + m_Libraries.push_back(li); + + library_added = true; + } + + // Add plugin info + PluginInfo pi; + pi.LibraryIndex = m_Libraries.size() - 1; + pi.Index = i; + pi.UniqueID = desc->UniqueID; + pi.Label = desc->Label; + pi.Name = desc->Name; + pi.Descriptor = NULL; + m_Plugins.push_back(pi); + + // Find number of input ports + unsigned long in_port_count = 0; + for (unsigned long p = 0; p < desc->PortCount; p++) { + if (LADSPA_IS_PORT_INPUT(desc->PortDescriptors[p])) { + in_port_count++; + } + } + if (in_port_count > m_MaxInputPortCount) { + m_MaxInputPortCount = in_port_count; + } + + // Add to index + m_IDLookup[desc->UniqueID] = m_Plugins.size() - 1; + + } else { + cerr << "WARNING: Plugin " << desc->UniqueID << " not added" << endl; + } + } + + desc = desc_func(++i); + } + } + dlclose(handle); + } } #ifdef HAVE_LIBLRDF @@ -497,11 +620,84 @@ void LADSPAInfo::ExamineRDFFile(const std::string path, const std::string basename) { - string fileuri = "file://" + path + basename; + string fileuri = "file://" + path + basename; + + if (lrdf_read_file(fileuri.c_str())) { + cerr << "WARNING: File " << path + basename << " could not be parsed [Ignored]" << endl; + } +} - if (lrdf_read_file(fileuri.c_str())) { - cerr << "WARNING: File " << path + basename << " could not be parsed [Ignored]" << endl; - } +// Recursively add rdf information for plugins that have been +// found from scanning LADSPA_PATH +void +LADSPAInfo::MetadataRDFDescend(const char * uri, + unsigned long parent) +{ + unsigned long this_uri_index; + +// Check URI not already added + if (m_RDFURILookup.find(uri) == m_RDFURILookup.end()) { + + // Not found + RDFURIInfo ri; + + ri.URI = uri; + + if (ri.URI == LADSPA_BASE "Plugin") { + + // Add top level group as "LADSPA" + // This will always happen, even if there are no .rdf files read by liblrdf + // or if there is no liblrdf support + ri.Label = "LADSPA"; + } else { + char * label = lrdf_get_label(uri); + if (label) { + ri.Label = label; + } else { + ri.Label = "(No label)"; + } + } + + // Add any instances found + lrdf_uris * instances = lrdf_get_instances(uri); + if (instances) { + for (long j = 0; j < instances->count; j++) { + unsigned long uid = lrdf_get_uid(instances->items[j]); + if (m_IDLookup.find(uid) != m_IDLookup.end()) { + ri.Plugins.push_back(m_IDLookup[uid]); + } + } + } + + lrdf_free_uris(instances); + + m_RDFURIs.push_back(ri); + this_uri_index = m_RDFURIs.size() - 1; + + m_RDFURILookup[ri.URI] = this_uri_index; + m_RDFLabelLookup[ri.Label] = this_uri_index; + + } else { + + // Already added + this_uri_index = m_RDFURILookup[uri]; + } + +// Only add parent - child info if this uri is NOT the first (root) uri + if (this_uri_index > 0) { + m_RDFURIs[this_uri_index].Parents.push_back(parent); + m_RDFURIs[parent].Children.push_back(this_uri_index); + } + + lrdf_uris * uris = lrdf_get_subclasses(uri); + + if (uris) { + for (long i = 0; i < uris->count; i++) { + MetadataRDFDescend(uris->items[i], this_uri_index); + } + } + + lrdf_free_uris(uris); } #endif @@ -509,65 +705,66 @@ bool LADSPAInfo::CheckPlugin(const LADSPA_Descriptor *desc) { #define test(t, m) { \ - if (!(t)) { \ - cerr << m << endl; \ - return false; \ - } \ + if (!(t)) { \ + cerr << m << endl; \ + return false; \ + } \ } - test(!LADSPA_IS_REALTIME(desc->Properties), "WARNING: Plugin must run real time"); - test(desc->instantiate, "WARNING: Plugin has no instatiate function"); - test(desc->connect_port, "WARNING: Warning: Plugin has no connect_port funciton"); - test(desc->run, "WARNING: Plugin has no run function"); - test(!(desc->run_adding != 0 && desc->set_run_adding_gain == 0), - "WARNING: Plugin has run_adding but no set_run_adding_gain"); - test(!(desc->run_adding == 0 && desc->set_run_adding_gain != 0), - "WARNING: Plugin has set_run_adding_gain but no run_adding"); - test(desc->cleanup, "WARNING: Plugin has no cleanup function"); - test(!LADSPA_IS_INPLACE_BROKEN(desc->Properties), - "WARNING: Plugin cannot use in place processing"); - test(desc->PortCount, "WARNING: Plugin has no ports"); - - return true; + test(desc->instantiate, "WARNING: Plugin has no instatiate function"); + test(desc->connect_port, "WARNING: Warning: Plugin has no connect_port funciton"); + test(desc->run, "WARNING: Plugin has no run function"); + test(!(desc->run_adding != 0 && desc->set_run_adding_gain == 0), + "WARNING: Plugin has run_adding but no set_run_adding_gain"); + test(!(desc->run_adding == 0 && desc->set_run_adding_gain != 0), + "WARNING: Plugin has set_run_adding_gain but no run_adding"); + test(desc->cleanup, "WARNING: Plugin has no cleanup function"); + test(!LADSPA_IS_INPLACE_BROKEN(desc->Properties), + "WARNING: Plugin cannot use in place processing"); + test(desc->PortCount, "WARNING: Plugin has no ports"); + + return true; } LADSPA_Descriptor_Function LADSPAInfo::GetDescriptorFunctionForLibrary(unsigned long library_index) { - LibraryInfo *li = &(m_Libraries[library_index]); - if (!(li->Handle)) { + LibraryInfo *li = &(m_Libraries[library_index]); + + if (!(li->Handle)) { - // Need full path - string fullpath = m_Paths[li->PathIndex]; - fullpath.append(li->Basename); + // Need full path + string fullpath = m_Paths[li->PathIndex]; + fullpath.append(li->Basename); - li->Handle = dlopen(fullpath.c_str(), RTLD_NOW); - if (!(li->Handle)) { + // Immediate symbol resolution, as plugin code is likely to be executed + li->Handle = dlopen(fullpath.c_str(), RTLD_NOW); + if (!(li->Handle)) { - // Plugin library changed since last path scan - cerr << "WARNING: Plugin library " << fullpath << " cannot be loaded" << endl; - cerr << "Rescan of plugins recommended" << endl; - cerr << "dlerror() output:" << endl; - cerr << dlerror() << endl; - return NULL; - } - } + // Plugin library changed since last path scan + cerr << "WARNING: Plugin library " << fullpath << " cannot be loaded" << endl; + cerr << "Rescan of plugins recommended" << endl; + cerr << "dlerror() output:" << endl; + cerr << dlerror() << endl; + return NULL; + } + } // Got handle so now verify that it's a LADSPA plugin library - const LADSPA_Descriptor_Function desc_func = (LADSPA_Descriptor_Function)dlsym(li->Handle, - "ladspa_descriptor"); - if (!desc_func) { - - // Is DLL, but not a LADSPA one (changed since last path scan?) - cerr << "WARNING: DLL " << m_Paths[li->PathIndex] << li->Basename - << " has no ladspa_descriptor function" << endl; - cerr << "Rescan of plugins recommended" << endl; - cerr << "dlerror() output:" << endl; - cerr << dlerror() << endl; - - // Unload library - dlclose(li->Handle); - return NULL; - } - - return desc_func; + const LADSPA_Descriptor_Function desc_func = (LADSPA_Descriptor_Function)dlsym(li->Handle, + "ladspa_descriptor"); + if (!desc_func) { + + // Is DLL, but not a LADSPA one (changed since last path scan?) + cerr << "WARNING: DLL " << m_Paths[li->PathIndex] << li->Basename + << " has no ladspa_descriptor function" << endl; + cerr << "Rescan of plugins recommended" << endl; + cerr << "dlerror() output:" << endl; + cerr << dlerror() << endl; + + // Unload library + dlclose(li->Handle); + return NULL; + } + + return desc_func; } diff --git a/SpiralSound/Plugins/LADSPAPlugin/LADSPAInfo.h b/SpiralSound/Plugins/LADSPAPlugin/LADSPAInfo.h index fd36327..f2a75df 100644 --- a/SpiralSound/Plugins/LADSPAPlugin/LADSPAInfo.h +++ b/SpiralSound/Plugins/LADSPAPlugin/LADSPAInfo.h @@ -1,28 +1,31 @@ -/* - LADSPAInfo.h - Header file for LADSPA Plugin info class - - Copyright (C) 2002 Mike Rawes - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +// +// LADSPAInfo.h - Header file for LADSPA Plugin info class +// +// Copyleft (C) 2002 Mike Rawes +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// #ifndef __ladspa_info_h__ #define __ladspa_info_h__ +#include + #include #include +#include #include #include @@ -33,124 +36,164 @@ public: // Also examine supplied path list // For all paths, add basic plugin information for later lookup, // instantiation and so on. - LADSPAInfo(bool override, const char *path_list); + LADSPAInfo(bool override = false, const char *path_list = ""); // Unload all loaded plugins and clean up - ~LADSPAInfo(); + ~LADSPAInfo(); // ************************************************************************ // Loading/Unloading plugin libraries // // At first, no library dlls are loaded. // -// Each library has an associated reference count, which is initially 0. -// As descriptors are requested, using GetDescriptorByID, this count -// is incremented. The library dll is loaded on the first request. -// At descriptors are discarded, the count is decremented, and when this -// reaches 0, the library is unloaded. +// A plugin library may have more than one plugin descriptor. The +// descriptor is used to instantiate, activate, execute plugin instances. +// Administration of plugin instances are outwith the scope of this class, +// instead, descriptors are requested using GetDecriptorByID, and disposed +// of using DiscardDescriptorByID. +// +// Each library keeps a reference count of descriptors requested. A library +// is loaded when a descriptor is requested for the first time, and remains +// loaded until the number of discards matches the number of requests. // Rescan all paths in $LADSPA_PATH, as per constructor. // This will also unload all libraries, and make any descriptors that // have not been discarded with DiscardDescriptorByID invalid. - void RescanPlugins(void); + void RescanPlugins(void); // Unload all dlopened libraries. This will make any descriptors that // have not been discarded with DiscardDescriptorByID invalid. - void UnloadAllLibraries(void); + void UnloadAllLibraries(void); // Get descriptor of plugin with given ID. This increments the descriptor // count for the corresponding library. - const LADSPA_Descriptor *GetDescriptorByID(unsigned long unique_id); + const LADSPA_Descriptor *GetDescriptorByID(unsigned long unique_id); // Notify that a descriptor corresponding to the given ID has been // discarded. This decrements the descriptor count for the corresponding // library. - void DiscardDescriptorByID(unsigned long unique_id); - -// Get unique ID of plugin identified by given library filename and label. - unsigned long GetIDFromFilenameAndLabel(std::string filename, - std::string label); + void DiscardDescriptorByID(unsigned long unique_id); - struct PluginEntry - { - unsigned long UniqueID; - std::string Name; - }; +// ************************************************************************ +// SSM Specific options -// Get a list of plugins ordered by name (duplicate names are -// appended with a (number) - const std::vector GetPluginList(void); +// Get unique ID of plugin identified by given library filename and label. +// This is for backwards compatibility with older versions of SSM where the +// path and label of the plugin was stored in the configuration - current +// versions store the Unique ID + unsigned long GetIDFromFilenameAndLabel(std::string filename, + std::string label); + +// Struct for plugin information returned by queries + struct PluginEntry + { + unsigned int Depth; + unsigned long UniqueID; + std::string Name; + + bool operator<(const PluginEntry& pe) + { + return (Name GetMenuList(void); // Get the index in the above list for given Unique ID // If not found, this returns the size of the above list - unsigned long GetPluginListEntryByID(unsigned long unique_id); + unsigned long GetPluginListEntryByID(unsigned long unique_id); // Get the number of input ports for the plugin with the most // input ports - unsigned long GetMaxInputPortCount(void) { return m_MaxInputPortCount; } - - void PrintInfo(void); + unsigned long GetMaxInputPortCount(void) { return m_MaxInputPortCount; } private: - void CleanUp(void); - void ScanPathList(const char *path_list, - void (LADSPAInfo::*ExamineFunc)(const std::string, - const std::string)); - void ExaminePluginLibrary(const std::string path, - const std::string basename); +// See LADSPAInfo.C for comments on these functions + void DescendGroup(std::string prefix, + const std::string group, + unsigned int depth); + std::list GetSubGroups(const std::string group); + + void CleanUp(void); + void ScanPathList(const char *path_list, + void (LADSPAInfo::*ExamineFunc)(const std::string, + const std::string)); + void ExaminePluginLibrary(const std::string path, + const std::string basename); + + bool CheckPlugin(const LADSPA_Descriptor *desc); + LADSPA_Descriptor_Function GetDescriptorFunctionForLibrary(unsigned long library_index); #ifdef HAVE_LIBLRDF - void ExamineRDFFile(const std::string path, - const std::string basename); + void ExamineRDFFile(const std::string path, + const std::string basename); + void MetadataRDFDescend(const char *uri, + unsigned long parent); #endif - bool CheckPlugin(const LADSPA_Descriptor *desc); - LADSPA_Descriptor_Function GetDescriptorFunctionForLibrary(unsigned long library_index); - - struct LibraryInfo - { - unsigned long PathIndex; // Index of path in m_Paths - std::string Basename; // Filename - unsigned long RefCount; // Count of descriptors requested from library - void *Handle; // DLL Handle, NULL - }; - - struct PluginInfo - { - unsigned long LibraryIndex; // Index of library in m_Libraries - unsigned long Index; // Plugin index in library - const LADSPA_Descriptor *Descriptor; // Descriptor, NULL - }; - - typedef std::map > IDMap; - - typedef std::map > StringMap; - - // For sorting vectors of PluginEntries - struct PluginEntrySortAsc - { - bool operator()(const PluginEntry &begin, const PluginEntry &end) - { - return begin.Name < end.Name; - } - }; - - bool m_LADSPAPathOverride; - char *m_ExtraPaths; - - std::vector m_Paths; - std::vector m_Libraries; - std::vector m_Plugins; - - IDMap m_IDLookup; - StringMap m_FilenameLookup; - - std::vector m_OrderedPluginList; - - unsigned long m_MaxInputPortCount; +// For cached library information + struct LibraryInfo + { + unsigned long PathIndex; // Index of path in m_Paths + std::string Basename; // Filename + unsigned long RefCount; // Count of descriptors requested + void *Handle; // DLL Handle, NULL + }; + +// For cached plugin information + struct PluginInfo + { + unsigned long LibraryIndex; // Index of library in m_Libraries + unsigned long Index; // Plugin index in library + unsigned long UniqueID; // Unique ID + std::string Label; // Plugin label + std::string Name; // Plugin Name + const LADSPA_Descriptor *Descriptor; // Descriptor, NULL + }; + +// For cached RDF uri information + struct RDFURIInfo + { + std::string URI; // Full URI for use with lrdf + std::string Label; // Label + std::vector Parents; // Index of parents in m_RDFURIs + std::vector Children; // Indices of children in m_RDFURIs + std::vector Plugins; // Indices of plugins in m_Plugins + }; + +// Lookup maps + typedef std::map > IDMap; + + typedef std::map > StringMap; + + bool m_LADSPAPathOverride; + char *m_ExtraPaths; + +// LADSPA Plugin information database + std::vector m_Paths; + std::vector m_Libraries; + std::vector m_Plugins; + +// Plugin lookup maps + IDMap m_IDLookup; + +// RDF URI database + std::vector m_RDFURIs; + +// RDF URI lookup map + StringMap m_RDFURILookup; + +// RDF Label lookup map + StringMap m_RDFLabelLookup; + +// SSM specific data + std::vector m_SSMMenuList; + StringMap m_FilenameLookup; + unsigned long m_MaxInputPortCount; }; #endif // __ladspa_info_h__ diff --git a/SpiralSound/Plugins/LADSPAPlugin/LADSPAPlugin.C b/SpiralSound/Plugins/LADSPAPlugin/LADSPAPlugin.C index c2218f8..d6a45bf 100644 --- a/SpiralSound/Plugins/LADSPAPlugin/LADSPAPlugin.C +++ b/SpiralSound/Plugins/LADSPAPlugin/LADSPAPlugin.C @@ -1,5 +1,7 @@ -/* SpiralSound +/* LADSPAPlugin.C * Copyleft (C) 2001 David Griffiths + * LADSPA Plugin by Nicolas Noble + * Modified by Mike Rawes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +22,14 @@ #include #include +#ifdef HAVE_POSIX_SHM +// All this, just for SHM +#include // For ftruncate +#include // For O_CREAT, O_RDONLY etc +#include // shm_* +#include // shm_* +#endif + #include "SpiralIcon.xpm" #include "LADSPAPlugin.h" #include "LADSPAPluginGUI.h" @@ -53,7 +63,65 @@ string SpiralPlugin_GetGroupName() LADSPAPlugin::LADSPAPlugin() { +#ifdef HAVE_POSIX_SHM +// Share the LADSPA Database via SHM +// We keep two things: A reference counter, and a pointer to the +// database. We can get away with just a pointer as all instances +// are in the same address space (process + thread) + + int shm_rc_fd; + int shm_db_fd; + + shm_rc_fd = shm_open(m_SHMRefCountPath, O_RDWR, 0644); + if (shm_rc_fd > 0) { + // Got an existing refcount + m_SHMRefCount = (unsigned long *)mmap(0, sizeof(unsigned long), PROT_READ | PROT_WRITE, MAP_SHARED, + shm_rc_fd, 0); + + (*m_SHMRefCount)++; + + shm_db_fd = shm_open(m_SHMLDBPath, O_RDONLY, 0644); + if (shm_db_fd > 0) { + // Got LADSPA Database + m_SHMLDB = (LADSPAInfo **)mmap(0, sizeof(LADSPAInfo *), PROT_READ, MAP_SHARED, + shm_db_fd, 0); + + m_LADSPAInfo = *m_SHMLDB; + } else { + std::cerr << "LADSPAPlugin: ERROR: Could not open SHM file '" << m_SHMLDBPath << std::cerr; + } + } else { + // Need to create a new SHM file for ref counter + shm_rc_fd = shm_open(m_SHMRefCountPath, O_CREAT | O_RDWR, 0644); + if (shm_rc_fd > 0) { + ftruncate(shm_rc_fd, sizeof(unsigned long)); + m_SHMRefCount = (unsigned long *)mmap(0, sizeof(unsigned long), PROT_READ | PROT_WRITE, MAP_SHARED, + shm_rc_fd, 0); + + // Initilise to 1 (this instance) + *m_SHMRefCount = 1; + + shm_db_fd = shm_open(m_SHMLDBPath, O_CREAT | O_RDWR, 0644); + if (shm_db_fd > 0) { + // Create LADSPA Plugin Database + m_LADSPAInfo = new LADSPAInfo(false, ""); + + ftruncate(shm_db_fd, sizeof(LADSPAInfo *)); + m_SHMLDB = (LADSPAInfo **)mmap(0, sizeof(LADSPAInfo *), PROT_READ | PROT_WRITE, MAP_SHARED, + shm_db_fd, 0); + + *m_SHMLDB = m_LADSPAInfo; + } else { + std::cerr << "LADSPAPlugin: ERROR: Could not create SHM file '" << m_SHMLDBPath << "'" << std::endl; + } + } else { + std::cerr << "LADSPAPlugin: ERROR: Could not create SHM file '" << m_SHMRefCountPath << "'" << std::endl; + } + } +#else +// No POSIX SHM, just create a new database m_LADSPAInfo = new LADSPAInfo(false, ""); +#endif m_PlugDesc = NULL; @@ -71,7 +139,7 @@ LADSPAPlugin::LADSPAPlugin() m_MaxInputPortCount = m_LADSPAInfo->GetMaxInputPortCount(); // For receiving from GUI - m_AudioCH->RegisterData("SetPluginIndex", ChannelHandler::INPUT,&(m_InData.PluginIndex), sizeof(m_InData.PluginIndex)); + m_AudioCH->RegisterData("SetUniqueID", ChannelHandler::INPUT,&(m_InData.UniqueID), sizeof(m_InData.UniqueID)); m_AudioCH->RegisterData("SetTabIndex", ChannelHandler::INPUT,&(m_InData.TabIndex), sizeof(m_InData.TabIndex)); m_AudioCH->RegisterData("SetUpdateInputs", ChannelHandler::INPUT,&(m_InData.UpdateInputs),sizeof(m_InData.UpdateInputs)); m_AudioCH->RegisterData("SetInputPortIndex", ChannelHandler::INPUT, &(m_InData.InputPortIndex), sizeof(m_InData.InputPortIndex)); @@ -93,13 +161,14 @@ LADSPAPlugin::LADSPAPlugin() if (m_OutData.InputPortNames && m_OutData.InputPortDefaults && - m_OutData.InputPortSettings) { + m_OutData.InputPortSettings && + m_OutData.InputPortValues) { m_AudioCH->RegisterData("GetInputPortNames", ChannelHandler::OUTPUT, m_OutData.InputPortNames, 256 * m_MaxInputPortCount); m_AudioCH->RegisterData("GetInputPortSettings", ChannelHandler::OUTPUT, m_OutData.InputPortSettings, sizeof(PortSettings) * m_MaxInputPortCount); m_AudioCH->RegisterData("GetInputPortValues", ChannelHandler::OUTPUT, m_OutData.InputPortValues, sizeof(PortValues) * m_MaxInputPortCount); m_AudioCH->RegisterData("GetInputPortDefaults", ChannelHandler::OUTPUT, m_OutData.InputPortDefaults, sizeof(float) * m_MaxInputPortCount); } else { - cerr<<"Memory allocation error"<GetPluginList()); + this, m_AudioCH, m_HostInfo, m_LADSPAInfo->GetMenuList()); } void LADSPAPlugin::Execute() @@ -205,8 +292,7 @@ void LADSPAPlugin::ExecuteCommands() break; case (SELECTPLUGIN): { - vector pe = m_LADSPAInfo->GetPluginList(); - UpdatePlugin(pe[m_InData.PluginIndex - 1].UniqueID); + UpdatePlugin(m_InData.UniqueID); } break; case (CLEARPLUGIN): @@ -857,7 +943,6 @@ bool LADSPAPlugin::SelectPlugin(unsigned long UniqueID) UpdatePluginInfoWithHost(); m_UniqueID = m_PlugDesc->UniqueID; - m_PluginIndex = m_LADSPAInfo->GetPluginListEntryByID(m_UniqueID) + 1; m_InputPortCount = m_PluginInfo.NumInputs; int lbl_length; @@ -891,7 +976,6 @@ void LADSPAPlugin::ClearPlugin(void) m_TabIndex = 1; m_UpdateInputs = true; m_UniqueID = 0; - m_PluginIndex = 0; m_InputPortCount = 0; strncpy(m_Name, "None\0", 5); strncpy(m_Maker, "None\0", 5); diff --git a/SpiralSound/Plugins/LADSPAPlugin/LADSPAPlugin.h b/SpiralSound/Plugins/LADSPAPlugin/LADSPAPlugin.h index 952fd28..d5e3f5f 100644 --- a/SpiralSound/Plugins/LADSPAPlugin/LADSPAPlugin.h +++ b/SpiralSound/Plugins/LADSPAPlugin/LADSPAPlugin.h @@ -1,5 +1,7 @@ -/* SpiralSound +/* LADSPAPlugin.h * Copyleft (C) 2001 David Griffiths + * LADSPA Plugin by Nicolas Noble + * Modified by Mike Rawes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +42,7 @@ struct PortValues class LADSPAPlugin : public SpiralPlugin { public: - LADSPAPlugin(); + LADSPAPlugin(); virtual ~LADSPAPlugin(); virtual PluginInfo &Initialise(const HostInfo *Host); @@ -50,7 +52,7 @@ public: virtual void StreamOut(ostream &s); virtual void StreamIn(istream &s); - unsigned long GetPluginIndex() { return m_PluginIndex; } + unsigned long GetUniqueID() { return m_UniqueID; } const char *GetName() { return (const char *)m_Name; } const char *GetMaker() { return (const char *)m_Maker; } int GetTabIndex() { return m_TabIndex; } @@ -130,7 +132,7 @@ private: // Data received from GUI struct InputChannelData { - unsigned long PluginIndex; + unsigned long UniqueID; int TabIndex; bool UpdateInputs; unsigned long InputPortIndex; @@ -142,6 +144,13 @@ private: OutputChannelData m_OutData; InputChannelData m_InData; + +// SHM stuff - for sharing the LADSPA Plugin database + static const char * const m_SHMRefCountPath = "/SpiralSynthModular-LADSPAPlugin-RefCount"; + static const char * const m_SHMLDBPath = "/SpiralSynthModular-LADSPAPlugin-Database"; + + unsigned long *m_SHMRefCount; + LADSPAInfo **m_SHMLDB; }; #endif // __ladspa_plugin_h__ diff --git a/SpiralSound/Plugins/LADSPAPlugin/LADSPAPluginGUI.C b/SpiralSound/Plugins/LADSPAPlugin/LADSPAPluginGUI.C index e2bb1b3..9f02ea9 100644 --- a/SpiralSound/Plugins/LADSPAPlugin/LADSPAPluginGUI.C +++ b/SpiralSound/Plugins/LADSPAPlugin/LADSPAPluginGUI.C @@ -1,6 +1,7 @@ -/* SpiralPlugin +/* LADSPAPluginGUI.C * Copyleft (C) 2000 David Griffiths * LADSPA Plugin by Nicolas Noble + * Modified by Mike Rawes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,8 +38,8 @@ LADSPAPluginGUI::LADSPAPluginGUI(int w, int h, const vector &PVec) : SpiralPluginGUI(w,h,o,ch) { - m_GUIColour = (Fl_Color)Info->GUI_COLOUR; - m_PluginList = PVec; + m_GUIColour = (Fl_Color)Info->GUI_COLOUR; + m_PluginList = PVec; int Width=20; int Height=100; @@ -54,7 +55,7 @@ SpiralPluginGUI(w,h,o,ch) if (!(m_InputPortNames && m_InputPortSettings && m_InputPortValues && m_InputPortDefaults)) { - cerr<<"Memory allocation error\n"<box (FL_PLASTIC_UP_BOX); + m_ControlGroup->box (FL_PLASTIC_UP_BOX); m_ControlGroup->labelsize(12); m_ControlScroll = new Fl_Scroll (10, 85, 480, 220, ""); @@ -88,7 +89,7 @@ SpiralPluginGUI(w,h,o,ch) m_ControlScroll->add(m_ControlPack); m_SetupGroup = new Fl_Group (5, 80, 490, 230, "Setup"); - m_SetupGroup->box (FL_PLASTIC_UP_BOX); + m_SetupGroup->box (FL_PLASTIC_UP_BOX); m_SetupGroup->labelsize(12); m_Browser = new Fl_Choice(50,85,440,22,"Plugin:"); @@ -97,37 +98,32 @@ SpiralPluginGUI(w,h,o,ch) m_Browser->callback((Fl_Callback *)cb_Select); m_Browser->add("(None)"); + m_PluginIDLookup.push_back(0); - for (vector::iterator i=m_PluginList.begin(); +// The plugin list is already formatted for addition to our drop-down, +// so just add all items as they are + unsigned long size = m_Browser->size(); + int depth = 1; + + for (vector::iterator i=m_PluginList.begin(); i!=m_PluginList.end(); i++) { - unsigned long len = i->Name.length(); - unsigned long esc_count = 0; - const char *tmp = i->Name.c_str(); - char *dest; + m_Browser->add(i->Name.c_str()); - for (unsigned long c = 0; c < len; c++) { - if (tmp[c] == '/') esc_count++; - } + unsigned int dsize = m_Browser->size() - size; + int ddepth = i->Depth - depth; - dest = (char *)malloc(len + 1 + esc_count); - - if (dest) { - unsigned long d = 0; - for (unsigned long c = 0; c < len; c++, d++) { - if (tmp[c] == '/' || tmp[c] == '|') { - dest[d] = '\\'; - d++; - dest[d] = tmp[c]; - } else { - dest[d] = tmp[c]; - } - } - dest[len + esc_count] = '\0'; - m_Browser->add(dest); - free(dest); + size = m_Browser->size(); + depth = i->Depth; + + // Add blanks to ID Lookup vector to account for sub-menus + for (unsigned long j = 1; j < (dsize - ddepth); j++) { + m_PluginIDLookup.push_back(0); } - } + // Add to ID Lookup vector (this maps Menu Items to Unique IDs) + m_PluginIDLookup.push_back(i->UniqueID); + } + m_Browser->value(0); m_SetupGroup->add(m_Browser); @@ -143,29 +139,29 @@ SpiralPluginGUI(w,h,o,ch) m_SetupGroup->add(m_InputScroll); - m_ValueLabel = new Fl_Box(15,115,60,15,"Value"); + m_ValueLabel = new Fl_Box(15,115,60,15,"Value"); m_ValueLabel->labelsize(12); - m_SetupGroup->add(m_ValueLabel); + m_SetupGroup->add(m_ValueLabel); - m_DefaultLabel = new Fl_Box(77,115,60,15,"Default"); + m_DefaultLabel = new Fl_Box(77,115,60,15,"Default"); m_DefaultLabel->labelsize(12); - m_SetupGroup->add(m_DefaultLabel); + m_SetupGroup->add(m_DefaultLabel); - m_MinLabel = new Fl_Box(139,115,60,15,"Min"); + m_MinLabel = new Fl_Box(139,115,60,15,"Min"); m_MinLabel->labelsize(12); - m_SetupGroup->add(m_MinLabel); + m_SetupGroup->add(m_MinLabel); - m_MaxLabel = new Fl_Box(201,115,60,15,"Max"); + m_MaxLabel = new Fl_Box(201,115,60,15,"Max"); m_MaxLabel->labelsize(12); - m_SetupGroup->add(m_MaxLabel); + m_SetupGroup->add(m_MaxLabel); - m_ClampLabel = new Fl_Box(280,115,10,15,"Clamp?"); + m_ClampLabel = new Fl_Box(280,115,10,15,"Clamp?"); m_ClampLabel->labelsize(12); - m_SetupGroup->add(m_ClampLabel); + m_SetupGroup->add(m_ClampLabel); - m_PortLabel = new Fl_Box(325,115,60,15,"Port Name"); + m_PortLabel = new Fl_Box(325,115,60,15,"Port Name"); m_PortLabel->labelsize(12); - m_SetupGroup->add(m_PortLabel); + m_SetupGroup->add(m_PortLabel); m_UpdateInputs = new Fl_LED_Button (10, 282, 25, 25, "Update input values?"); m_UpdateInputs->labelsize(12); @@ -190,6 +186,9 @@ LADSPAPluginGUI::~LADSPAPluginGUI(void) if (m_InputPortSettings) free(m_InputPortSettings); if (m_InputPortValues) free(m_InputPortValues); if (m_InputPortDefaults) free(m_InputPortDefaults); + + m_PluginIDLookup.clear(); + Fl::check(); } @@ -243,7 +242,7 @@ void LADSPAPluginGUI::UpdateDefaultAdjustControls(void) void LADSPAPluginGUI::UpdateValues(SpiralPlugin *o) { LADSPAPlugin* Plugin = (LADSPAPlugin*)o; - SetPluginIndex(Plugin->GetPluginIndex()); + SetUniqueID(Plugin->GetUniqueID()); SetName(Plugin->GetName()); SetMaker(Plugin->GetMaker()); SetTabIndex(Plugin->GetTabIndex()); @@ -336,10 +335,17 @@ void LADSPAPluginGUI::SetUpdateInputs(bool state) m_UpdateInputs->value(m_UpdateInputState); } -void LADSPAPluginGUI::SetPluginIndex(unsigned long n) +void LADSPAPluginGUI::SetUniqueID(unsigned long n) { - m_PluginIndex = n; - m_Browser->value(m_PluginIndex); + m_UniqueID = n; + + vector::iterator i = std::find(m_PluginIDLookup.begin(), m_PluginIDLookup.end(), m_UniqueID); + + if (i != m_PluginIDLookup.end()) { + m_Browser->value(i - m_PluginIDLookup.begin()); + } else { + m_Browser->value(0); + } } void LADSPAPluginGUI::SetName(const char *s) @@ -529,7 +535,6 @@ void LADSPAPluginGUI::Update(void) void LADSPAPluginGUI::ClearPlugin(void) { - m_PluginIndex = 0; m_InputPortCount = 0; m_PortIndex = 0; @@ -573,22 +578,22 @@ void LADSPAPluginGUI::SelectPlugin(void) m_GUICH->GetData("GetInputPortSettings", m_InputPortSettings); m_GUICH->GetData("GetInputPortDefaults", m_InputPortDefaults); - SetName((const char *)m_Name); + SetName((const char *)m_Name); SetMaker((const char *)m_Maker); for (unsigned long p = 0; p < m_InputPortCount; p++) { AddPortInfo((const char *)(m_InputPortNames + p * 256)); SetPortSettings(p, m_InputPortSettings[p].Min, - m_InputPortSettings[p].Max, - m_InputPortSettings[p].Clamp, - m_InputPortDefaults[p]); + m_InputPortSettings[p].Max, + m_InputPortSettings[p].Clamp, + m_InputPortDefaults[p]); SetDefaultAdjust(p); } UpdateDefaultAdjustControls(); m_PortIndex = m_InputPortCount; - + redraw(); } @@ -612,15 +617,15 @@ inline void LADSPAPluginGUI::cb_Select_i(Fl_Choice* o) { ClearPlugin(); - m_PluginIndex = o->value(); + unsigned long m_UniqueID = m_PluginIDLookup[o->value()]; - if (m_PluginIndex != 0) { - // Plugin selected - m_GUICH->SetData("SetPluginIndex",&m_PluginIndex); + if (m_UniqueID != 0) { + // Plugin selected + m_GUICH->SetData("SetUniqueID",&m_UniqueID); m_GUICH->SetCommand(LADSPAPlugin::SELECTPLUGIN); - m_GUICH->Wait(); + m_GUICH->Wait(); } - SelectPlugin(); + SelectPlugin(); // redraw(); } diff --git a/SpiralSound/Plugins/LADSPAPlugin/LADSPAPluginGUI.h b/SpiralSound/Plugins/LADSPAPlugin/LADSPAPluginGUI.h index e9b02f7..c3a940f 100644 --- a/SpiralSound/Plugins/LADSPAPlugin/LADSPAPluginGUI.h +++ b/SpiralSound/Plugins/LADSPAPlugin/LADSPAPluginGUI.h @@ -1,5 +1,7 @@ -/* SpiralPlugin +/* LADSPAPluginGUI.h * Copyleft (C) 2000 David Griffiths + * LADSPA Plugin by Nicolas Noble + * Modified by Mike Rawes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,7 +65,7 @@ private: void AddPortInfo(const char *Info); void SetTabIndex(int index); void SetUpdateInputs(bool state); - void SetPluginIndex(unsigned long n); + void SetUniqueID(unsigned long n); void SetName(const char *s); void SetMaker(const char *s); void SetPortSettings(unsigned long n, float min, float max, bool clamp, float defolt); @@ -72,8 +74,8 @@ private: void ClearPlugin(void); void SelectPlugin(void); - Fl_Color m_GUIColour; - Fl_Box *m_NameLabel; + Fl_Color m_GUIColour; + Fl_Box *m_NameLabel; Fl_Box *m_MakerLabel; Fl_Tabs *m_Tab; Fl_Group *m_ControlGroup; @@ -82,12 +84,12 @@ private: Fl_Group *m_SetupGroup; Fl_Choice *m_Browser; - Fl_Box *m_ValueLabel; - Fl_Box *m_DefaultLabel; - Fl_Box *m_MinLabel; - Fl_Box *m_MaxLabel; - Fl_Box *m_ClampLabel; - Fl_Box *m_PortLabel; + Fl_Box *m_ValueLabel; + Fl_Box *m_DefaultLabel; + Fl_Box *m_MinLabel; + Fl_Box *m_MaxLabel; + Fl_Box *m_ClampLabel; + Fl_Box *m_PortLabel; Fl_Scroll *m_InputScroll; Fl_Pack *m_InputPack; @@ -101,6 +103,7 @@ private: std::vector m_PortDefaultAdjustLabels; std::vector m_PluginList; + std::vector m_PluginIDLookup; unsigned long m_PortIndex; float m_Default; @@ -108,7 +111,7 @@ private: float m_Max; bool m_Clamp; - unsigned long m_PluginIndex; + unsigned long m_UniqueID; int m_TabIndex; bool m_UpdateInputState; char m_Name[256]; @@ -120,7 +123,7 @@ private: PortValues *m_InputPortValues; float *m_InputPortDefaults; - inline void cb_TabChange_i(Fl_Tabs *o); + inline void cb_TabChange_i(Fl_Tabs *o); static void cb_TabChange(Fl_Tabs *o); inline void cb_Select_i(Fl_Choice* o); static void cb_Select(Fl_Choice* o); @@ -138,6 +141,4 @@ private: static void cb_DefaultAdjust(Fl_Knob *o); }; - - #endif // __ladspa_plugin_gui_h__