MIDI set_sync_client fix, cleanups, compilation fixes for gcc 2.95 - Alex
[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         {               
85                 if (LADSPA_IS_INPLACE_BROKEN(descriptor->Properties)) {
86                         tX_warning("Plugin \"%s\" disabled. No in-place processing support.", descriptor->Name);
87                 }
88                 else
89                 {               
90                         in_audio=0; out_audio=0; in_ctrl=0;
91                 
92                         for (port = 0; port<descriptor->PortCount; port++)
93                         {                       
94                                 if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[port]))
95                                 {
96                                         if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) in_audio++;
97                                         else
98                                         if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[port])) out_audio++;
99                                 }
100                                 else 
101                                 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[port]) && LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) in_ctrl++;                    
102                         }
103                         
104                         if ((in_audio == 1) && (out_audio == 1)) {
105                                 new LADSPA_Plugin(descriptor, filename);
106                         }
107                         else { tX_warning("Plugin \"%s\" disabled. Not a 1-in/1-out plugin.", descriptor->Name); }
108                 }
109         }
110 }
111
112 void LADSPA_Plugin :: scandir(char *dirname)
113 {
114         int dirlen=strlen(dirname);
115         int needslash=0;
116         DIR * dir;
117         struct dirent * entry;
118         char *filename;
119         void *handle;
120         LADSPA_Descriptor_Function desc_func;
121         
122         if (!dirlen) { tX_error("tX: Error: empty directory name?"); return; };
123
124         if (dirname[dirlen - 1] != '/') needslash=1;
125         
126         dir = opendir(dirname);
127         
128         if (!dir) { tX_error("tX: Error: couldn't access directory \"%s\".", dirname); return; };
129         
130         while (1)
131         {
132                 entry=readdir(dir);
133                 
134                 if (!entry) { closedir(dir); return; }
135                 
136                 filename = (char *) malloc (dirlen + strlen(entry->d_name) + 1 + needslash);
137                 
138                 strcpy(filename, dirname);
139                 if (needslash) strcat(filename, "/");
140                 strcat(filename, entry->d_name);
141                 
142                 handle = dlopen(filename, RTLD_LAZY);
143                 
144                 if (handle)
145                 {
146                         /* clear dlerror */
147                         dlerror();
148                         
149                         /* check wether this is a LADSPA lib */
150                         desc_func = (LADSPA_Descriptor_Function) dlsym(handle, "ladspa_descriptor");
151                         
152                         if (dlerror() == NULL && desc_func) {
153                                 LADSPA_Plugin :: handlelib(handle, desc_func, entry->d_name);
154                         } else {
155                                 tX_error("tX: Error: %s is not a LADSPA plugin library.", filename);
156                                 dlclose(handle);
157                         }
158                 }
159                 
160                 free (filename);
161         }
162 }
163
164 void LADSPA_Plugin :: status ()
165 {
166         printf ("tX: %i LADSPA plugins available\n", plugin_list.size());
167         debug_display();
168 }
169
170 void LADSPA_Plugin :: debug_display()
171 {
172         std::list <LADSPA_Plugin *> :: iterator plugin;
173         
174         for (plugin=plugin_list.begin(); plugin != plugin_list.end(); plugin++)
175         {
176                 printf("plugin: %60s | id: %5li | ports: %2li\n", (*plugin)->getName(), (*plugin)->getUniqueID(), (*plugin)->getPortCount());
177         }
178 }
179
180 LADSPA_Plugin :: LADSPA_Plugin (const LADSPA_Descriptor *ld, char *filename)
181 {
182         ladspa_descriptor = ld;
183         
184         plugin_list.push_back(this);
185         strcpy(file, filename);
186         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);
187         LADSPA_Class::add_plugin(this);
188 }
189
190 LADSPA_Plugin * LADSPA_Plugin :: getPluginByIndex(int i)
191 {
192         std::list <LADSPA_Plugin *> :: iterator plugin;
193         int p;
194         
195         plugin = plugin_list.begin();
196         for (p=0; (p<i) && (plugin != plugin_list.end()); p++, plugin++);
197         
198         if (plugin==plugin_list.end()) return NULL;
199         
200         else return (*plugin);
201 }
202
203 LADSPA_Plugin * LADSPA_Plugin :: getPluginByUniqueID(long ID)
204 {
205         std::list <LADSPA_Plugin *> :: iterator plugin;
206         
207         for (plugin=plugin_list.begin(); plugin != plugin_list.end(); plugin++)
208         {
209                 if ((*plugin)->getUniqueID()==ID) return (*plugin);
210         }
211
212         return NULL;
213 }