Fixing a memory corruption - and changing the way tX_midiin works. Not
[terminatorX.git] / terminatorX / src / tX_ladspa_class.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_class.cc
20 */
21
22 #include "tX_ladspa_class.h"
23 #include "tX_global.h"
24 #include <dirent.h>
25 #include <dlfcn.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #ifdef USE_LRDF
31 #include <lrdf.h>
32 #endif
33
34 LADSPA_Class * LADSPA_Class::root=NULL;
35 LADSPA_Class * LADSPA_Class::unclassified=NULL;
36 std::list <char *> LADSPA_Class::rdf_files;
37 vtt_class *LADSPA_Class::current_vtt;
38
39 /* Why do have to code this myself? */
40 static int compare(const char *a, const char *b) {
41         int lena, lenb, i;
42
43         if (!a && !b) return 0;
44         if (!a) return 2;
45         if (!b) return 1;
46         
47         lena=strlen(a);
48         lenb=strlen(b);
49         
50         for (i=0; (i<lena) && (i<lenb); i++) {
51                 if (a[i]>b[i]) {
52                         return 2;
53                 } else if (a[i]<b[i]) {
54                         return 1;
55                 }
56         }
57         
58         if (lena>lenb) return 1;
59         else if (lenb>lena) return 2;
60         return 0;
61 }
62
63 void LADSPA_Class::init() {
64         char *start, *end, *buffer;
65
66 #ifdef USE_LRDF
67         /* Scanning every dir in path */
68         start = globals.lrdf_path;
69         
70         while (*start != '\0') {
71                 end = start;
72                 while (*end != ':' && *end != '\0') end++;
73     
74                 buffer = (char *) malloc(1 + end - start);
75                 if (end > start) strncpy(buffer, start, end - start);
76                         
77                 buffer[end - start] = '\0';
78                 LADSPA_Class::scandir(buffer);
79                 free (buffer); 
80     
81         start = end;
82         if (*start == ':') start++;
83         }
84         
85         if (rdf_files.size() > 0) {
86                 char *uris[rdf_files.size()+1];
87                 std::list <char *> :: iterator i;
88                 int t;
89                 
90                 for (i=rdf_files.begin(), t=0; i!=rdf_files.end(); i++, t++) {
91                         uris[t]=(*i);
92                 }
93                 uris[t]=NULL;
94                 
95                 lrdf_init();
96         
97                 if (lrdf_read_files((const char **) uris)) {
98                         tX_error("liblrdf had problems reading the rdf files");
99         }
100 #endif
101                 root=new LADSPA_Class("http://ladspa.org/ontology#Plugin");
102 #ifdef USE_LRDF         
103                 lrdf_cleanup();
104         } else {
105                 tX_error("No RDF files found");
106         }
107 #endif
108         
109         unclassified=new LADSPA_Class();
110         /* This is the last class to accpet all plugins not accepted by other classes. */
111         root->subclasses.push_back(unclassified);
112 }
113
114 void LADSPA_Class::scandir(char *dirname) {
115         int dirlen=strlen(dirname);
116         int needslash=0;
117         DIR * dir;
118         struct dirent * entry;
119         char *filename;
120         
121         if (!dirlen) { tX_error("LADSPA_Class::scandir() Empty directory name"); return; };
122
123         if (dirname[dirlen - 1] != '/') needslash=1;
124         
125         dir = opendir(dirname);
126         
127         if (!dir) { tX_error("LADSPA_Class::scandir() couldn't access directory \"%s\"", dirname); return; };
128         
129         while (1) {
130                 entry=readdir(dir);
131                 
132                 if (!entry) { closedir(dir); return; }
133                 
134                 if ((strcmp(entry->d_name, ".")==0) ||
135                         (strcmp(entry->d_name, "..")==0)) continue;
136                 
137                 filename = (char *) malloc (dirlen + strlen(entry->d_name) + 10 + needslash);
138                 
139                 strcpy(filename, "file:");
140                 strcat(filename, dirname);
141                 if (needslash) strcat(filename, "/");
142                 strcat(filename, entry->d_name);
143                 
144                 tX_debug("Found RDF file: %s", filename);
145                 rdf_files.push_back(filename);          
146         }       
147 }
148
149 void LADSPA_Class::insert_class(LADSPA_Class *cls) {
150         std::list <LADSPA_Class *> :: iterator i;
151         
152         for (i=subclasses.begin(); i!=subclasses.end(); i++) {
153                 LADSPA_Class *a_class=(*i);
154                 int res=compare(cls->label, a_class->label);
155                 
156                 if (res < 2) {
157                         subclasses.insert(i, cls);
158                         return;
159                 }
160         }
161         
162         subclasses.push_back(cls);
163 }
164
165 LADSPA_Class :: LADSPA_Class (char *uri) : label(NULL), accept_all(false) {
166 #ifdef USE_LRDF 
167         lrdf_uris *ulist;
168         char *urilabel;
169         int i;
170         
171         urilabel=lrdf_get_label(uri);
172         
173         if (urilabel) {
174                 label=strdup(urilabel);
175         }
176         
177         /* Finding subclasses... */
178         ulist = lrdf_get_subclasses(uri);
179         
180         for (i = 0; ulist && i < ulist->count; i++) {
181                 insert_class(new LADSPA_Class(ulist->items[i]));
182         }
183
184         lrdf_free_uris(ulist);
185
186         /* Finding instances... */
187         ulist=lrdf_get_instances(uri);
188         
189         for (i = 0; ulist && i < ulist->count; i++) {
190                 registered_ids.push_back(lrdf_get_uid(ulist->items[i]));
191         }
192
193         lrdf_free_uris(ulist);
194 #endif  
195 }
196
197 LADSPA_Class :: LADSPA_Class() : label("Unclassified"), accept_all(true) {
198 }
199
200 bool LADSPA_Class :: add_plugin(LADSPA_Plugin *plugin) {
201         return root->add_plugin_instance(plugin);
202 }
203
204 bool LADSPA_Class :: add_plugin_instance(LADSPA_Plugin *plugin) {
205         if (accept_all) {
206                 insert_plugin(plugin);
207                 return true;
208         }
209         
210         long id=plugin->getUniqueID();
211         std::list <long> :: iterator i;
212         
213         /* Is this plugin an instance of this class? */
214         
215         for (i=registered_ids.begin(); i!=registered_ids.end(); i++) {
216                 if ((*i)==id) {
217                         /* The plugin belongs to this class... */
218                         insert_plugin(plugin);
219                         return true;
220                 }
221         }
222         
223         /* Try to insert the plugin in subclasses */
224         std::list <LADSPA_Class *> :: iterator cls;
225         
226         for (cls=subclasses.begin(); cls!=subclasses.end(); cls++) {
227                 LADSPA_Class *lrdf_class=(*cls);
228                 
229                 if (lrdf_class->add_plugin_instance(plugin)) return true;
230         }
231         
232         /* Giving up... */
233         
234         return false;
235 }
236
237 void LADSPA_Class::insert_plugin(LADSPA_Plugin *plugin) {
238         std::list <LADSPA_Plugin *> :: iterator i;
239         
240         for (i=plugins.begin(); i!=plugins.end(); i++) {
241                 LADSPA_Plugin *a_plug=(*i);
242                 int res=compare(plugin->getName(), a_plug->getName());
243                 
244                 if (res < 2) {
245                         plugins.insert(i, plugin);
246                         return;
247                 }
248         }
249         
250         plugins.push_back(plugin);
251 }
252
253 void LADSPA_Class::list(char *buffer) {
254         strcat(buffer, "\t");
255         
256         printf("%s class %s {\n", buffer, label);
257
258         std::list <LADSPA_Plugin *> :: iterator i;      
259         
260         for (i=plugins.begin(); i!=plugins.end(); i++) {
261                 printf("%s - plugin: %s\n", buffer, (*i)->getName());
262         }
263         
264         std::list <LADSPA_Class *> :: iterator c;
265         
266         for (c=subclasses.begin(); c!=subclasses.end(); c++) (*c)->list(buffer);
267         
268         printf("%s}\n", buffer);
269         
270         buffer[strlen(buffer)-1]=0;
271 }
272
273 void LADSPA_Class::dump() {
274         char buffer[256]="";
275         root->list(buffer);
276 }
277
278 static void menu_callback(GtkWidget *wid, LADSPA_Plugin *plugin) {
279         vtt_class *vtt=LADSPA_Class::get_current_vtt();
280         
281         if (vtt) {
282                 vtt->add_effect(plugin);
283         } else {
284                 tX_error("LADSPA_Class::menu_callback() no vtt");
285         }
286 }
287
288
289 GtkWidget * LADSPA_Class :: get_menu() {
290         std::list <LADSPA_Class *> :: iterator cls;
291         GtkWidget *menu=gtk_menu_new();
292         GtkWidget *item;
293         
294         for (cls=subclasses.begin(); cls!=subclasses.end(); cls++) {
295                 LADSPA_Class *c=(*cls);
296                 
297                 if (c->plugins.size() || c->subclasses.size()) {
298                         item=gtk_menu_item_new_with_label(c->label);
299                         GtkWidget *submenu=c->get_menu();
300                         gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
301                         gtk_menu_append(menu, item);
302                         gtk_widget_show(item);
303                 }
304         }
305         
306         if (subclasses.size() && plugins.size()) {
307                 item = gtk_menu_item_new();
308                 gtk_menu_append(menu, item);
309                 gtk_widget_set_sensitive (item, FALSE);
310                 gtk_widget_show (item);
311         }
312         
313         std::list <LADSPA_Plugin *> :: iterator plugin;
314         
315         for (plugin=plugins.begin(); plugin != plugins.end(); plugin++) {
316                 char buffer[512];
317                 LADSPA_Plugin *p=(*plugin);
318                 
319                 sprintf(buffer, "%s - (%s, %i)", p->getName(), p->getLabel(), p->getUniqueID());
320                 item=gtk_menu_item_new_with_label(buffer);
321                 gtk_menu_append(menu, item);
322                 gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(menu_callback), p);            
323                 gtk_widget_show(item);
324         }
325         
326         return menu;
327 }
328
329 GtkWidget * LADSPA_Class :: get_ladspa_menu() {
330         return root->get_menu();
331 }