Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

823 lines
22KB

  1. //
  2. // LADSPAInfo.C - Class for indexing information on LADSPA Plugins
  3. //
  4. // Copyleft (C) 2002 Mike Rawes <myk@waxfrenzy.org>
  5. //
  6. // This program is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation; either version 2 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // This program is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with this program; if not, write to the Free Software
  18. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. //
  20. // #include <config.h>
  21. #include <vector>
  22. #include <string>
  23. #include <list>
  24. #include <map>
  25. #include <iostream>
  26. #include <sstream>
  27. #include <algorithm>
  28. #include <stdio.h>
  29. #include <cstring>
  30. #include <cstdlib>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <dirent.h>
  34. #include <dlfcn.h>
  35. #include <ladspa.h>
  36. #define HAVE_LIBLRDF 1
  37. #ifdef HAVE_LIBLRDF
  38. #include <lrdf.h>
  39. #endif
  40. #include "LADSPAInfo.h"
  41. using namespace std;
  42. LADSPAInfo::LADSPAInfo(bool override,
  43. const char *path_list)
  44. {
  45. if (strlen(path_list) > 0) {
  46. m_ExtraPaths = strdup(path_list);
  47. } else {
  48. m_ExtraPaths = NULL;
  49. }
  50. m_LADSPAPathOverride = override;
  51. RescanPlugins();
  52. }
  53. LADSPAInfo::~LADSPAInfo()
  54. {
  55. CleanUp();
  56. }
  57. void
  58. LADSPAInfo::RescanPlugins(void)
  59. {
  60. // Clear out what we've got
  61. CleanUp();
  62. if (!m_LADSPAPathOverride) {
  63. // Get $LADPSA_PATH, if available
  64. char *ladspa_path = getenv("LADSPA_PATH");
  65. if (ladspa_path) {
  66. ScanPathList(ladspa_path, &LADSPAInfo::ExaminePluginLibrary);
  67. } else {
  68. cerr << "WARNING: LADSPA_PATH environment variable not set" << endl;
  69. cerr << " Assuming /usr/lib/ladspa:/usr/local/lib/ladspa" << endl;
  70. ScanPathList("/usr/lib/ladspa:/usr/local/lib/ladspa", &LADSPAInfo::ExaminePluginLibrary);
  71. }
  72. }
  73. // Check any supplied extra paths
  74. if (m_ExtraPaths) {
  75. ScanPathList(m_ExtraPaths, &LADSPAInfo::ExaminePluginLibrary);
  76. }
  77. // Do we have any plugins now?
  78. if (m_Plugins.size() == 0) {
  79. cerr << "WARNING: No plugins found" << endl;
  80. } else {
  81. cerr << m_Plugins.size() << " plugins found in " << m_Libraries.size() << " libraries" << endl;
  82. #ifdef HAVE_LIBLRDF
  83. // Got some plugins. Now search for RDF data
  84. lrdf_init();
  85. char *rdf_path = getenv("LADSPA_RDF_PATH");
  86. if (rdf_path) {
  87. // Examine rdf info
  88. ScanPathList(rdf_path, &LADSPAInfo::ExamineRDFFile);
  89. } else {
  90. cerr << "WARNING: LADSPA_RDF_PATH environment variable not set" << endl;
  91. cerr << " Assuming /usr/share/ladspa/rdf:/usr/local/share/ladspa/rdf" << endl;
  92. // Examine rdf info
  93. ScanPathList("/usr/share/ladspa/rdf:/usr/local/share/ladspa/rdf", &LADSPAInfo::ExamineRDFFile);
  94. }
  95. MetadataRDFDescend(LADSPA_BASE "Plugin", 0);
  96. // See which plugins were not added to an rdf group, and add them
  97. // all into the top level 'LADSPA' one
  98. list<unsigned long> rdf_p;
  99. // Get indices of plugins added to groups
  100. for (vector<RDFURIInfo>::iterator ri = m_RDFURIs.begin(); ri != m_RDFURIs.end(); ri++) {
  101. rdf_p.insert(rdf_p.begin(), ri->Plugins.begin(), ri->Plugins.end());
  102. }
  103. // Add all uncategorized plugins to top level group, subclassed by their
  104. // library's basename.
  105. rdf_p.unique();
  106. rdf_p.sort();
  107. unsigned long last_p = 0;
  108. for (list<unsigned long>::iterator p = rdf_p.begin(); p != rdf_p.end(); p++) {
  109. if ((*p - last_p) > 1) {
  110. for (unsigned long i = last_p + 1; i < *p; i++) {
  111. // URI 0 is top-level "LADSPA" group
  112. m_RDFURIs[0].Plugins.push_back(i);
  113. }
  114. }
  115. last_p = *p;
  116. }
  117. while (++last_p < m_Plugins.size()) {
  118. // URI 0 is top-level "LADSPA" group
  119. m_RDFURIs[0].Plugins.push_back(last_p);
  120. }
  121. lrdf_cleanup();
  122. #else
  123. // No RDF. Add all plugins to top-level group
  124. RDFURIInfo ri;
  125. ri.URI = "";
  126. ri.Label = "LADSPA";
  127. m_RDFURIs.push_back(ri);
  128. m_RDFLabelLookup["LADSPA"] = 0;
  129. for (unsigned long i = 0; i < m_Plugins.size(); i++) {
  130. // Add plugin index
  131. m_RDFURIs[0].Plugins.push_back(i);
  132. }
  133. #endif
  134. }
  135. }
  136. void
  137. LADSPAInfo::UnloadAllLibraries(void)
  138. {
  139. // Blank descriptors
  140. for (vector<PluginInfo>::iterator i = m_Plugins.begin();
  141. i != m_Plugins.end(); i++) {
  142. if (i->Descriptor) i->Descriptor = NULL;
  143. }
  144. // Unload DLLs,
  145. for (vector<LibraryInfo>::iterator i = m_Libraries.begin();
  146. i != m_Libraries.end(); i++) {
  147. if (i->Handle) {
  148. dlclose(i->Handle);
  149. i->Handle = NULL;
  150. }
  151. i->RefCount = 0;
  152. }
  153. }
  154. const LADSPA_Descriptor *
  155. LADSPAInfo::GetDescriptorByID(unsigned long unique_id)
  156. {
  157. if (m_IDLookup.find(unique_id) == m_IDLookup.end()) {
  158. cerr << "LADSPA Plugin ID " << unique_id << " not found!" << endl;
  159. return NULL;
  160. }
  161. // Got plugin index
  162. unsigned long plugin_index = m_IDLookup[unique_id];
  163. PluginInfo *pi = &(m_Plugins[plugin_index]);
  164. LibraryInfo *li = &(m_Libraries[pi->LibraryIndex]);
  165. if (!(pi->Descriptor)) {
  166. LADSPA_Descriptor_Function desc_func = GetDescriptorFunctionForLibrary(pi->LibraryIndex);
  167. if (desc_func) pi->Descriptor = desc_func(pi->Index);
  168. }
  169. if (pi->Descriptor) {
  170. // Success, so increment ref counter for library
  171. li->RefCount++;
  172. }
  173. return pi->Descriptor;
  174. }
  175. void
  176. LADSPAInfo::DiscardDescriptorByID(unsigned long unique_id)
  177. {
  178. if (m_IDLookup.find(unique_id) == m_IDLookup.end()) {
  179. cerr << "LADSPA Plugin ID " << unique_id << " not found!" << endl;
  180. } else {
  181. // Get plugin index
  182. unsigned long plugin_index = m_IDLookup[unique_id];
  183. PluginInfo *pi = &(m_Plugins[plugin_index]);
  184. LibraryInfo *li = &(m_Libraries[pi->LibraryIndex]);
  185. pi->Descriptor = NULL;
  186. // Decrement reference counter for library, and unload if last
  187. if (li->RefCount > 0) {
  188. li->RefCount--;
  189. if (li->RefCount == 0) {
  190. // Unload library
  191. dlclose(li->Handle);
  192. li->Handle = NULL;
  193. }
  194. }
  195. }
  196. }
  197. // ****************************************************************************
  198. // ** SSM Specific Functions **
  199. // ****************************************************************************
  200. unsigned long
  201. LADSPAInfo::GetIDFromFilenameAndLabel(std::string filename,
  202. std::string label)
  203. {
  204. bool library_loaded = false;
  205. if (m_FilenameLookup.find(filename) == m_FilenameLookup.end()) {
  206. cerr << "LADSPA Library " << filename << " not found!" << endl;
  207. return 0;
  208. }
  209. unsigned long library_index = m_FilenameLookup[filename];
  210. if (!(m_Libraries[library_index].Handle)) library_loaded = true;
  211. LADSPA_Descriptor_Function desc_func = GetDescriptorFunctionForLibrary(library_index);
  212. if (!desc_func) {
  213. return 0;
  214. }
  215. // Search for label in library
  216. const LADSPA_Descriptor *desc;
  217. for (unsigned long i = 0; (desc = desc_func(i)) != NULL; i++) {
  218. string l = desc->Label;
  219. if (l == label) {
  220. // If we had to load the library, unload it
  221. unsigned long id = desc->UniqueID;
  222. if (library_loaded) {
  223. dlclose(m_Libraries[library_index].Handle);
  224. m_Libraries[library_index].Handle = NULL;
  225. }
  226. return id;
  227. }
  228. }
  229. cerr << "Plugin " << label << " not found in library " << filename << endl;
  230. return 0;
  231. }
  232. const vector<LADSPAInfo::PluginEntry>
  233. LADSPAInfo::GetMenuList(void)
  234. {
  235. m_SSMMenuList.clear();
  236. DescendGroup("", "LADSPA", 1);
  237. return m_SSMMenuList;
  238. }
  239. const vector<LADSPAInfo::PluginInfo>
  240. LADSPAInfo::GetPluginInfo(void)
  241. {
  242. return m_Plugins;
  243. }
  244. unsigned long
  245. LADSPAInfo::GetPluginListEntryByID(unsigned long unique_id)
  246. {
  247. unsigned long j = 0;
  248. for (vector<PluginEntry>::iterator i = m_SSMMenuList.begin();
  249. i != m_SSMMenuList.end(); i++, j++) {
  250. if (i->UniqueID == unique_id) return j;
  251. }
  252. return m_SSMMenuList.size();
  253. }
  254. // ****************************************************************************
  255. // ** Private Member Functions **
  256. // ****************************************************************************
  257. // Build a list of plugins by group, suitable for SSM LADSPA Plugin drop-down
  258. // The top-level "LADSPA" group is not included
  259. void
  260. LADSPAInfo::DescendGroup(string prefix,
  261. const string group,
  262. unsigned int depth)
  263. {
  264. list<string> groups = GetSubGroups(group);
  265. if (prefix.length() > 0) {
  266. // Add an explicit '/' as we're creating sub-menus from groups
  267. prefix += "/";
  268. }
  269. for (list<string>::iterator g = groups.begin(); g != groups.end(); g++) {
  270. string name;
  271. // Escape '/' and '|' characters
  272. size_t x = g->find_first_of("/|");
  273. if (x == string::npos) {
  274. name = *g;
  275. } else {
  276. size_t last_x = 0;
  277. while (x < string::npos) {
  278. name += g->substr(last_x, x - last_x) + '\\' + (*g)[x];
  279. last_x = x + 1;
  280. x = g->find_first_of("/|", x + 1);
  281. }
  282. name += g->substr(last_x, x - last_x);
  283. }
  284. DescendGroup(prefix + name, *g, depth + 1);
  285. }
  286. if (m_RDFLabelLookup.find(group) != m_RDFLabelLookup.end()) {
  287. unsigned long uri_index = m_RDFLabelLookup[group];
  288. // Create group for unclassified plugins
  289. if (prefix.length() == 0) {
  290. prefix = "Unclassified/";
  291. depth = depth + 1;
  292. }
  293. // Temporary list (for sorting the plugins by name)
  294. list<PluginEntry> plugins;
  295. for (vector<unsigned long>::iterator p = m_RDFURIs[uri_index].Plugins.begin();
  296. p != m_RDFURIs[uri_index].Plugins.end(); p++) {
  297. PluginInfo *pi = &(m_Plugins[*p]);
  298. string name;
  299. // Escape '/' and '|' characters
  300. size_t x = pi->Name.find_first_of("/|");
  301. if (x == string::npos) {
  302. name = pi->Name;
  303. } else {
  304. size_t last_x = 0;
  305. while (x < string::npos) {
  306. name += pi->Name.substr(last_x, x - last_x) + '\\' + pi->Name[x];
  307. last_x = x + 1;
  308. x = pi->Name.find_first_of("/|", x + 1);
  309. }
  310. name += pi->Name.substr(last_x, x - last_x);
  311. }
  312. PluginEntry pe;
  313. pe.Depth = depth;
  314. pe.UniqueID = pi->UniqueID;
  315. pe.Name = name;
  316. pe.Category = prefix;
  317. pe.Category = pe.Category.substr(0, pe.Category.size()-1);
  318. plugins.push_back(pe);
  319. }
  320. plugins.sort();
  321. // Deal with duplicates by numbering them
  322. for (list<PluginEntry>::iterator i = plugins.begin();
  323. i != plugins.end(); ) {
  324. string name = i->Name;
  325. i++;
  326. unsigned long n = 2;
  327. while ((i != plugins.end()) && (i->Name == name)) {
  328. stringstream s;
  329. s << n;
  330. i->Name = name + " (" + s.str() + ")";
  331. n++;
  332. i++;
  333. }
  334. }
  335. // Add all ordered entries to the Menu List
  336. // This ensures that plugins appear after groups
  337. for (list<PluginEntry>::iterator p = plugins.begin(); p != plugins.end(); p++) {
  338. m_SSMMenuList.push_back(*p);
  339. }
  340. }
  341. }
  342. // Get list of groups that are within given group. The root group is
  343. // always "LADSPA"
  344. list<string>
  345. LADSPAInfo::GetSubGroups(const string group)
  346. {
  347. list<string> groups;
  348. unsigned long uri_index;
  349. if (m_RDFLabelLookup.find(group) == m_RDFLabelLookup.end()) {
  350. return groups;
  351. } else {
  352. uri_index = m_RDFLabelLookup[group];
  353. }
  354. for (vector<unsigned long>::iterator sg = m_RDFURIs[uri_index].Children.begin();
  355. sg != m_RDFURIs[uri_index].Children.end(); sg++) {
  356. groups.push_back(m_RDFURIs[*sg].Label);
  357. }
  358. groups.sort();
  359. return groups;
  360. }
  361. // Unload any loaded DLLs and clear vectors etc
  362. void
  363. LADSPAInfo::CleanUp(void)
  364. {
  365. m_MaxInputPortCount = 0;
  366. m_IDLookup.clear();
  367. m_Plugins.clear();
  368. // Unload loaded dlls
  369. for (vector<LibraryInfo>::iterator i = m_Libraries.begin();
  370. i != m_Libraries.end(); i++) {
  371. if (i->Handle) dlclose(i->Handle);
  372. }
  373. m_Libraries.clear();
  374. m_Paths.clear();
  375. m_RDFURILookup.clear();
  376. m_RDFURIs.clear();
  377. if (m_ExtraPaths) {
  378. free(m_ExtraPaths);
  379. m_ExtraPaths = NULL;
  380. }
  381. }
  382. // Given a colon-separated list of paths, examine the contents of each
  383. // path, examining any regular files using the given member function,
  384. // which currently can be:
  385. //
  386. // ExaminePluginLibrary - add plugin library info from plugins
  387. // ExamineRDFFile - add plugin information from .rdf/.rdfs files
  388. void
  389. LADSPAInfo::ScanPathList(const char *path_list,
  390. void (LADSPAInfo::*ExamineFunc)(const string,
  391. const string))
  392. {
  393. const char *start;
  394. const char *end;
  395. int extra;
  396. char *path;
  397. string basename;
  398. DIR *dp;
  399. struct dirent *ep;
  400. struct stat sb;
  401. // This does the same kind of thing as strtok, but strtok won't
  402. // like the const
  403. start = path_list;
  404. while (*start != '\0') {
  405. while (*start == ':') start++;
  406. end = start;
  407. while (*end != ':' && *end != '\0') end++;
  408. if (end - start > 0) {
  409. extra = (*(end - 1) == '/') ? 0 : 1;
  410. path = (char *)malloc(end - start + 1 + extra);
  411. if (path) {
  412. strncpy(path, start, end - start);
  413. if (extra == 1) path[end - start] = '/';
  414. path[end - start + extra] = '\0';
  415. dp = opendir(path);
  416. if (!dp) {
  417. cerr << "WARNING: Could not open path " << path << endl;
  418. } else {
  419. while ((ep = readdir(dp))) {
  420. // Stat file to get type
  421. basename = ep->d_name;
  422. if (!stat((path + basename).c_str(), &sb)) {
  423. // We only want regular files
  424. if (S_ISREG(sb.st_mode)) (*this.*ExamineFunc)(path, basename);
  425. }
  426. }
  427. closedir(dp);
  428. }
  429. free(path);
  430. }
  431. }
  432. start = end;
  433. }
  434. }
  435. // Check given file is a valid LADSPA Plugin library
  436. //
  437. // If so, add path, library and plugin info
  438. // to the m_Paths, m_Libraries and m_Plugins vectors.
  439. //
  440. void
  441. LADSPAInfo::ExaminePluginLibrary(const string path,
  442. const string basename)
  443. {
  444. void *handle;
  445. LADSPA_Descriptor_Function desc_func;
  446. const LADSPA_Descriptor *desc;
  447. string fullpath = path + basename;
  448. // We're not executing any code, so be lazy about resolving symbols
  449. handle = dlopen(fullpath.c_str(), RTLD_LAZY);
  450. if (!handle) {
  451. cerr << "WARNING: File " << fullpath
  452. << " could not be examined" << endl;
  453. cerr << "dlerror() output:" << endl;
  454. cerr << dlerror() << endl;
  455. } else {
  456. // It's a DLL, so now see if it's a LADSPA plugin library
  457. desc_func = (LADSPA_Descriptor_Function)dlsym(handle,
  458. "ladspa_descriptor");
  459. if (!desc_func) {
  460. // Is DLL, but not a LADSPA one
  461. cerr << "WARNING: DLL " << fullpath
  462. << " has no ladspa_descriptor function" << endl;
  463. cerr << "dlerror() output:" << endl;
  464. cerr << dlerror() << endl;
  465. } else {
  466. // Got ladspa_descriptor, so we can now get plugin info
  467. bool library_added = false;
  468. unsigned long i = 0;
  469. desc = desc_func(i);
  470. while (desc) {
  471. // First, check that it's not a dupe
  472. if (m_IDLookup.find(desc->UniqueID) != m_IDLookup.end()) {
  473. unsigned long plugin_index = m_IDLookup[desc->UniqueID];
  474. unsigned long library_index = m_Plugins[plugin_index].LibraryIndex;
  475. unsigned long path_index = m_Libraries[library_index].PathIndex;
  476. cerr << "WARNING: Duplicated Plugin ID ("
  477. << desc->UniqueID << ") found:" << endl;
  478. cerr << " Plugin " << m_Plugins[plugin_index].Index
  479. << " in library: " << m_Paths[path_index]
  480. << m_Libraries[library_index].Basename
  481. << " [First instance found]" << endl;
  482. cerr << " Plugin " << i << " in library: " << fullpath
  483. << " [Duplicate not added]" << endl;
  484. } else {
  485. if (CheckPlugin(desc)) {
  486. // Add path if not already added
  487. unsigned long path_index;
  488. vector<string>::iterator p = find(m_Paths.begin(), m_Paths.end(), path);
  489. if (p == m_Paths.end()) {
  490. path_index = m_Paths.size();
  491. m_Paths.push_back(path);
  492. } else {
  493. path_index = p - m_Paths.begin();
  494. }
  495. // Add library info if not already added
  496. if (!library_added) {
  497. LibraryInfo li;
  498. li.PathIndex = path_index;
  499. li.Basename = basename;
  500. li.RefCount = 0;
  501. li.Handle = NULL;
  502. m_Libraries.push_back(li);
  503. library_added = true;
  504. }
  505. // Add plugin info
  506. PluginInfo pi;
  507. pi.LibraryIndex = m_Libraries.size() - 1;
  508. pi.Index = i;
  509. pi.UniqueID = desc->UniqueID;
  510. pi.Label = desc->Label;
  511. pi.Name = desc->Name;
  512. pi.Descriptor = NULL;
  513. pi.Maker = desc->Maker;
  514. pi.AudioInputs = 0;
  515. pi.AudioOutputs = 0;
  516. // Find number of input ports
  517. unsigned long in_port_count = 0;
  518. for (unsigned long p = 0; p < desc->PortCount; p++) {
  519. if (LADSPA_IS_PORT_INPUT(desc->PortDescriptors[p])) {
  520. in_port_count++;
  521. if ( LADSPA_IS_PORT_AUDIO(desc->PortDescriptors[p] ) )
  522. pi.AudioInputs++;
  523. }
  524. }
  525. for (unsigned long p = 0; p < desc->PortCount; p++) {
  526. if (LADSPA_IS_PORT_OUTPUT(desc->PortDescriptors[p])) {
  527. if ( LADSPA_IS_PORT_AUDIO(desc->PortDescriptors[p] ) )
  528. pi.AudioOutputs++;
  529. }
  530. }
  531. if (in_port_count > m_MaxInputPortCount) {
  532. m_MaxInputPortCount = in_port_count;
  533. }
  534. m_Plugins.push_back(pi);
  535. // Add to index
  536. m_IDLookup[desc->UniqueID] = m_Plugins.size() - 1;
  537. } else {
  538. cerr << "WARNING: Plugin " << desc->UniqueID << " not added" << endl;
  539. }
  540. }
  541. desc = desc_func(++i);
  542. }
  543. }
  544. dlclose(handle);
  545. }
  546. }
  547. #ifdef HAVE_LIBLRDF
  548. // Examine given RDF plugin meta-data file
  549. void
  550. LADSPAInfo::ExamineRDFFile(const std::string path,
  551. const std::string basename)
  552. {
  553. string fileuri = "file://" + path + basename;
  554. if (lrdf_read_file(fileuri.c_str())) {
  555. cerr << "WARNING: File " << path + basename << " could not be parsed [Ignored]" << endl;
  556. }
  557. }
  558. // Recursively add rdf information for plugins that have been
  559. // found from scanning LADSPA_PATH
  560. void
  561. LADSPAInfo::MetadataRDFDescend(const char * uri,
  562. unsigned long parent)
  563. {
  564. unsigned long this_uri_index;
  565. // Check URI not already added
  566. if (m_RDFURILookup.find(uri) == m_RDFURILookup.end()) {
  567. // Not found
  568. RDFURIInfo ri;
  569. ri.URI = uri;
  570. if (ri.URI == LADSPA_BASE "Plugin") {
  571. // Add top level group as "LADSPA"
  572. // This will always happen, even if there are no .rdf files read by liblrdf
  573. // or if there is no liblrdf support
  574. ri.Label = "LADSPA";
  575. } else {
  576. char * label = lrdf_get_label(uri);
  577. if (label) {
  578. ri.Label = label;
  579. } else {
  580. ri.Label = "(No label)";
  581. }
  582. }
  583. // Add any instances found
  584. lrdf_uris * instances = lrdf_get_instances(uri);
  585. if (instances) {
  586. for (unsigned long j = 0; j < instances->count; j++) {
  587. unsigned long uid = lrdf_get_uid(instances->items[j]);
  588. if (m_IDLookup.find(uid) != m_IDLookup.end()) {
  589. ri.Plugins.push_back(m_IDLookup[uid]);
  590. }
  591. }
  592. }
  593. lrdf_free_uris(instances);
  594. m_RDFURIs.push_back(ri);
  595. this_uri_index = m_RDFURIs.size() - 1;
  596. m_RDFURILookup[ri.URI] = this_uri_index;
  597. m_RDFLabelLookup[ri.Label] = this_uri_index;
  598. } else {
  599. // Already added
  600. this_uri_index = m_RDFURILookup[uri];
  601. }
  602. // Only add parent - child info if this uri is NOT the first (root) uri
  603. if (this_uri_index > 0) {
  604. m_RDFURIs[this_uri_index].Parents.push_back(parent);
  605. m_RDFURIs[parent].Children.push_back(this_uri_index);
  606. }
  607. lrdf_uris * uris = lrdf_get_subclasses(uri);
  608. if (uris) {
  609. for (unsigned long i = 0; i < uris->count; i++) {
  610. MetadataRDFDescend(uris->items[i], this_uri_index);
  611. }
  612. }
  613. lrdf_free_uris(uris);
  614. }
  615. #endif
  616. bool
  617. LADSPAInfo::CheckPlugin(const LADSPA_Descriptor *desc)
  618. {
  619. #define test(t, m) { \
  620. if (!(t)) { \
  621. cerr << m << endl; \
  622. return false; \
  623. } \
  624. }
  625. test(desc->instantiate, "WARNING: Plugin has no instatiate function");
  626. test(desc->connect_port, "WARNING: Warning: Plugin has no connect_port funciton");
  627. test(desc->run, "WARNING: Plugin has no run function");
  628. test(!(desc->run_adding != 0 && desc->set_run_adding_gain == 0),
  629. "WARNING: Plugin has run_adding but no set_run_adding_gain");
  630. test(!(desc->run_adding == 0 && desc->set_run_adding_gain != 0),
  631. "WARNING: Plugin has set_run_adding_gain but no run_adding");
  632. test(desc->cleanup, "WARNING: Plugin has no cleanup function");
  633. test(!LADSPA_IS_INPLACE_BROKEN(desc->Properties),
  634. "WARNING: Plugin cannot use in place processing");
  635. test(desc->PortCount, "WARNING: Plugin has no ports");
  636. test(desc->Name, "WARNING: Plugin has no name" );
  637. test( !( LADSPA_IS_INPLACE_BROKEN( desc->Properties ) ), "WARNING: plugin inplace processing is broken" );
  638. test ( LADSPA_IS_HARD_RT_CAPABLE( desc->Properties ), "WARNING: Plugin is not RT incapable" );
  639. return true;
  640. }
  641. LADSPA_Descriptor_Function
  642. LADSPAInfo::GetDescriptorFunctionForLibrary(unsigned long library_index)
  643. {
  644. LibraryInfo *li = &(m_Libraries[library_index]);
  645. if (!(li->Handle)) {
  646. // Need full path
  647. string fullpath = m_Paths[li->PathIndex];
  648. fullpath.append(li->Basename);
  649. // Immediate symbol resolution, as plugin code is likely to be executed
  650. li->Handle = dlopen(fullpath.c_str(), RTLD_NOW);
  651. if (!(li->Handle)) {
  652. // Plugin library changed since last path scan
  653. cerr << "WARNING: Plugin library " << fullpath << " cannot be loaded" << endl;
  654. cerr << "Rescan of plugins recommended" << endl;
  655. cerr << "dlerror() output:" << endl;
  656. cerr << dlerror() << endl;
  657. return NULL;
  658. }
  659. }
  660. // Got handle so now verify that it's a LADSPA plugin library
  661. const LADSPA_Descriptor_Function desc_func = (LADSPA_Descriptor_Function)dlsym(li->Handle,
  662. "ladspa_descriptor");
  663. if (!desc_func) {
  664. // Is DLL, but not a LADSPA one (changed since last path scan?)
  665. cerr << "WARNING: DLL " << m_Paths[li->PathIndex] << li->Basename
  666. << " has no ladspa_descriptor function" << endl;
  667. cerr << "Rescan of plugins recommended" << endl;
  668. cerr << "dlerror() output:" << endl;
  669. cerr << dlerror() << endl;
  670. // Unload library
  671. dlclose(li->Handle);
  672. return NULL;
  673. }
  674. return desc_func;
  675. }