1 /*
2  * Copyright (C) 2004 2005 2007 2008 2011, 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 
22 #include <config.h>
23 
24 #include <math.h>
25 #include "inifile.h"
26 #include "ladspadialog.h"
27 #include "effectbrowser.h"
28 #include "int_box.h"
29 #include "float_box.h"
30 #include "um.h"
31 #include "combo.h"
32 #include "gettext.h"
33 
34 static gchar *first_effect = NULL;
35 
ladspa_dialog_first_effect(void)36 gchar *ladspa_dialog_first_effect(void)
37 {
38      return first_effect;
39 }
40 
41 #if defined(HAVE_LADSPA)
42 
43 GtkObjectClass *parent_class;
44 
ladspa_dialog_apply(EffectDialog * ed)45 gboolean ladspa_dialog_apply(EffectDialog *ed)
46 {
47      LadspaDialog *ld = LADSPA_DIALOG(ed);
48      guint i,j,k;
49      Intbox *ib;
50      Floatbox *fb;
51      GtkToggleButton *tb;
52      gchar *c,*d;
53      gboolean output_mapped[8] = { 0 };
54      gboolean res,is_tb;
55      float f,l,u;
56      Document *doc = EFFECT_BROWSER(ed->eb)->dl->selected;
57      Chunk *chunk = doc->chunk;
58      LADSPA_PortRangeHintDescriptor prhd;
59 
60      for (i=0; i<ld->effect->numports[0]; i++) {
61 	  is_tb = FALSE;
62 	  if (IS_INTBOX(ld->settings[0][i])) {
63 	       ib = INTBOX(ld->settings[0][i]);
64 	       if (intbox_check(ib)) return TRUE;
65 	       f = (float)ib->val;
66 	  } else if (IS_FLOATBOX(ld->settings[0][i])) {
67 	       fb = FLOATBOX(ld->settings[0][i]);
68 	       if (floatbox_check(fb)) return TRUE;
69 	       f = fb->val;
70 	  } else {
71 	       /* Must be a togglebutton */
72 	       tb = GTK_TOGGLE_BUTTON(ld->settings[0][i]);
73 	       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb)))
74 		    f = 1.0;
75 	       else
76 		    f = 0.0;
77 	       is_tb = TRUE;
78 	  }
79 	  prhd = ld->effect->ports[0][i].prh.HintDescriptor;
80 	  l = ld->effect->ports[0][i].prh.LowerBound;
81 	  u = ld->effect->ports[0][i].prh.UpperBound;
82 	  if (LADSPA_IS_HINT_SAMPLE_RATE(prhd)) {
83 	       l *= (gfloat)chunk->format.samplerate;
84 	       u *= (gfloat)chunk->format.samplerate;
85 	  }
86 	  if (LADSPA_IS_HINT_BOUNDED_BELOW(prhd) && f < l) {
87 	       c = g_strdup_printf(_("Value for '%s' must not be below %f"),
88 				   ld->effect->ports[0][i].name,l);
89 	       user_error(c);
90 	       g_free(c);
91 	       return TRUE;
92 	  }
93 	  if (LADSPA_IS_HINT_BOUNDED_ABOVE(prhd) && f > u) {
94 	       c = g_strdup_printf(_("Value for '%s' must not be above %f"),
95 				   ld->effect->ports[0][i].name,
96 				   u);
97 	       user_error(c);
98 	       g_free(c);
99 	       return TRUE;
100 	  }
101 	  c = g_strdup_printf("ladspa_%s_defaultControl%d",ld->effect->id,i);
102 	  if (is_tb) inifile_set_gboolean(c, f != 0.0);
103 	  else inifile_set_gfloat(c, f);
104 	  ld->effect->ports[0][i].value = f;
105      }
106 
107      for (j=2; j<4; j++)
108 	  for (i=0; i<ld->effect->numports[j]; i++) {
109 
110 	       k = combo_selected_index(COMBO(ld->settings[j][i]));
111 
112 	       d = g_strdup_printf("ladspa_%s_default%s%d",ld->effect->id,
113 				   (j==2)?"Input":"Output",i);
114 	       if (k >= ld->channels) {
115 		    ld->effect->ports[j][i].map = -1;
116 		    ld->effect->ports[j][i].value = 0.0;
117 		    inifile_set_gint32(d,-1);
118 		    g_free(d);
119 		    continue;
120 	       }
121 	       g_assert(ld->channels == chunk->format.channels);
122 	       g_assert(k < ld->channels);
123 	       if (j==3){
124 		    if (output_mapped[k]) {
125 			 g_free(d);
126 			 d = g_strdup_printf
127 			      (_("You have mapped more than one "
128 			       "output port to channel '%s'. You "
129 			       "can only map one output port to "
130 			       "each channel."),channel_name(k,ld->channels));
131 			 user_error(d);
132 			 g_free(d);
133 			 return TRUE;
134 		    } else output_mapped[k] = TRUE;
135 	       }
136 	       ld->effect->ports[j][i].map = k;
137 	       inifile_set_guint32(d,k);
138 	       g_free(d);
139 	  }
140 
141      ld->effect->keep = gtk_toggle_button_get_active(ld->keep);
142      c = g_strdup_printf("ladspa_%s_defaultKeep",ld->effect->id);
143      inifile_set_gboolean(c,ld->effect->keep);
144      g_free(c);
145 
146      res = document_apply_cb(doc,
147 			     (document_apply_proc)ladspa_run_effect,
148 			     TRUE,ld->effect);
149      if (res) return TRUE;
150 
151      for (i=0; i<ld->effect->numports[1]; i++) {
152 	  c = g_strdup_printf("%f",ld->effect->ports[1][i].value);
153 	  gtk_label_set_text(GTK_LABEL(ld->settings[1][i]), c);
154 	  g_free(c);
155      }
156 
157      return FALSE;
158 }
159 
ladspa_dialog_target_changed(EffectDialog * ed)160 static void ladspa_dialog_target_changed(EffectDialog *ed)
161 {
162      LadspaDialog *ld = LADSPA_DIALOG(ed);
163      EffectBrowser *eb = EFFECT_BROWSER(ed->eb);
164      /* puts("ladspa_dialog_target_changed");      */
165      if (ld->channels != eb->dl->format.channels)
166 	  effect_browser_invalidate_effect(eb,ld->effect->id,'L');
167 }
168 
ladspa_dialog_setup(EffectDialog * ed)169 void ladspa_dialog_setup(EffectDialog *ed)
170 {
171      LadspaDialog *ld = LADSPA_DIALOG(ed);
172      LadspaEffect *eff;
173      GtkWidget *a,*b,*c,*d,*e,*x;
174      guint i,k,n,q;
175      gint j;
176      float f,u,l;
177      GList *li;
178      gchar *ch;
179      gboolean bo,want_scale;
180      Dataformat *format = &(EFFECT_BROWSER(ed->eb)->dl->format);
181      LADSPA_PortRangeHintDescriptor prhd;
182 
183      /* puts("ladspa_dialog_setup"); */
184      ld->effect = eff = ladspa_find_effect(ed->effect_name);
185      g_assert(eff != NULL);
186      a = gtk_table_new(8,2,FALSE);
187      gtk_container_add(ed->input_area, a);
188      b = gtk_label_new(eff->name);
189      gtk_table_attach(GTK_TABLE(a),b,0,2,0,1,GTK_FILL|GTK_SHRINK,0,0,0);
190      gtk_misc_set_alignment(GTK_MISC(b),0.0,0.5);
191      ch = g_strdup_printf(_("Author: %s"),eff->maker);
192      b = gtk_label_new(ch);
193      g_free(ch);
194      gtk_table_attach(GTK_TABLE(a),b,0,2,1,2,GTK_FILL|GTK_SHRINK,0,0,0);
195      gtk_misc_set_alignment(GTK_MISC(b),0.0,0.5);
196      ch = g_strdup_printf(_("Copyright: %s"),eff->copyright);
197      b = gtk_label_new(ch);
198      g_free(ch);
199      gtk_table_attach(GTK_TABLE(a),b,0,2,2,3,GTK_FILL|GTK_SHRINK,0,0,0);
200      gtk_misc_set_alignment(GTK_MISC(b),0.0,0.5);
201      if (eff->numports[0] > 0) {
202 	  ld->settings[0] = g_malloc(eff->numports[0] * sizeof(GtkWidget *));
203 	  b = gtk_frame_new(_(" Input controls "));
204 	  gtk_table_attach(GTK_TABLE(a),b,0,1,3,4,GTK_FILL,0,0,8);
205 	  c = gtk_vbox_new(FALSE,3);
206 	  gtk_container_add(GTK_CONTAINER(b),c);
207 	  gtk_container_set_border_width(GTK_CONTAINER(c),4);
208 	  for (i=0; i<eff->numports[0]; i++) {
209 	       prhd = eff->ports[0][i].prh.HintDescriptor;
210 	       ch = g_strdup_printf("ladspa_%s_defaultControl%d",eff->id,i);
211 	       if (LADSPA_IS_HINT_TOGGLED(prhd)) {
212 		    d=gtk_check_button_new_with_label(eff->ports[0][i].name);
213 		    bo = LADSPA_IS_HINT_DEFAULT_1(prhd);
214 		    bo = inifile_get_gboolean(ch,bo);
215 		    gtk_toggle_button_set_active
216 			 (GTK_TOGGLE_BUTTON(d),
217 			  LADSPA_IS_HINT_DEFAULT_1(prhd));
218 		    gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
219 		    ld->settings[0][i] = d;
220 	       } else {
221 		    d = gtk_hbox_new(FALSE,3);
222 		    gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
223 		    e = gtk_label_new(eff->ports[0][i].name);
224 		    gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
225 
226 		    u = eff->ports[0][i].prh.UpperBound;
227 		    l = eff->ports[0][i].prh.LowerBound;
228 		    if (LADSPA_IS_HINT_SAMPLE_RATE(prhd)) {
229 			 u *= format->samplerate;
230 			 l *= format->samplerate;
231 		    }
232 
233 		    if (LADSPA_IS_HINT_DEFAULT_MINIMUM(prhd)) f=l;
234 		    else if (LADSPA_IS_HINT_DEFAULT_LOW(prhd)) {
235 			 if (LADSPA_IS_HINT_LOGARITHMIC(prhd))
236 			      f = exp(log(l)*0.75+log(u)*0.25);
237 			 else
238 			      f = l*0.75 + u*0.25;
239 		    } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(prhd)) {
240 			 if (LADSPA_IS_HINT_LOGARITHMIC(prhd))
241 			      f = exp(log(l)*0.5 + log(u)*0.5);
242 			 else
243 			      f = l*0.5 + u*0.5;
244 		    } else if (LADSPA_IS_HINT_DEFAULT_HIGH(prhd)) {
245 			 if (LADSPA_IS_HINT_LOGARITHMIC(prhd))
246 			      f = exp(log(l)*0.25+log(u)*0.75);
247 			 else
248 			      f = l*0.25 + u*0.75;
249 		    } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(prhd)) f=u;
250 		    else if (LADSPA_IS_HINT_DEFAULT_0(prhd)) f=0.0;
251 		    else if (LADSPA_IS_HINT_DEFAULT_1(prhd)) f=1.0;
252 		    else if (LADSPA_IS_HINT_DEFAULT_100(prhd)) f=100.0;
253 		    else if (LADSPA_IS_HINT_DEFAULT_440(prhd)) f=440.0;
254 		    else if (LADSPA_IS_HINT_BOUNDED_BELOW(prhd)) f=l;
255 		    else if (LADSPA_IS_HINT_BOUNDED_ABOVE(prhd)) f=u;
256 		    else f=0.0;
257 		    f = inifile_get_gfloat(ch,f);
258 
259 		    want_scale = (LADSPA_IS_HINT_BOUNDED_BELOW(prhd) &&
260 				  LADSPA_IS_HINT_BOUNDED_ABOVE(prhd));
261 
262 		    if (LADSPA_IS_HINT_INTEGER(prhd)) {
263 			 e = intbox_new((long)f);
264 			 if (want_scale) {
265 			      x = intbox_create_scale(INTBOX(e),(long)l,
266 						      (long)u);
267 			      gtk_box_pack_end(GTK_BOX(d),x,FALSE,FALSE,0);
268 			      gtk_widget_set_can_focus(x,FALSE);
269 			 }
270 		    } else {
271 			 e = floatbox_new(f);
272 			 if (want_scale) {
273 			      x = floatbox_create_scale(FLOATBOX(e),l,u);
274 			      gtk_box_pack_end(GTK_BOX(d),x,FALSE,FALSE,0);
275 			      gtk_widget_set_can_focus(x,FALSE);
276 			 }
277 		    }
278 
279 		    ld->settings[0][i] = e;
280 
281 		    gtk_box_pack_end(GTK_BOX(d),e,FALSE,FALSE,0);
282 	       }
283 	       g_free(ch);
284 	  }
285      } else ld->settings[0] = NULL;
286 
287      k = format->channels;
288      ld->channels = k;
289 
290      if (eff->numports[1] > 0) {
291 	  ld->settings[1] = g_malloc(eff->numports[1] * sizeof(GtkWidget *));
292 	  b = gtk_frame_new(_(" Output controls "));
293 	  gtk_table_attach(GTK_TABLE(a),b,0,1,4,5,GTK_FILL,0,0,8);
294 	  c = gtk_vbox_new(FALSE,3);
295 	  gtk_container_add(GTK_CONTAINER(b),c);
296 	  gtk_container_set_border_width(GTK_CONTAINER(c),4);
297 	  for (i=0; i<eff->numports[1]; i++) {
298 	       d = gtk_hbox_new(FALSE,3);
299 	       gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
300 	       e = gtk_label_new(eff->ports[1][i].name);
301 	       gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
302 	       e = gtk_label_new("--");
303 	       ld->settings[1][i] = e;
304 	       gtk_box_pack_end(GTK_BOX(d),e,FALSE,FALSE,0);
305 	  }
306      } else ld->settings[1] = NULL;
307 
308      li = NULL;
309      for (j=0; j<k; j++)
310 	  li = g_list_append(li,g_strdup(channel_name(j,k)));
311      li = g_list_append(li,g_strdup(_("None")));
312 
313      for (n=0; n<2; n++) {
314 	  if (eff->numports[n+2] == 0) {
315 	       ld->settings[n+2] = NULL;
316 	       continue;
317 	  }
318 	  ld->settings[n+2] = g_malloc(eff->numports[n+2]*sizeof(GtkWidget *));
319 	  b = gtk_frame_new(n==0 ? _(" Input audio ") : _(" Output audio "));
320 	  gtk_table_attach(GTK_TABLE(a),b,0,1,5+n,6+n,GTK_FILL,0,0,8);
321 	  c = gtk_vbox_new(FALSE,3);
322 	  gtk_container_add(GTK_CONTAINER(b),c);
323 	  gtk_container_set_border_width(GTK_CONTAINER(c),4);
324 	  for (i=0; i<eff->numports[n+2]; i++) {
325 	       d = gtk_hbox_new(FALSE,3);
326 	       gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
327 	       e = gtk_label_new(eff->ports[n+2][i].name);
328 	       gtk_box_pack_start(GTK_BOX(d),e,FALSE,FALSE,0);
329 	       e = combo_new();
330 	       ld->settings[n+2][i] = e;
331 	       gtk_box_pack_end(GTK_BOX(d),e,FALSE,FALSE,0);
332 	       ch = g_strdup_printf("ladspa_%s_default%s%d",eff->id,
333 				    (n==0)?"Input":"Output",i);
334 
335 	       q = (i < k) ? i : k;
336 	       j = inifile_get_gint32(ch,q);
337 	       g_free(ch);
338 	       if (j <= -1)
339 		    j = k;
340 	       else if (j >= k) {
341 		    j = q;
342 	       }
343 	       combo_set_items(COMBO(e),li,j);
344 	  }
345      }
346 
347      g_list_foreach(li,(GFunc)g_free,NULL);
348      g_list_free(li);
349 
350      b = gtk_check_button_new_with_label(_("Keep data in unmapped output "
351 					 "channels"));
352      gtk_table_attach(GTK_TABLE(a),b,0,2,7,8,GTK_FILL,0,0,0);
353      ch = g_strdup_printf("ladspa_%s_defaultKeep",ld->effect->id);
354      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b),
355 				  inifile_get_gboolean(ch,TRUE));
356      g_free(ch);
357      ld->keep = GTK_TOGGLE_BUTTON(b);
358 
359      gtk_widget_show_all(a);
360 }
361 
ladspa_dialog_destroy(GtkObject * obj)362 static void ladspa_dialog_destroy(GtkObject *obj)
363 {
364      LadspaDialog *ld = LADSPA_DIALOG(obj);
365      /* puts("ladspa_dialog_destroy"); */
366      guint i;
367      for (i=0; i<4; i++) {
368 	  g_free(ld->settings[i]);
369 	  ld->settings[i] = NULL;
370      }
371      parent_class->destroy(obj);
372 }
373 
ladspa_dialog_class_init(GtkObjectClass * klass)374 void ladspa_dialog_class_init(GtkObjectClass *klass)
375 {
376      parent_class = gtk_type_class(effect_dialog_get_type());
377      EFFECT_DIALOG_CLASS(klass)->apply = ladspa_dialog_apply;
378      EFFECT_DIALOG_CLASS(klass)->setup = ladspa_dialog_setup;
379      EFFECT_DIALOG_CLASS(klass)->target_changed = ladspa_dialog_target_changed;
380      klass->destroy = ladspa_dialog_destroy;
381 }
382 
ladspa_dialog_init(GtkObject * obj)383 void ladspa_dialog_init(GtkObject *obj)
384 {
385      /* Wait with initialisation until the setup signal */
386 }
387 
ladspa_dialog_get_type(void)388 GtkType ladspa_dialog_get_type(void)
389 {
390      static GtkType id=0;
391      if (!id) {
392 	  GtkTypeInfo info = {
393 	       "LadspaDialog",
394 	       sizeof(LadspaDialog),
395 	       sizeof(LadspaDialogClass),
396 	       (GtkClassInitFunc)ladspa_dialog_class_init,
397 	       (GtkObjectInitFunc)ladspa_dialog_init
398 	  };
399 	  id = gtk_type_unique(effect_dialog_get_type(),&info);
400      }
401      return id;
402 }
403 
register_func(LadspaEffect * eff)404 static void register_func(LadspaEffect *eff)
405 {
406      effect_register_add_effect('L', eff->id, eff->name, eff->maker,
407 				eff->filename);
408      if (first_effect == NULL) first_effect = eff->id;
409 }
410 
ladspa_dialog_rebuild(gchar source_tag,gpointer user_data)411 static void ladspa_dialog_rebuild(gchar source_tag, gpointer user_data)
412 {
413      ladspa_rescan();
414      ladspa_foreach_effect(register_func);
415 }
416 
ladspa_dialog_get(gchar * name,gchar source_tag,gpointer user_data)417 static EffectDialog *ladspa_dialog_get(gchar *name, gchar source_tag,
418 				       gpointer user_data)
419 {
420      if (ladspa_find_effect(name) == NULL) return NULL;
421      return EFFECT_DIALOG(gtk_type_new(ladspa_dialog_get_type()));
422 }
423 
ladspa_dialog_register(void)424 void ladspa_dialog_register(void)
425 {
426      effect_register_add_source("LADSPA Plugin",'L',ladspa_dialog_rebuild,
427 				NULL,ladspa_dialog_get,NULL);
428 }
429 
430 #else /* matches #if defined(HAVE_LADSPA) */
431 
ladspa_dialog_register(void)432 void ladspa_dialog_register(void)
433 {
434 }
435 
436 #endif /* defined(HAVE_LADSPA) */
437