It's 2020...
[terminatorX.git] / src / tX_ladspa.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2020  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, see <http://www.gnu.org/licenses/>.
17  
18     File: tX_ladspa.cc
19  
20     Description: LADSPA_Plugin takes care of loading LADSPA plugins.
21                  Most of this code is based on the LADSPA SDK code by
22                  Richard W.E. Furse. For more information about ladspa
23                  checkout http://www.ladspa.org          
24 */
25
26 #include <tX_ladspa.h>
27 #include <tX_ladspa_class.h>
28 #include <dirent.h>
29 #include <dlfcn.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 std::list <LADSPA_Plugin *> LADSPA_Plugin :: plugin_list;
35 std::list <LADSPA_Stereo_Plugin *> LADSPA_Stereo_Plugin :: stereo_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 strncpy(ladspa_path, ladspa_path_ptr, sizeof(ladspa_path));
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_plugin_warning("Plugin \"%s\" [%li] disabled: No in-place processing support.", descriptor->Label, descriptor->UniqueID);
86                 } else if (!LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties) && !globals.force_nonrt_plugins) {
87                         tX_plugin_warning("Plugin \"%s\" [%li] disabled: Not realtime capable.", descriptor->Label, descriptor->UniqueID);
88                 } else {
89                         if (!LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties)) {
90                                 tX_warning("Plugin \"%s\" [%li] is classified as non-rt capable: loading forced.", descriptor->Label, descriptor->UniqueID);
91                         }
92                         in_audio=0; out_audio=0; in_ctrl=0;
93                 
94                         for (port = 0; port<descriptor->PortCount; port++) {                    
95                                 if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[port])) {
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                                 } else 
100                                         if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[port]) && LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) in_ctrl++;                    
101                         }
102                         
103                         if ((in_audio == 1) && (out_audio == 1)) {
104                                 new LADSPA_Plugin(descriptor, filename);
105                         } if ((in_audio == 2) && (out_audio == 2)) {
106                                 new LADSPA_Stereo_Plugin(descriptor, filename);
107                         }
108                         else { tX_plugin_warning("Plugin \"%s\" [%li] disabled: Neither mono nor stereo.", descriptor->Label, descriptor->UniqueID); }
109                 }
110         }
111 }
112
113 void LADSPA_Plugin :: scandir(char *dirname)
114 {
115         int dirlen=strlen(dirname);
116         int needslash=0;
117         DIR * dir;
118         struct dirent * entry;
119         char *filename;
120         void *handle;
121         LADSPA_Descriptor_Function desc_func;
122         
123         if (!dirlen) { tX_error("empty directory name?"); return; };
124
125         if (dirname[dirlen - 1] != '/') needslash=1;
126         
127         dir = opendir(dirname);
128         
129         if (!dir) { tX_error("couldn't access directory \"%s\".", dirname); return; };
130         
131         while (1) {
132                 entry=readdir(dir);             
133                 if (!entry) { closedir(dir); return; }
134                 
135                 filename = (char *) malloc (dirlen + strlen(entry->d_name) + 1 + needslash);
136                 
137                 strcpy(filename, dirname);
138                 if (needslash) strcat(filename, "/");
139                 strcat(filename, entry->d_name);
140                 
141                 handle = dlopen(filename, RTLD_LAZY);
142                 
143                 if (handle) {
144                         /* clear dlerror */
145                         dlerror();
146                         
147                         /* check wether this is a LADSPA lib */
148                         desc_func = (LADSPA_Descriptor_Function) dlsym(handle, "ladspa_descriptor");
149                         
150                         if (dlerror() == NULL && desc_func) {
151                                 LADSPA_Plugin :: handlelib(handle, desc_func, entry->d_name);
152                         } else {
153                                 tX_error("\"%s\" is not a LADSPA plugin library.", filename);
154                                 dlclose(handle);
155                         }
156                 }
157                 
158                 free (filename);
159         }
160 }
161
162 void LADSPA_Plugin :: status ()
163 {
164         debug_display();
165 }
166
167 void LADSPA_Plugin :: debug_display()
168 {
169         std::list <LADSPA_Plugin *> :: iterator plugin;
170         
171         for (plugin=plugin_list.begin(); plugin != plugin_list.end(); plugin++) {
172                 printf("plugin: %60s | id: %5li | ports: %2li\n", (*plugin)->getName(), (*plugin)->getUniqueID(), (*plugin)->getPortCount());
173         }
174 }
175
176 LADSPA_Plugin :: LADSPA_Plugin (const LADSPA_Descriptor *ld, char *filename)
177 {
178         ladspa_descriptor = ld;
179         
180         plugin_list.push_back(this);
181         strcpy(file, filename);
182         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);
183         LADSPA_Class::add_plugin(this);
184 }
185
186 LADSPA_Plugin * LADSPA_Plugin :: getPluginByIndex(int i)
187 {
188         std::list <LADSPA_Plugin *> :: iterator plugin;
189         int p;
190         
191         plugin = plugin_list.begin();
192         for (p=0; (p<i) && (plugin != plugin_list.end()); p++, plugin++);
193         
194         if (plugin==plugin_list.end()) return NULL;
195         
196         else return (*plugin);
197 }
198
199 LADSPA_Plugin * LADSPA_Plugin :: getPluginByUniqueID(long ID)
200 {
201         std::list <LADSPA_Plugin *> :: iterator plugin;
202         
203         for (plugin=plugin_list.begin(); plugin != plugin_list.end(); plugin++) {
204                 if ((*plugin)->getUniqueID()==ID) return (*plugin);
205         }
206
207         return NULL;
208 }
209
210 /* STEREO */
211
212 LADSPA_Stereo_Plugin :: LADSPA_Stereo_Plugin (const LADSPA_Descriptor *ld, char *filename)
213 {
214         ladspa_descriptor = ld;
215         
216         stereo_plugin_list.push_back(this);
217         strcpy(file, filename);
218         sprintf(info_string, "LADSPA-Stereo-Plugin: %s\nLabel: %s\nFile: %s\nUnique ID: %li\nMaker: %s\nCopyright: %s", ld->Name, ld->Label, file, ld->UniqueID, ld->Maker, ld->Copyright);
219         LADSPA_Class::add_stereo_plugin(this);
220 }
221
222 LADSPA_Stereo_Plugin * LADSPA_Stereo_Plugin :: getPluginByIndex(int i)
223 {
224         std::list <LADSPA_Stereo_Plugin *> :: iterator plugin;
225         int p;
226         
227         plugin = stereo_plugin_list.begin();
228         for (p=0; (p<i) && (plugin != stereo_plugin_list.end()); p++, plugin++);
229         
230         if (plugin==stereo_plugin_list.end()) return NULL;
231         
232         else return (*plugin);
233 }
234
235 LADSPA_Stereo_Plugin * LADSPA_Stereo_Plugin :: getPluginByUniqueID(long ID)
236 {
237         std::list <LADSPA_Stereo_Plugin *> :: iterator plugin;
238         
239         for (plugin=stereo_plugin_list.begin(); plugin != stereo_plugin_list.end(); plugin++) {
240                 if ((*plugin)->getUniqueID()==ID) return (*plugin);
241         }
242
243         return NULL;
244 }
245
246 bool LADSPA_Stereo_Plugin::is_stereo() { return true; }
247 bool LADSPA_Plugin::is_stereo() { return false; }