8c17c9732e2c36ae712c54703cf5cb14409486a8
[terminatorX.git] / src / tX_ladspa.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2003  Alexander K├Ânig
4  
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9  
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  
19     File: tX_ladspa.cc
20  
21     Description: LADSPA_Plugin takes care of loading LADSPA plugins.
22                  Most of this code is based on the LADSPA SDK code by
23                  Richard W.E. Furse. For more information about ladspa
24                  checkout http://www.ladspa.org          
25 */
26
27 #include <tX_ladspa.h>
28 #include <tX_ladspa_class.h>
29 #include <dirent.h>
30 #include <dlfcn.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 std::list <LADSPA_Plugin *> LADSPA_Plugin :: plugin_list;
36
37 void LADSPA_Plugin :: init ()
38 {
39         char *ladspa_path_ptr;
40         char ladspa_path[PATH_MAX];
41         char *start, *end, *buffer;
42
43         /* Finding the LADSPA Path */
44         ladspa_path_ptr=getenv("LADSPA_PATH");
45         
46         if (!ladspa_path_ptr)  {
47                 tX_warning("LADSPA_PATH not set. Trying /usr/lib/ladspa:/usr/local/lib/ladspa");
48                 strcpy(ladspa_path, "/usr/lib/ladspa:/usr/local/lib/ladspa");
49         }
50         else strcpy(ladspa_path, ladspa_path_ptr);
51         
52         /* Scanning every dir in path */
53         start = ladspa_path;
54         
55         while (*start != '\0')
56         {
57                 end = start;
58                 while (*end != ':' && *end != '\0') end++;
59     
60                 buffer = (char *) malloc(1 + end - start);
61                 if (end > start) strncpy(buffer, start, end - start);
62                         
63                 buffer[end - start] = '\0';
64                 LADSPA_Plugin::scandir(buffer);
65                 free (buffer); 
66     
67                 start = end;
68                 if (*start == ':') start++;
69         }       
70 }
71
72 /* This routine expects to get *valid* port descriptors.
73    There's no error checking as in the LADSPA SDK's "analyseplugin".
74 */
75
76 void LADSPA_Plugin :: handlelib(void *lib, LADSPA_Descriptor_Function desc_func, char *filename)
77 {
78         long i;
79         unsigned long port;
80         const LADSPA_Descriptor *descriptor;
81         int in_audio, out_audio, in_ctrl;       
82         
83         for (i=0; (descriptor = desc_func(i)) != NULL; i++) {           
84                 if (LADSPA_IS_INPLACE_BROKEN(descriptor->Properties)) {
85                         tX_warning("Plugin \"%s\" disabled. No in-place processing support.", descriptor->Name);
86                 } else {                
87                         in_audio=0; out_audio=0; in_ctrl=0;
88                 
89                         for (port = 0; port<descriptor->PortCount; port++) {                    
90                                 if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[port])) {
91                                         if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) in_audio++;
92                                         else
93                                         if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[port])) out_audio++;
94                                 } else 
95                                         if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[port]) && LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) in_ctrl++;                    
96                         }
97                         
98                         if ((in_audio == 1) && (out_audio == 1)) {
99                                 new LADSPA_Plugin(descriptor, filename);
100                         }
101                         else { tX_warning("Plugin \"%s\" disabled. Not a 1-in/1-out plugin.", descriptor->Name); }
102                 }
103         }
104 }
105
106 void LADSPA_Plugin :: scandir(char *dirname)
107 {
108         int dirlen=strlen(dirname);
109         int needslash=0;
110         DIR * dir;
111         struct dirent * entry;
112         char *filename;
113         void *handle;
114         LADSPA_Descriptor_Function desc_func;
115         
116         if (!dirlen) { tX_error("tX: Error: empty directory name?"); return; };
117
118         if (dirname[dirlen - 1] != '/') needslash=1;
119         
120         dir = opendir(dirname);
121         
122         if (!dir) { tX_error("tX: Error: couldn't access directory \"%s\".", dirname); return; };
123         
124         while (1) {
125                 entry=readdir(dir);             
126                 if (!entry) { closedir(dir); return; }
127                 
128                 filename = (char *) malloc (dirlen + strlen(entry->d_name) + 1 + needslash);
129                 
130                 strcpy(filename, dirname);
131                 if (needslash) strcat(filename, "/");
132                 strcat(filename, entry->d_name);
133                 
134                 handle = dlopen(filename, RTLD_LAZY);
135                 
136                 if (handle) {
137                         /* clear dlerror */
138                         dlerror();
139                         
140                         /* check wether this is a LADSPA lib */
141                         desc_func = (LADSPA_Descriptor_Function) dlsym(handle, "ladspa_descriptor");
142                         
143                         if (dlerror() == NULL && desc_func) {
144                                 LADSPA_Plugin :: handlelib(handle, desc_func, entry->d_name);
145                         } else {
146                                 tX_error("tX: Error: %s is not a LADSPA plugin library.", filename);
147                                 dlclose(handle);
148                         }
149                 }
150                 
151                 free (filename);
152         }
153 }
154
155 void LADSPA_Plugin :: status ()
156 {
157         printf ("tX: %i LADSPA plugins available\n", plugin_list.size());
158         debug_display();
159 }
160
161 void LADSPA_Plugin :: debug_display()
162 {
163         std::list <LADSPA_Plugin *> :: iterator plugin;
164         
165         for (plugin=plugin_list.begin(); plugin != plugin_list.end(); plugin++) {
166                 printf("plugin: %60s | id: %5li | ports: %2li\n", (*plugin)->getName(), (*plugin)->getUniqueID(), (*plugin)->getPortCount());
167         }
168 }
169
170 LADSPA_Plugin :: LADSPA_Plugin (const LADSPA_Descriptor *ld, char *filename)
171 {
172         ladspa_descriptor = ld;
173         
174         plugin_list.push_back(this);
175         strcpy(file, filename);
176         sprintf(info_string, "LADSPA-Plugin: %s\nLabel: %s\nFile: %s\nUnique ID: %li\nMaker: %s\nCopyright: %s", ld->Name, ld->Label, file, ld->UniqueID, ld->Maker, ld->Copyright);
177         LADSPA_Class::add_plugin(this);
178 }
179
180 LADSPA_Plugin * LADSPA_Plugin :: getPluginByIndex(int i)
181 {
182         std::list <LADSPA_Plugin *> :: iterator plugin;
183         int p;
184         
185         plugin = plugin_list.begin();
186         for (p=0; (p<i) && (plugin != plugin_list.end()); p++, plugin++);
187         
188         if (plugin==plugin_list.end()) return NULL;
189         
190         else return (*plugin);
191 }
192
193 LADSPA_Plugin * LADSPA_Plugin :: getPluginByUniqueID(long ID)
194 {
195         std::list <LADSPA_Plugin *> :: iterator plugin;
196         
197         for (plugin=plugin_list.begin(); plugin != plugin_list.end(); plugin++) {
198                 if ((*plugin)->getUniqueID()==ID) return (*plugin);
199         }
200
201         return NULL;
202 }