1 /*
2  * Copyright (C) 2004 2005 2007, Magnus Hjorth
3  *
4  * This file is part of mhWaveEdit.
5  *
6  * mhWaveEdit is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * mhWaveEdit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with mhWaveEdit; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <config.h>
22 
23 #ifdef HAVE_LADSPA
24 
25 #include <dlfcn.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <errno.h>
29 #include <locale.h>
30 #include "um.h"
31 #include "ladspacore.h"
32 #include "gettext.h"
33 
34 static GHashTable *effect_list;
35 
descriptor_to_index(LADSPA_PortDescriptor pdesc)36 static int descriptor_to_index(LADSPA_PortDescriptor pdesc)
37 {
38      int j;
39      if ((pdesc & LADSPA_PORT_INPUT) != 0) j=0;
40      else if ((pdesc & LADSPA_PORT_OUTPUT) != 0) j=1;
41      else return -1;
42      if ((pdesc & LADSPA_PORT_CONTROL) != 0) return j;
43      else if ((pdesc & LADSPA_PORT_AUDIO) != 0) return j+2;
44      else return -1;
45 }
46 
scan_file(gchar * filename,gchar * basename,gboolean do_check)47 static void scan_file(gchar *filename, gchar *basename, gboolean do_check)
48 {
49      void *p;
50      LADSPA_Descriptor_Function func;
51      gchar *msg,*c;
52      gint i,j;
53      int k[4];
54      unsigned long l;
55      const LADSPA_Descriptor *desc;
56      LadspaEffect *eff;
57 
58      p = dlopen(filename,RTLD_NOW);
59      if (p == NULL) {
60 	  console_message(dlerror());
61 	  return;
62      }
63      func = dlsym(p,"ladspa_descriptor");
64      if (func == NULL) {
65 	  msg = g_strdup_printf("%s: ladspa_descriptor: %s",
66 				basename,dlerror());
67 	  console_message(msg);
68 	  g_free(msg);
69 	  dlclose(p);
70 	  return;
71      }
72      i=0;
73      while (1) {
74      outer:
75 	  desc = func(i);
76 	  if (desc == NULL) break;
77 	  c = g_strdup_printf("%ld_%s",(long int)desc->UniqueID,basename);
78 	  if (do_check &&
79 	      g_hash_table_lookup(effect_list,c) != NULL) {
80 	       g_free(c);
81 	       i++;
82 	       continue;
83 	  }
84 	  eff = g_malloc0(sizeof(*eff));
85 	  eff->id = c;
86 	  eff->filename = g_strdup(filename);
87 	  eff->effect_number = i++;
88 	  eff->name = g_strdup(desc->Name);
89 	  eff->maker = g_strdup(desc->Maker);
90 	  eff->copyright = g_strdup(desc->Copyright);
91 	  for (l=0; l<desc->PortCount; l++) {
92 	       j = descriptor_to_index(desc->PortDescriptors[l]);
93 	       if (j < 0) {
94 		    msg = g_strdup_printf(_("Effect %s contains "
95 					    "invalid port %s"),eff->name,
96 					  desc->PortNames[l]);
97 		    console_message(msg);
98 		    g_free(msg);
99 		    g_free(eff->id);
100 		    g_free(eff->filename);
101 		    g_free(eff->name);
102 		    g_free(eff->maker);
103 		    g_free(eff->copyright);
104 		    g_free(eff);
105 		    goto outer;
106 	       }
107 	       eff->numports[j]++;
108 	  }
109 	  for (j=0; j<4; j++)
110 	       if (eff->numports[j] > 0)
111 		    eff->ports[j] = g_malloc(eff->numports[j] *
112 					     sizeof(LadspaPort));
113 	  k[0] = k[1] = k[2] = k[3] = 0;
114 	  for (l=0; l<desc->PortCount; l++) {
115 	       j = descriptor_to_index(desc->PortDescriptors[l]);
116 	       if (j < 0) continue;
117 	       eff->ports[j][k[j]].number = l;
118 	       eff->ports[j][k[j]].name = g_strdup(desc->PortNames[l]);
119 	       memcpy(&(eff->ports[j][k[j]].prh),
120 		      &(desc->PortRangeHints[l]),
121 		      sizeof(LADSPA_PortRangeHint));
122 	       k[j] ++;
123 	  }
124 	  g_hash_table_insert(effect_list,eff->id,eff);
125      }
126      dlclose(p);
127 }
128 
scan_directory(gchar * dir,gpointer dummy)129 static void scan_directory(gchar *dir, gpointer dummy)
130 {
131      DIR *d;
132      struct dirent *de;
133      int i;
134      gchar *fn,*msg;
135      char *cur_lc_numeric;
136 
137      d = opendir(dir);
138      if (d == NULL) {
139 	  if (errno != ENOENT) {
140 	       msg = g_strdup_printf(_("Ladspa: Error scanning %s"),dir);
141 	       console_perror(msg);
142 	       g_free(msg);
143 	  }
144 	  return;
145      }
146 
147      /* Some LADSPA plugins resets LC_NUMERIC setting,
148       * so we need to save it. */
149      cur_lc_numeric = setlocale(LC_NUMERIC, NULL);
150 
151      while (1) {
152 	  de = readdir(d);
153 	  if (de == NULL) break;
154 	  i = strlen(de->d_name);
155 	  if (i<4 || strcmp(de->d_name + i-3, ".so")) continue;
156 	  fn = g_strdup_printf("%s/%s",dir,de->d_name);
157 
158 	  scan_file(fn,de->d_name,FALSE);
159 
160 	  g_free(fn);
161      }
162      closedir(d);
163 
164      /* Restore LC_NUMERIC setting. */
165      setlocale(LC_NUMERIC, cur_lc_numeric);
166 }
167 
ladspa_cleanup_func(gpointer key,gpointer value,gpointer user_data)168 static gboolean ladspa_cleanup_func(gpointer key, gpointer value,
169 				    gpointer user_data)
170 {
171      int i,j;
172      LadspaEffect *eff;
173      eff = (LadspaEffect *)value;
174      g_free(eff->id);
175      g_free(eff->name);
176      g_free(eff->filename);
177      g_free(eff->maker);
178      g_free(eff->copyright);
179 
180      for (i=0; i<4; i++) {
181 	  for (j=0; j<eff->numports[i]; j++)
182 	       g_free(eff->ports[i][j].name);
183 	  g_free(eff->ports[i]);
184      }
185 
186      g_free(eff);
187      /* eff->id == value, so no need to free value again */
188      return TRUE;
189 }
190 
ladspa_cleanup(void)191 static void ladspa_cleanup(void)
192 {
193      if (effect_list == NULL) return;
194      g_hash_table_foreach_remove(effect_list, ladspa_cleanup_func, NULL);
195      g_hash_table_destroy(effect_list);
196      effect_list = NULL;
197 }
198 
ladspa_path_foreach(void (* function)(gchar * dirname,gpointer user_data),gpointer user_data)199 static void ladspa_path_foreach(void (*function)(gchar *dirname,
200 						 gpointer user_data),
201 				gpointer user_data)
202 {
203      gchar *p,*c;
204 
205      p = getenv("LADSPA_PATH");
206      if (p == NULL) {
207 	  p = DEFAULT_LADSPA_PATH;
208 	  /* console_message(_("Environment variable LADSPA_PATH not set.\n"
209 	     "LADSPA support is disabled."));
210 	     return; */
211      }
212      p = g_strdup(p);
213      c = strtok(p,":");
214      while (c != NULL) {
215 	  function(c,user_data);
216 	  c = strtok(NULL,":");
217      }
218      free(p);
219 
220 }
221 
ladspa_rescan(void)222 void ladspa_rescan(void)
223 {
224      ladspa_cleanup();
225      effect_list = g_hash_table_new(g_str_hash,g_str_equal);
226 
227      ladspa_path_foreach(scan_directory,NULL);
228 }
229 
foreach_func(gpointer key,gpointer value,gpointer user_data)230 static void foreach_func(gpointer key, gpointer value, gpointer user_data)
231 {
232      void (*func)(void *) = (void (*)(void *))user_data;
233      func(value);
234 }
235 
ladspa_foreach_effect(void (* func)(LadspaEffect * eff))236 void ladspa_foreach_effect(void (*func)(LadspaEffect *eff))
237 {
238      g_hash_table_foreach(effect_list,foreach_func,func);
239 }
240 
find_effect_func(gchar * dirname,gpointer user_data)241 void find_effect_func(gchar *dirname, gpointer user_data)
242 {
243      gchar *fn = (gchar *)user_data;
244      gchar *c;
245      c = g_strdup_printf("%s/%s",dirname,fn);
246      if (file_exists(c))
247 	  scan_file(c,fn,TRUE);
248      g_free(c);
249 }
250 
ladspa_find_effect(gchar * id)251 LadspaEffect *ladspa_find_effect(gchar *id)
252 {
253      LadspaEffect *eff;
254      gchar *c,*d,*e;
255      unsigned long unid;
256 
257      if (effect_list == NULL)
258 	  effect_list = g_hash_table_new(g_str_hash,g_str_equal);
259      eff = (LadspaEffect *)g_hash_table_lookup(effect_list,id);
260      if (eff != NULL) return eff;
261 
262      /* Parse the ID to get uniqueID and filename */
263      c = g_strdup(id);
264      d = strchr(c,'_');
265      if (d == NULL) {
266 	  g_free(c);
267 	  return NULL;
268      }
269      *d = 0;
270      d++;
271      /* c should now be UniqueID, d filename. g_free(c) frees both c & d */
272      unid = strtoul(c,&e,10);
273      if (*e != 0) {
274 	  g_free(c);
275 	  return NULL;
276      }
277 
278      /* Search for the file and add it's effects if found */
279      ladspa_path_foreach(find_effect_func,d);
280      g_free(c);
281 
282      /* Try again */
283      eff = (LadspaEffect *)g_hash_table_lookup(effect_list,id);
284 
285      return eff;
286 
287 }
288 
289 static LadspaEffect *processing_effect;
290 static const LADSPA_Descriptor *processing_desc;
291 static LADSPA_Handle processing_handle;
292 static sample_t *processing_outbuf;
293 
ladspa_filter_proc(void * in,guint sample_size,chunk_writeout_func out_func,WriteoutID id,Dataformat * format)294 static gboolean ladspa_filter_proc(void *in, guint sample_size,
295 				   chunk_writeout_func out_func, WriteoutID id,
296 				   Dataformat *format)
297 {
298      sample_t *s = (sample_t *)in;
299      guint chans = format->channels;
300      guint frames = sample_size / (sizeof(sample_t)*chans);
301      guint i,j,k,m;
302      int l;
303      float *b;
304      for (i=0; i<frames; i+=j) {
305 	  j = MIN(frames-i, 1024);
306 	  /* Set input */
307 	  for (k=0; k < processing_effect->numports[2]; k++) {
308 	       l = processing_effect->ports[2][k].map;
309 	       if (l < 0) continue;
310 	       b = processing_effect->ports[2][k].buffer;
311 #ifndef USE_DOUBLE_SAMPLES
312 	       if (chans == 1) {
313 		    memcpy(b,&s[i],j*sizeof(float));
314 		    continue;
315 	       }
316 #endif
317 	       for (m=0; m<j; m++)
318 		    b[m] = (float) s[chans*(i+m) + l];
319 	  }
320 	  /* Run plugin */
321 	  processing_desc->run(processing_handle,j);
322 	  /* Get output */
323 	  /* Copy the input to use as default (a little inefficient,
324 	     I know..) */
325 	  if (processing_effect->keep)
326 	       memcpy(processing_outbuf,&s[i],j*chans*sizeof(sample_t));
327 	  else
328 	       memset(processing_outbuf,0,j*chans*sizeof(sample_t));
329 	  for (k=0; k < processing_effect->numports[3]; k++) {
330 	       l = processing_effect->ports[3][k].map;
331 	       if (l < 0) continue;
332 	       b = processing_effect->ports[3][k].buffer;
333 #ifndef USE_DOUBLE_SAMPLES
334 	       if (chans == 1) {
335 		    memcpy(processing_outbuf,b,j*sizeof(float));
336 		    continue;
337 	       }
338 #endif
339 	       for (m=0; m<j; m++)
340 		    processing_outbuf[chans*m + l] = b[m];
341 	  }
342 	  /* Write output */
343 	  if (out_func(id,processing_outbuf,j*chans*sizeof(sample_t)))
344 	       return TRUE;
345      }
346      return FALSE;
347 }
348 
ladspa_run_effect(Chunk * chunk,StatusBar * bar,LadspaEffect * eff,int dither_mode)349 Chunk *ladspa_run_effect(Chunk *chunk, StatusBar *bar, LadspaEffect *eff,
350 			 int dither_mode)
351 {
352      void *p;
353      gchar *c;
354      int i,j,k;
355      Chunk *r;
356      float f;
357      LADSPA_Descriptor_Function func;
358      const LADSPA_Descriptor *desc;
359      LADSPA_Handle hand;
360      char *cur_lc_numeric;
361 
362      /* Save LC_NUMERIC setting. */
363      cur_lc_numeric = setlocale(LC_NUMERIC, NULL);
364 
365      /* Open plugin */
366      p = dlopen(eff->filename,RTLD_LAZY);
367      if (p == NULL) {
368 	  user_error(dlerror());
369 	  return NULL;
370      }
371      func = dlsym(p,"ladspa_descriptor");
372      if (func == NULL) {
373 	  c = g_strdup_printf("%s: ladspa_descriptor: %s",eff->filename,
374 			      dlerror());
375 	  user_error(c);
376 	  g_free(c);
377 	  dlclose(p);
378 	  setlocale(LC_NUMERIC, cur_lc_numeric);
379 	  return NULL;
380      }
381      desc = func(eff->effect_number);
382      g_assert(desc != NULL);
383      hand = desc->instantiate(desc,chunk->format.samplerate);
384      /* Connect ports */
385      for (i=0; i<2; i++)
386 	  for (j=0; j<eff->numports[i]; j++) {
387 	       f = eff->ports[i][j].value;
388 	       desc->connect_port(hand,eff->ports[i][j].number,
389 				  &(eff->ports[i][j].value));
390 	       eff->ports[i][j].value = f;
391 	  }
392      for (i=2; i<4; i++)
393 	  for (j=0; j<eff->numports[i]; j++) {
394 	       eff->ports[i][j].buffer = g_malloc(1024*sizeof(float));
395 	       desc->connect_port(hand,eff->ports[i][j].number,
396 				  eff->ports[i][j].buffer);
397 	       if (i == 2 && eff->ports[i][j].map == -1)
398 		    for (k=0; k<1024; k++)
399 			 eff->ports[i][j].buffer[k] =
400 			      eff->ports[i][j].value;
401 	  }
402      /* Apply effect */
403      processing_effect = eff;
404      processing_desc = desc;
405      processing_handle = hand;
406      processing_outbuf = g_malloc(1024*chunk->format.channels*
407 				  sizeof(sample_t));
408      if (desc->activate != NULL) desc->activate(hand);
409      c = g_strdup_printf(_("Applying effect '%s'"),eff->name);
410      r = chunk_filter(chunk, ladspa_filter_proc, NULL, CHUNK_FILTER_MANY,
411 		      TRUE, dither_mode, bar, c);
412      g_free(c);
413      if (desc->deactivate != NULL) desc->deactivate(hand);
414      if (desc->cleanup != NULL) desc->cleanup(hand);
415      dlclose(p);
416      g_free(processing_outbuf);
417      for (i=2; i<4; i++)
418 	  for (j=0; j<eff->numports[i]; j++)
419 	       g_free(eff->ports[i][j].buffer);
420 
421      /* Restore LC_NUMERIC setting. */
422      setlocale(LC_NUMERIC, cur_lc_numeric);
423      return r;
424 }
425 
426 #endif /* HAVE_LADSPA */
427