7ee6ad46180590b2de03fa23652547af1697d029
[terminatorX.git] / src / tX_ladspa.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2002  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 <dirent.h>
29 #include <dlfcn.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 list <LADSPA_Plugin *> LADSPA_Plugin :: plugin_list;
35
36 void LADSPA_Plugin :: init ()
37 {
38         char *ladspa_path_ptr;
39         char ladspa_path[PATH_MAX];
40         char *start, *end, *buffer;
41
42         printf("tX: Looking for LADSPA plugins.\n");
43         
44         /* Finding the LADSPA Path */
45         ladspa_path_ptr=getenv("LADSPA_PATH");
46         
47         if (!ladspa_path_ptr) 
48         {
49                 fprintf(stderr, "tX: Warning: LADSPA_PATH not set. Trying /usr/lib/ladspa:/usr/local/lib/ladspa.\n");
50                 strcpy(ladspa_path, "/usr/lib/ladspa:/usr/local/lib/ladspa");
51         }
52         else strcpy(ladspa_path, ladspa_path_ptr);
53         
54         /* Scanning every dir in path */
55         start = ladspa_path;
56         
57         while (*start != '\0')
58         {
59                 end = start;
60                 while (*end != ':' && *end != '\0') end++;
61     
62                 buffer = (char *) malloc(1 + end - start);
63                 if (end > start) strncpy(buffer, start, end - start);
64                         
65                 buffer[end - start] = '\0';
66                 LADSPA_Plugin::scandir(buffer);
67                 free (buffer); 
68     
69                 start = end;
70                 if (*start == ':') start++;
71         }       
72 }
73
74 /* This routine expects to get *valid* port descriptors.
75    There's no error checking as in the LADSPA SDK's "analyseplugin".
76 */
77
78 void LADSPA_Plugin :: handlelib(void *lib, LADSPA_Descriptor_Function desc_func, char *filename)
79 {
80         long i;
81         long port;
82         const LADSPA_Descriptor *descriptor;
83         int in_audio, out_audio, in_ctrl;       
84         
85         for (i=0; (descriptor = desc_func(i)) != NULL; i++)
86         {               
87                 if (LADSPA_IS_INPLACE_BROKEN(descriptor->Properties))
88                 {
89                         fprintf(stderr, "tX: Plugin \"%s\" disabled. No in-place processing support.\n", descriptor->Name);
90                 }
91                 else
92                 {               
93                         in_audio=0; out_audio=0; in_ctrl=0;
94                 
95                         for (port = 0; port<descriptor->PortCount; port++)
96                         {                       
97                                 if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[port]))
98                                 {
99                                         if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) in_audio++;
100                                         else
101                                         if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[port])) out_audio++;
102                                 }
103                                 else 
104                                 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[port]) && LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) in_ctrl++;                    
105                         }
106                         
107                         if ((in_audio == 1) && (out_audio == 1))
108                         {
109                                 printf("tX: Plugin \"%s\" loaded.\n", descriptor->Name);
110                                 new LADSPA_Plugin(descriptor, filename);
111                         }
112                         else fprintf(stderr, "tX: Plugin \"%s\" disabled. Not a 1-in/1-out plugin.\n", descriptor->Name);
113                 }
114         }
115 }
116
117 void LADSPA_Plugin :: scandir(char *dirname)
118 {
119         int dirlen=strlen(dirname);
120         int needslash=0;
121         DIR * dir;
122         struct dirent * entry;
123         char *filename;
124         void *handle;
125         LADSPA_Descriptor_Function desc_func;
126
127         printf("tX: Scanning %s for LADSPA plugins.\n", dirname);
128         
129         if (!dirlen) { fprintf(stderr, "tX: Error: empty directory name?\n"); return; };
130
131         if (dirname[dirlen - 1] != '/') needslash=1;
132         
133         dir = opendir(dirname);
134         
135         if (!dir) { fprintf(stderr, "tX: Error: couldn't access directory.\n"); return; };
136         
137         while (1)
138         {
139                 entry=readdir(dir);
140                 
141                 if (!entry) { closedir(dir); return; }
142                 
143                 filename = (char *) malloc (dirlen + strlen(entry->d_name) + 1 + needslash);
144                 
145                 strcpy(filename, dirname);
146                 if (needslash) strcat(filename, "/");
147                 strcat(filename, entry->d_name);
148                 
149                 handle = dlopen(filename, RTLD_LAZY);
150                 
151                 if (handle)
152                 {
153                         /* clear dlerror */
154                         dlerror();
155                         
156                         /* check wether this is a LADSPA lib */
157                         desc_func = (LADSPA_Descriptor_Function) dlsym(handle, "ladspa_descriptor");
158                         
159                         if (dlerror() == NULL && desc_func)
160                         {
161                                 printf("tX: Analyzing LADSPA plugin library %s.\n", filename);
162                                 LADSPA_Plugin :: handlelib(handle, desc_func, entry->d_name);
163                         }
164                         else
165                         {
166                                 fprintf(stderr, "tX: Error: %s is not a LADSPA plugin library.");
167                                 dlclose(handle);
168                         }
169                 }
170                 
171                 free (filename);
172         }
173 }
174
175 void LADSPA_Plugin :: status ()
176 {
177         printf ("tX: %i LADSPA plugins available\n", plugin_list.size());
178         debug_display();
179 }
180
181 void LADSPA_Plugin :: debug_display()
182 {
183         list <LADSPA_Plugin *> :: iterator plugin;
184         
185         for (plugin=plugin_list.begin(); plugin != plugin_list.end(); plugin++)
186         {
187                 printf("plugin: %60s | id: %5i | ports: %2i\n", (*plugin)->getName(), (*plugin)->getUniqueID(), (*plugin)->getPortCount());
188         }
189 }
190
191 LADSPA_Plugin :: LADSPA_Plugin (const LADSPA_Descriptor *ld, char *filename)
192 {
193         ladspa_descriptor = ld;
194         plugin_list.push_back(this);
195         strcpy(file, filename);
196         sprintf (info_string, "   LADSPA-Plugin: %s   \n   Label: %s   \n   File: %s   \n   Unique ID: %i   \n   Maker: %s   \n   Copyright: %s   ", ld->Name, ld->Label, file, ld->UniqueID, ld->Maker, ld->Copyright);
197 }
198
199 LADSPA_Plugin * LADSPA_Plugin :: getPluginByIndex(int i)
200 {
201         list <LADSPA_Plugin *> :: iterator plugin;
202         int p;
203         
204         plugin = plugin_list.begin();
205         for (p=0; (p<i) && (plugin != plugin_list.end()); p++, plugin++);
206         
207         if (plugin==plugin_list.end()) return NULL;
208         
209         else return (*plugin);
210 }
211
212 LADSPA_Plugin * LADSPA_Plugin :: getPluginByUniqueID(long ID)
213 {
214         list <LADSPA_Plugin *> :: iterator plugin;
215         
216         for (plugin=plugin_list.begin(); plugin != plugin_list.end(); plugin++)
217         {
218                 if ((*plugin)->getUniqueID()==ID) return (*plugin);
219         }
220
221         return NULL;
222 }