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