1 /* -*- linux-c -*-
2 Copyright (C) 2004 Tom Szilagyi
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: plugin.c 1245 2012-02-04 10:33:30Z assworth $
19 */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <dlfcn.h>
27 #include <unistd.h>
28 #include <dirent.h>
29 #include <glib.h>
30 #include <glib-object.h>
31 #include <gdk/gdk.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <gtk/gtk.h>
34 #include <libxml/globals.h>
35 #include <libxml/parser.h>
36 #include <libxml/tree.h>
37 #include <ladspa.h>
38 #include <lrdf.h>
39
40 #include "common.h"
41 #include "utils_gui.h"
42 #include "i18n.h"
43 #include "options.h"
44 #include "trashlist.h"
45 #include "plugin.h"
46
47
48 extern options_t options;
49
50 extern volatile int plugin_lock;
51
52 extern int n_plugins;
53 extern plugin_instance * plugin_vect[MAX_PLUGINS];
54
55 extern LADSPA_Data * l_buf;
56 extern LADSPA_Data * r_buf;
57
58 extern unsigned long out_SR;
59
60 int fxbuilder_on;
61 GtkWidget * fxbuilder_window;
62 GtkWidget * avail_list;
63 GtkListStore * avail_store = NULL;
64 GtkTreeSelection * avail_select;
65 GtkWidget * running_list;
66 GtkListStore * running_store = NULL;
67 GtkTreeSelection * running_select;
68
69 GtkWidget * add_button;
70 GtkWidget * remove_button;
71 GtkWidget * conf_button;
72
73 GtkWidget * rp_menu;
74 GtkWidget * scrolled_win_running;
75
76 extern GtkWidget * plugin_toggle;
77
78 typedef struct {
79 plugin_instance * instance;
80 int index;
81 } optdata_t;
82
83 typedef struct {
84 plugin_instance * instance;
85 float start;
86 } btnpdata_t;
87
88 int added_plugin = 0;
89
90
91 void
set_active_state(void)92 set_active_state(void) {
93
94 GtkTreeIter iter;
95
96 if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(running_store), &iter, NULL, 0)) {
97 /* disable buttons and menu */
98 gtk_widget_set_sensitive(remove_button, FALSE);
99 gtk_widget_set_sensitive(conf_button, FALSE);
100 } else {
101 /* enable buttons and menu */
102 gtk_widget_set_sensitive(remove_button, TRUE);
103 gtk_widget_set_sensitive(conf_button, TRUE);
104 }
105
106 }
107
108 static int
rdf_filter(const struct dirent * de)109 rdf_filter(const struct dirent * de) {
110
111 if (de->d_type != DT_UNKNOWN && de->d_type != DT_REG && de->d_type != DT_LNK)
112 return 0;
113
114 if (de->d_name[0] == '.')
115 return 0;
116
117 return (((strlen(de->d_name) >= 4) && (strcmp(de->d_name + strlen(de->d_name) - 3, ".n3") == 0)) ||
118 ((strlen(de->d_name) >= 5) && (strcmp(de->d_name + strlen(de->d_name) - 4, ".rdf") == 0)) ||
119 ((strlen(de->d_name) >= 6) && (strcmp(de->d_name + strlen(de->d_name) - 5, ".rdfs") == 0)));
120 }
121
122 static int
so_filter(const struct dirent * de)123 so_filter(const struct dirent * de) {
124
125 if (de->d_type != DT_UNKNOWN && de->d_type != DT_REG && de->d_type != DT_LNK)
126 return 0;
127
128 if (de->d_name[0] == '.')
129 return 0;
130
131 return ((strlen(de->d_name) >= 4) && (strcmp(de->d_name + strlen(de->d_name) - 3, ".so") == 0));
132 }
133
134 void
parse_lrdf_data(void)135 parse_lrdf_data(void) {
136
137 char * str;
138 char lrdf_path[MAXLEN];
139 char rdf_path[MAXLEN];
140 char fileuri[MAXLEN];
141 int i, j = 0;
142 struct dirent ** de;
143 int n;
144
145 lrdf_path[0] = '\0';
146
147 if ((str = getenv("LADSPA_RDF_PATH"))) {
148 snprintf(lrdf_path, MAXLEN-1, "%s:", str);
149 } else {
150 strncat(lrdf_path, "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf:", MAXLEN-1);
151 }
152
153 for (i = 0; lrdf_path[i] != '\0'; i++) {
154 if (lrdf_path[i] == ':') {
155 rdf_path[j] = '\0';
156 j = 0;
157
158 n = scandir(rdf_path, &de, rdf_filter, alphasort);
159 if (n >= 0) {
160 int c;
161
162 for (c = 0; c < n; ++c) {
163 snprintf(fileuri, MAXLEN-1, "file://%s/%s", rdf_path, de[c]->d_name);
164 if (lrdf_read_file(fileuri)) {
165 fprintf(stderr,
166 "warning: could not parse RDF file: %s\n", fileuri);
167 }
168 free(de[c]);
169 }
170 free(de);
171 }
172 } else {
173 rdf_path[j++] = lrdf_path[i];
174 }
175 }
176 }
177
178
179 void
get_ladspa_category(unsigned long plugin_id,char * str)180 get_ladspa_category(unsigned long plugin_id, char * str) {
181
182 char buf[256];
183 lrdf_statement pattern;
184 lrdf_statement * matches1;
185 lrdf_statement * matches2;
186
187 snprintf(buf, 255, "%s%lu", LADSPA_BASE, plugin_id);
188 pattern.subject = buf;
189 pattern.predicate = RDF_TYPE;
190 pattern.object = 0;
191 pattern.object_type = lrdf_uri;
192
193 matches1 = lrdf_matches(&pattern);
194
195 if (!matches1) {
196 strncpy(str, "Unknown", MAXLEN-1);
197 return;
198 }
199
200 pattern.subject = matches1->object;
201 pattern.predicate = LADSPA_BASE "hasLabel";
202 pattern.object = 0;
203 pattern.object_type = lrdf_literal;
204
205 matches2 = lrdf_matches (&pattern);
206 lrdf_free_statements(matches1);
207
208 if (!matches2) {
209 strncpy(str, "Unknown", MAXLEN-1);
210 return;
211 }
212
213 strncpy(str, matches2->object, MAXLEN-1);
214 lrdf_free_statements(matches2);
215 }
216
217
218 static void
find_plugins(char * path_entry)219 find_plugins(char * path_entry) {
220
221 void * library = NULL;
222 char lib_name[MAXLEN];
223 LADSPA_Descriptor_Function descriptor_fn;
224 const LADSPA_Descriptor * descriptor;
225 struct dirent ** de;
226 int n, k, c;
227 long int port, n_ins, n_outs;
228 GtkTreeIter iter;
229 char id_str[32];
230 char n_ins_str[32];
231 char n_outs_str[32];
232 char c_str[32];
233 char category[MAXLEN];
234
235 n = scandir(path_entry, &de, so_filter, alphasort);
236 if (n >= 0) {
237 for (c = 0; c < n; ++c) {
238 snprintf(lib_name, MAXLEN-1, "%s/%s", path_entry, de[c]->d_name);
239 library = dlopen(lib_name, RTLD_LAZY);
240 if (library == NULL) {
241 free(de[c]);
242 continue;
243 }
244 descriptor_fn = dlsym(library, "ladspa_descriptor");
245 if (descriptor_fn == NULL) {
246 free(de[c]);
247 dlclose(library);
248 continue;
249 }
250
251 for (k = 0; ; ++k) {
252 descriptor = descriptor_fn(k);
253 if (descriptor == NULL) {
254 break;
255 }
256
257 for (n_ins = n_outs = port = 0; port < descriptor->PortCount; ++port) {
258 if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[port])) {
259 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port]))
260 ++n_ins;
261 if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[port]))
262 ++n_outs;
263 }
264 }
265
266 if ((n_ins == 1 && n_outs == 1) || (n_ins == 2 && n_outs == 2)) {
267
268 get_ladspa_category(descriptor->UniqueID, category);
269 snprintf(id_str, 31, "%ld", descriptor->UniqueID);
270 snprintf(n_ins_str, 31, "%ld", n_ins);
271 snprintf(n_outs_str, 31, "%ld", n_outs);
272 snprintf(c_str, 31, "%d", k);
273
274 gtk_list_store_append(avail_store, &iter);
275 gtk_list_store_set(avail_store, &iter, 0, id_str,
276 1, descriptor->Name, 2, category,
277 3, n_ins_str, 4, n_outs_str,
278 5, lib_name, 6, c_str, -1);
279 }
280 }
281 dlclose(library);
282 free(de[c]);
283 }
284 free(de);
285 }
286 }
287
288
289 static void
find_all_plugins(void)290 find_all_plugins(void) {
291
292 char * ladspa_path;
293 char * directory;
294
295 if (!(ladspa_path = getenv("LADSPA_PATH"))) {
296 find_plugins("/usr/lib/ladspa");
297 find_plugins("/usr/local/lib/ladspa");
298 } else {
299 ladspa_path = strdup(ladspa_path);
300 directory = strtok(ladspa_path, ":");
301 while (directory != NULL) {
302 find_plugins(directory);
303 directory = strtok(NULL, ":");
304 }
305 free(ladspa_path);
306 }
307 }
308
309
310
311 static gboolean
fxbuilder_close(GtkWidget * widget,GdkEvent * event,gpointer data)312 fxbuilder_close(GtkWidget * widget, GdkEvent * event, gpointer data) {
313
314 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(plugin_toggle), FALSE);
315 return TRUE;
316 }
317
318 void
show_fxbuilder(void)319 show_fxbuilder(void) {
320
321 set_active_state();
322 gtk_widget_show_all(fxbuilder_window);
323 fxbuilder_on = 1;
324 register_toplevel_window(fxbuilder_window, TOP_WIN_SKIN | TOP_WIN_TRAY);
325 }
326
327
328 void
hide_fxbuilder(void)329 hide_fxbuilder(void) {
330
331 gtk_widget_hide(fxbuilder_window);
332 fxbuilder_on = 0;
333 register_toplevel_window(fxbuilder_window, TOP_WIN_SKIN);
334 }
335
336
337 gint
fxbuilder_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer * data)338 fxbuilder_key_pressed(GtkWidget * widget, GdkEventKey * event, gpointer * data) {
339
340 switch (event->keyval) {
341 case GDK_q:
342 case GDK_Q:
343 case GDK_Escape:
344 fxbuilder_close(NULL, NULL, NULL);
345 return TRUE;
346 };
347
348 return FALSE;
349 }
350
351
352 /* we need this because the default gtk sort func doesn't obey spaces in strings
353 eg. "ABCE" gets in between "ABC D" and "ABC F" and not after them.
354 */
355 gint
compare_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)356 compare_func(GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data) {
357
358 int col = GPOINTER_TO_INT(user_data);
359 char * sa;
360 char * sb;
361 int ret;
362
363 gtk_tree_model_get(model, a, col, &sa, -1);
364 gtk_tree_model_get(model, b, col, &sb, -1);
365
366 ret = strcmp(sa, sb);
367
368 g_free(sa);
369 g_free(sb);
370
371 return ret;
372 }
373
374
375 plugin_instance *
instantiate(char * filename,int index)376 instantiate(char * filename, int index) {
377
378 LADSPA_Descriptor_Function descriptor_fn;
379 plugin_instance * instance;
380 int n_ins, n_outs, n_ctrl, port;
381
382 if ((instance = calloc(1, sizeof(plugin_instance))) == NULL) {
383 fprintf(stderr, "plugin.c: instantiate(): calloc error\n");
384 return NULL;
385 }
386
387 strncpy(instance->filename, filename, MAXLEN-1);
388 instance->index = index;
389
390 instance->library = dlopen(filename, RTLD_NOW);
391 if (instance->library == NULL) {
392 fprintf(stderr, "dlopen() failed on %s -- is it a valid shared library file?\n", filename);
393 free(instance);
394 return NULL;
395 }
396 descriptor_fn = dlsym(instance->library, "ladspa_descriptor");
397 if (descriptor_fn == NULL) {
398 fprintf(stderr,
399 "dlsym() failed to load symbol 'ladspa_descriptor'. "
400 "Possibly a bug in %s\n", filename);
401 dlclose(instance->library);
402 free(instance);
403 return NULL;
404 }
405 instance->descriptor = descriptor_fn(index);
406
407 if (LADSPA_IS_INPLACE_BROKEN(instance->descriptor->Properties)) {
408 fprintf(stderr,
409 "%s (%s) is INPLACE_BROKEN and thus unusable in "
410 "Aqualung at this time.\n", instance->descriptor->Label, instance->descriptor->Name);
411 dlclose(instance->library);
412 free(instance);
413 return NULL;
414 }
415
416 for (n_ins = n_outs = n_ctrl = port = 0; port < instance->descriptor->PortCount; ++port) {
417 if (LADSPA_IS_PORT_AUDIO(instance->descriptor->PortDescriptors[port])) {
418 if (LADSPA_IS_PORT_INPUT(instance->descriptor->PortDescriptors[port]))
419 ++n_ins;
420 if (LADSPA_IS_PORT_OUTPUT(instance->descriptor->PortDescriptors[port]))
421 ++n_outs;
422 } else {
423 ++n_ctrl;
424 }
425 }
426
427 if (n_ctrl > MAX_KNOBS) {
428 fprintf(stderr,
429 "%s (%s) has more than %d input knobs; "
430 "Aqualung cannot use it.\n",
431 instance->descriptor->Label, instance->descriptor->Name, MAX_KNOBS);
432 dlclose(instance->library);
433 free(instance);
434 return NULL;
435 }
436
437 if ((n_ins == 1) && (n_outs == 1)) {
438 instance->is_mono = 1;
439 instance->handle = instance->descriptor->instantiate(instance->descriptor, out_SR);
440 instance->handle2 = instance->descriptor->instantiate(instance->descriptor, out_SR);
441 } else {
442 instance->is_mono = 0;
443 instance->handle = instance->descriptor->instantiate(instance->descriptor, out_SR);
444 instance->handle2 = NULL;
445 }
446
447 instance->is_restored = 0;
448 instance->is_bypassed = 1;
449 instance->shift_pressed = 0;
450 instance->window = NULL;
451 instance->bypass_button = NULL;
452 instance->trashlist = trashlist_new();
453
454 return instance;
455 }
456
457
458 void
connect_port(plugin_instance * instance)459 connect_port(plugin_instance * instance) {
460
461 unsigned long port;
462 unsigned long inputs = 0, outputs = 0;
463 const LADSPA_Descriptor * plugin = instance->descriptor;
464
465 for (port = 0; port < plugin->PortCount; ++port) {
466
467 if (LADSPA_IS_PORT_CONTROL(plugin->PortDescriptors[port])) {
468 if (port < MAX_KNOBS) {
469 plugin->connect_port(instance->handle, port,
470 &(instance->knobs[port]));
471 if (instance->handle2)
472 plugin->connect_port(instance->handle2, port,
473 &(instance->knobs[port]));
474 } else {
475 fprintf(stderr, "impossible: control port count out of range\n");
476 }
477
478 } else if (LADSPA_IS_PORT_AUDIO(plugin->PortDescriptors[port])) {
479
480 if (LADSPA_IS_PORT_INPUT(plugin->PortDescriptors[port])) {
481 if (inputs == 0) {
482 plugin->connect_port(instance->handle, port, l_buf);
483 if (instance->handle2)
484 plugin->connect_port(instance->handle2, port, r_buf);
485 } else if (inputs == 1 && !instance->is_mono) {
486 plugin->connect_port(instance->handle, port, r_buf);
487 } else {
488 fprintf(stderr, "impossible: input port count out of range\n");
489 }
490 inputs++;
491
492 } else if (LADSPA_IS_PORT_OUTPUT(plugin->PortDescriptors[port])) {
493 if (outputs == 0) {
494 plugin->connect_port(instance->handle, port, l_buf);
495 if (instance->handle2)
496 plugin->connect_port(instance->handle2, port, r_buf);
497 } else if (outputs == 1 && !instance->is_mono) {
498 plugin->connect_port(instance->handle, port, r_buf);
499 } else {
500 fprintf(stderr, "impossible: output port count out of range\n");
501 }
502 outputs++;
503 }
504 }
505 }
506 }
507
508
509 void
activate(plugin_instance * instance)510 activate(plugin_instance * instance) {
511
512 const LADSPA_Descriptor * descriptor = instance->descriptor;
513
514 if (descriptor->activate) {
515 descriptor->activate(instance->handle);
516 if (instance->handle2) {
517 descriptor->activate(instance->handle2);
518 }
519 }
520 }
521
522
523 void
get_bypassed_name(plugin_instance * instance,char * str)524 get_bypassed_name(plugin_instance * instance, char * str) {
525
526 if (instance->is_bypassed) {
527 snprintf(str, MAXLEN-1, "(%s)", instance->descriptor->Name);
528 } else {
529 strncpy(str, instance->descriptor->Name, MAXLEN-1);
530 }
531 }
532
533
534 void
refresh_plugin_vect(int diff)535 refresh_plugin_vect(int diff) {
536
537 int i = 0, j = 0;
538 GtkTreeIter iter;
539 gpointer gp_instance;
540 plugin_instance * plugin_vect_shadow[MAX_PLUGINS];
541
542 while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(running_store), &iter, NULL, i) &&
543 i < MAX_PLUGINS) {
544
545 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 1, &gp_instance, -1);
546 plugin_vect_shadow[i] = (plugin_instance *) gp_instance;
547 ++i;
548 }
549
550 while (plugin_lock)
551 ;
552 if (diff < 0)
553 n_plugins += diff;
554
555 for (j = 0; j < i; j++) {
556 while (plugin_lock)
557 ;
558 plugin_vect[j] = plugin_vect_shadow[j];
559 }
560
561 while (plugin_lock)
562 ;
563 if (diff >= 0)
564 n_plugins += diff;
565 }
566
567
568 static gboolean
close_plugin_window(GtkWidget * widget,GdkEvent * event,gpointer data)569 close_plugin_window(GtkWidget * widget, GdkEvent * event, gpointer data) {
570
571 gtk_widget_hide(widget);
572 register_toplevel_window(widget, TOP_WIN_SKIN);
573 return TRUE;
574 }
575
576
577 void
plugin_bypassed(GtkWidget * widget,gpointer data)578 plugin_bypassed(GtkWidget * widget, gpointer data) {
579
580 int i = 0;
581 GtkTreeIter iter;
582 char bypassed_name[MAXLEN];
583 char * name;
584 gpointer gp_instance;
585 plugin_instance * instance = (plugin_instance *) data;
586
587 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
588 instance->is_bypassed = 1;
589 } else {
590 instance->is_bypassed = 0;
591 }
592
593 while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(running_store), &iter, NULL, i)) {
594
595 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 0, &name, 1, &gp_instance, -1);
596 if (instance == (plugin_instance *)gp_instance) {
597 get_bypassed_name(instance, bypassed_name);
598 gtk_list_store_set(running_store, &iter, 0, bypassed_name, -1);
599 return;
600 }
601 ++i;
602 }
603 }
604
605
606 void
plugin_btn_toggled(GtkWidget * widget,gpointer data)607 plugin_btn_toggled(GtkWidget * widget, gpointer data) {
608
609 LADSPA_Data * plugin_data = (LADSPA_Data *) data;
610
611 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
612 *plugin_data = 1.0f;
613 } else {
614 *plugin_data = -1.0f;
615 }
616 }
617
618
619 gint
update_plugin_outputs(gpointer data)620 update_plugin_outputs(gpointer data) {
621
622 plugin_instance * instance = (plugin_instance *) data;
623 unsigned long k;
624
625 for (k = 0; k < MAX_KNOBS && k < instance->descriptor->PortCount; ++k) {
626 if (LADSPA_IS_PORT_OUTPUT(instance->descriptor->PortDescriptors[k])
627 && LADSPA_IS_PORT_CONTROL(instance->descriptor->PortDescriptors[k])) {
628
629 while (plugin_lock)
630 ;
631 instance->adjustments[k]->value = instance->knobs[k];
632 }
633 }
634
635 for (k = 0; k < MAX_KNOBS && k < instance->descriptor->PortCount; ++k) {
636 if (LADSPA_IS_PORT_OUTPUT(instance->descriptor->PortDescriptors[k])
637 && LADSPA_IS_PORT_CONTROL(instance->descriptor->PortDescriptors[k])) {
638
639 gtk_adjustment_value_changed(instance->adjustments[k]);
640 }
641 }
642 return TRUE;
643 }
644
645
646 void
plugin_value_changed(GtkAdjustment * adj,gpointer data)647 plugin_value_changed(GtkAdjustment * adj, gpointer data) {
648
649 LADSPA_Data * plugin_data = (LADSPA_Data *) data;
650
651 *plugin_data = (LADSPA_Data) gtk_adjustment_get_value(adj);
652 }
653
654
655 void
changed_combo(GtkWidget * widget,gpointer * data)656 changed_combo(GtkWidget * widget, gpointer * data) {
657
658 optdata_t * optdata = (optdata_t *) data;
659 plugin_instance * instance = optdata->instance;
660 int k = optdata->index;
661
662 int i = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
663 LADSPA_Data value = 0.0f;
664
665 lrdf_defaults * defs = lrdf_get_scale_values(instance->descriptor->UniqueID, k);
666 value = defs->items[i].value;
667
668 lrdf_free_setting_values(defs);
669
670 instance->knobs[k] = value;
671 }
672
673
674 gint
plugin_window_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer * data)675 plugin_window_key_pressed(GtkWidget * widget, GdkEventKey * event, gpointer * data) {
676
677 plugin_instance * instance = (plugin_instance *) data;
678
679 switch (event->keyval) {
680 case GDK_Shift_L:
681 case GDK_Shift_R:
682 instance->shift_pressed = 1;
683 break;
684 }
685
686 return FALSE;
687 }
688
689
690 gint
plugin_window_key_released(GtkWidget * widget,GdkEventKey * event,gpointer * data)691 plugin_window_key_released(GtkWidget * widget, GdkEventKey * event, gpointer * data) {
692
693 plugin_instance * instance = (plugin_instance *) data;
694
695 switch (event->keyval) {
696 case GDK_Shift_L:
697 case GDK_Shift_R:
698 instance->shift_pressed = 0;
699 break;
700 }
701
702 return FALSE;
703 }
704
705
706 gint
plugin_window_focus_out(GtkWidget * widget,GdkEventKey * event,gpointer * data)707 plugin_window_focus_out(GtkWidget * widget, GdkEventKey * event, gpointer * data) {
708
709 plugin_instance * instance = (plugin_instance *) data;
710
711 instance->shift_pressed = 0;
712
713 return FALSE;
714 }
715
716
717 gint
plugin_scale_btn_pressed(GtkWidget * widget,GdkEventButton * event,gpointer * data)718 plugin_scale_btn_pressed(GtkWidget * widget, GdkEventButton * event, gpointer * data) {
719
720 btnpdata_t * btnpdata = (btnpdata_t *) data;
721 GtkAdjustment * adj;
722
723 if (event->button != 1)
724 return FALSE;
725
726 if (!btnpdata->instance->shift_pressed)
727 return FALSE;
728
729 adj = gtk_range_get_adjustment(GTK_RANGE(widget));
730 adj->value = btnpdata->start;
731 gtk_adjustment_value_changed(adj);
732
733 return TRUE;
734 }
735
736
737 void
build_plugin_window(plugin_instance * instance)738 build_plugin_window(plugin_instance * instance) {
739
740 const LADSPA_Descriptor * plugin = instance->descriptor;
741 const LADSPA_PortRangeHint * hints = plugin->PortRangeHints;
742 LADSPA_Data fact, min, max, step, start, default_val;
743 lrdf_defaults * defs;
744 int dp;
745 unsigned long k;
746 int n_outs = 0;
747 int n_ins = 0;
748 int n_toggled = 0;
749 int n_untoggled = 0;
750 int n_outctl = 0;
751 int n_outlat = 0;
752 int n_rows = 0;
753 int i = 0;
754
755 char str_inout[32];
756 char str_n[16];
757 char * c;
758 char maker[MAXLEN];
759 GtkWidget * widget;
760 GtkWidget * hbox;
761 GtkWidget * vbox;
762 GtkWidget * upper_hbox;
763 GtkWidget * upper_vbox;
764
765 GtkWidget * scrwin;
766 GtkWidget * inner_vbox;
767 GtkWidget * table = NULL;
768 GtkWidget * hseparator;
769 GtkObject * adjustment;
770 GtkWidget * combo;
771
772 optdata_t * optdata;
773 btnpdata_t * btnpdata;
774 int j;
775
776 GtkRequisition req;
777 int max_width = 0;
778 int height = 0;
779
780
781 instance->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
782 gtk_window_set_title(GTK_WINDOW(instance->window), plugin->Name);
783 gtk_window_set_position(GTK_WINDOW(instance->window), GTK_WIN_POS_CENTER);
784 gtk_window_set_transient_for(GTK_WINDOW(instance->window), GTK_WINDOW(fxbuilder_window));
785 g_signal_connect(G_OBJECT(instance->window), "key_press_event",
786 G_CALLBACK(plugin_window_key_pressed), instance);
787 g_signal_connect(G_OBJECT(instance->window), "key_release_event",
788 G_CALLBACK(plugin_window_key_released), instance);
789 g_signal_connect(G_OBJECT(instance->window), "focus_out_event",
790 G_CALLBACK(plugin_window_focus_out), instance);
791 gtk_widget_set_events(instance->window,
792 GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
793 gtk_container_set_border_width(GTK_CONTAINER(instance->window), 5);
794
795 vbox = gtk_vbox_new(FALSE, 3);
796 gtk_container_add(GTK_CONTAINER(instance->window), vbox);
797
798 upper_hbox = gtk_hbox_new(FALSE, 0);
799 gtk_box_pack_start(GTK_BOX(vbox), upper_hbox, FALSE, TRUE, 2);
800
801 upper_vbox = gtk_vbox_new(FALSE, 0);
802 gtk_box_pack_start(GTK_BOX(upper_hbox), upper_vbox, FALSE, FALSE, 2);
803
804 widget = gtk_label_new(plugin->Name);
805 gtk_widget_set_name(widget, "plugin_name");
806 hbox = gtk_hbox_new(FALSE, 0);
807 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
808 gtk_box_pack_start(GTK_BOX(upper_vbox), hbox, FALSE, FALSE, 2);
809
810 strncpy(maker, plugin->Maker, MAXLEN-1);
811 if ((c = strchr(maker, '<')) != NULL)
812 *c = '\0';
813 widget = gtk_label_new(maker);
814 gtk_widget_set_name(widget, "plugin_maker");
815 hbox = gtk_hbox_new(FALSE, 0);
816 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
817 gtk_box_pack_start(GTK_BOX(upper_vbox), hbox, FALSE, FALSE, 2);
818
819 /* count audio I/O ports */
820 for (k = 0; k < MAX_KNOBS && k < plugin->PortCount; ++k) {
821 if (LADSPA_IS_PORT_CONTROL(plugin->PortDescriptors[k]))
822 continue;
823 if (LADSPA_IS_PORT_OUTPUT(plugin->PortDescriptors[k])) {
824 ++n_outs;
825 } else {
826 ++n_ins;
827 }
828 }
829
830 strcpy(str_inout, "[ ");
831 if (n_ins == 1) {
832 strcat(str_inout, "1 in");
833 } else {
834 snprintf(str_n, 15, "%d ins", n_ins);
835 strcat(str_inout, str_n);
836 }
837 strcat(str_inout, " | ");
838 if (n_outs == 1) {
839 strcat(str_inout, "1 out");
840 } else {
841 snprintf(str_n, 15, "%d outs", n_outs);
842 strcat(str_inout, str_n);
843 }
844 strcat(str_inout, " ]");
845
846 widget = gtk_label_new(str_inout);
847 hbox = gtk_hbox_new(FALSE, 0);
848 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
849 gtk_box_pack_start(GTK_BOX(upper_vbox), hbox, FALSE, FALSE, 2);
850
851 upper_vbox = gtk_vbox_new(FALSE, 0);
852 gtk_box_pack_end(GTK_BOX(upper_hbox), upper_vbox, FALSE, FALSE, 2);
853
854
855 widget = gtk_toggle_button_new_with_label("BYPASS");
856 gtk_widget_set_name(widget, "plugin_bypass_button");
857 instance->bypass_button = widget;
858 gtk_box_pack_start(GTK_BOX(upper_vbox), widget, FALSE, FALSE, 2);
859 g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(plugin_bypassed), instance);
860 if (instance->is_restored) {
861 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), instance->is_bypassed);
862 } else {
863 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
864 }
865
866
867 /* count control I/O ports */
868 for (k = 0; k < MAX_KNOBS && k < plugin->PortCount; ++k) {
869 if (LADSPA_IS_PORT_AUDIO(plugin->PortDescriptors[k]))
870 continue;
871 if (LADSPA_IS_PORT_INPUT(plugin->PortDescriptors[k])) {
872 if (LADSPA_IS_HINT_TOGGLED(hints[k].HintDescriptor)) {
873 ++n_toggled;
874 } else {
875 ++n_untoggled;
876 }
877 } else {
878 if (strcmp(plugin->PortNames[k], "latency") == 0) {
879 ++n_outlat;
880 } else {
881 ++n_outctl;
882 }
883 }
884 ++n_rows;
885 }
886
887 if ((n_toggled) && (n_untoggled))
888 ++n_rows;
889 if (((n_toggled) || (n_untoggled)) && (n_outctl))
890 ++n_rows;
891 if (((n_toggled) || (n_untoggled) || (n_outctl)) && (n_outlat))
892 ++n_rows;
893
894
895 scrwin = gtk_scrolled_window_new(NULL, NULL);
896 gtk_widget_set_name(scrwin, "plugin_scrwin");
897 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
898 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
899 gtk_box_pack_start(GTK_BOX(vbox), scrwin, TRUE, TRUE, 2);
900
901 inner_vbox = gtk_vbox_new(FALSE, 0);
902 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrwin), inner_vbox);
903
904 if ((n_toggled) || (n_untoggled) || (n_outctl) || (n_outlat)) {
905 table = gtk_table_new(n_rows, 3, FALSE);
906 gtk_box_pack_start(GTK_BOX(inner_vbox), table, TRUE, TRUE, 2);
907 }
908
909 if (n_toggled) {
910 for (k = 0; k < MAX_KNOBS && k < plugin->PortCount; ++k) {
911 int max_height = 0;
912
913 if (!LADSPA_IS_PORT_CONTROL(plugin->PortDescriptors[k]))
914 continue;
915 if (LADSPA_IS_PORT_OUTPUT(plugin->PortDescriptors[k]))
916 continue;
917 if (!LADSPA_IS_HINT_TOGGLED(hints[k].HintDescriptor))
918 continue;
919
920 widget = gtk_label_new(plugin->PortNames[k]);
921 hbox = gtk_hbox_new(FALSE, 0);
922 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
923 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, i, i+1,
924 GTK_FILL, GTK_FILL | GTK_EXPAND, 2, 2);
925 gtk_widget_size_request(widget, &req);
926 req.height += 2;
927 if (req.width > max_width)
928 max_width = req.width;
929 if (req.height > max_height)
930 max_height = req.height;
931
932 widget = gtk_toggle_button_new();
933 gtk_widget_set_name(widget, "plugin_toggled");
934 gtk_widget_set_size_request(widget, 14, 14);
935 gtk_table_attach(GTK_TABLE(table), widget, 2, 3, i, i+1, 0, 0, 0, 0);
936 gtk_widget_size_request(widget, &req);
937 if (req.height > max_height)
938 max_height = req.height;
939 height += max_height;
940 ++i;
941
942 g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(plugin_btn_toggled),
943 &(instance->knobs[k]));
944
945 if (((instance->is_restored) && (instance->knobs[k] > 0.0f)) ||
946 ((!instance->is_restored) &&
947 (LADSPA_IS_HINT_DEFAULT_1(hints[k].HintDescriptor)))) {
948 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
949 }
950 }
951 }
952
953 if ((n_toggled) && (n_untoggled)) {
954 hseparator = gtk_hseparator_new();
955 gtk_table_attach(GTK_TABLE(table), hseparator, 0, 3, i, i+1, GTK_FILL, GTK_FILL, 2, 2);
956 ++i;
957 gtk_widget_size_request(hseparator, &req);
958 height += req.height + 5;
959 }
960
961 if (n_untoggled) {
962 for (k = 0; k < MAX_KNOBS && k < plugin->PortCount; ++k) {
963 int max_height = 0;
964
965 if (!LADSPA_IS_PORT_CONTROL(plugin->PortDescriptors[k]))
966 continue;
967 if (LADSPA_IS_PORT_OUTPUT(plugin->PortDescriptors[k]))
968 continue;
969 if (LADSPA_IS_HINT_TOGGLED(hints[k].HintDescriptor))
970 continue;
971
972 widget = gtk_label_new(plugin->PortNames[k]);
973 hbox = gtk_hbox_new(FALSE, 0);
974 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
975 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, i, i+1,
976 GTK_FILL, GTK_FILL | GTK_EXPAND, 2, 2);
977 gtk_widget_size_request(widget, &req);
978 req.height += 2;
979 if (req.width > max_width)
980 max_width = req.width;
981
982
983 if (LADSPA_IS_HINT_SAMPLE_RATE(hints[k].HintDescriptor)) {
984 fact = out_SR;
985 } else {
986 fact = 1.0f;
987 }
988
989 if (LADSPA_IS_HINT_BOUNDED_BELOW(hints[k].HintDescriptor)) {
990 min = hints[k].LowerBound * fact;
991 } else {
992 min = -10000.0f;
993 }
994
995 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hints[k].HintDescriptor)) {
996 max = hints[k].UpperBound * fact;
997 } else {
998 max = 10000.0f;
999 }
1000
1001 /* infinity */
1002 if (10000.0f <= max - min) {
1003 dp = 1;
1004 step = 5.0f;
1005
1006 /* 100.0 ... lots */
1007 } else if (100.0f < max - min) {
1008 dp = 0;
1009 step = 1.0f;
1010
1011 /* 10.0 ... 100.0 */
1012 } else if (10.0f < max - min) {
1013 dp = 1;
1014 step = 0.1f;
1015
1016 /* 1.0 ... 10.0 */
1017 } else if (1.0f < max - min) {
1018 dp = 2;
1019 step = 0.01f;
1020
1021 /* 0.0 ... 1.0 */
1022 } else {
1023 dp = 3;
1024 step = 0.001f;
1025 }
1026
1027 if (LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1028 dp = 0;
1029 if (step < 1.0f) step = 1.0f;
1030 }
1031
1032 if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hints[k].HintDescriptor)) {
1033 default_val = min;
1034 } else if (LADSPA_IS_HINT_DEFAULT_LOW(hints[k].HintDescriptor)) {
1035 default_val = min * 0.75f + max * 0.25f;
1036 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hints[k].HintDescriptor)) {
1037 default_val = min * 0.5f + max * 0.5f;
1038 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hints[k].HintDescriptor)) {
1039 default_val = min * 0.25f + max * 0.75f;
1040 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hints[k].HintDescriptor)) {
1041 default_val = max;
1042 } else if (LADSPA_IS_HINT_DEFAULT_0(hints[k].HintDescriptor)) {
1043 default_val = 0.0f;
1044 } else if (LADSPA_IS_HINT_DEFAULT_1(hints[k].HintDescriptor)) {
1045 default_val = 1.0f;
1046 } else if (LADSPA_IS_HINT_DEFAULT_100(hints[k].HintDescriptor)) {
1047 default_val = 100.0f;
1048 } else if (LADSPA_IS_HINT_DEFAULT_440(hints[k].HintDescriptor)) {
1049 default_val = 440.0f;
1050 } else if (LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1051 default_val = min;
1052 } else if (max >= 0.0f && min <= 0.0f) {
1053 default_val = 0.0f;
1054 } else {
1055 default_val = min * 0.5f + max * 0.5f;
1056 }
1057
1058 if (instance->is_restored) {
1059 start = instance->knobs[k];
1060 } else {
1061 instance->knobs[k] = start = default_val;
1062 }
1063
1064 defs = lrdf_get_scale_values(plugin->UniqueID, k);
1065 if ((defs) && (defs->count > 0)) { /* have scale values */
1066
1067 combo = gtk_combo_box_new_text ();
1068 gtk_widget_set_name(combo, "plugin_combo");
1069 gtk_table_attach(GTK_TABLE(table), combo, 1, 3, i, i+1,
1070 GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 2);
1071
1072 for (j = 0; j < defs->count; j++) {
1073 gtk_combo_box_append_text (GTK_COMBO_BOX (combo), defs->items[j].label);
1074 }
1075
1076 gtk_widget_size_request(combo, &req);
1077 req.height += 2;
1078 if (req.height > max_height)
1079 max_height = req.height;
1080
1081 /* now if we have an option that corresponds to 'start', choose that. */
1082 for (j = 0; j < defs->count; j++) {
1083 if (defs->items[j].value == start) {
1084 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), start);
1085 break;
1086 }
1087 }
1088
1089 if ((optdata = malloc(sizeof(optdata_t))) == NULL) {
1090 fprintf(stderr, "plugin.c: build_plugin_window(): malloc error\n");
1091 return;
1092 }
1093 trashlist_add(instance->trashlist, optdata);
1094
1095 optdata->instance = instance;
1096 optdata->index = k;
1097 g_signal_connect(combo, "changed", G_CALLBACK(changed_combo), optdata);
1098
1099 } else { /* no scale values */
1100
1101 adjustment = gtk_adjustment_new(start, min, max, step, step * 50.0, 0.0);
1102 instance->adjustments[k] = GTK_ADJUSTMENT(adjustment);
1103 g_signal_connect(G_OBJECT(adjustment), "value_changed",
1104 G_CALLBACK(plugin_value_changed), &(instance->knobs[k]));
1105
1106 if (!LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1107 widget = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
1108 gtk_widget_set_name(widget, "plugin_scale");
1109 gtk_widget_set_size_request(widget, 200, -1);
1110 gtk_scale_set_digits(GTK_SCALE(widget), dp);
1111 gtk_table_attach(GTK_TABLE(table), widget, 1, 2, i, i+1,
1112 GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 2);
1113 gtk_scale_set_draw_value(GTK_SCALE(widget), FALSE);
1114 gtk_widget_size_request(widget, &req);
1115 req.height += 2;
1116 if (req.height > max_height)
1117 max_height = req.height;
1118
1119 if ((btnpdata = malloc(sizeof(btnpdata_t))) == NULL) {
1120 fprintf(stderr,
1121 "plugin.c: build_plugin_window(): malloc error\n");
1122 return;
1123 }
1124 trashlist_add(instance->trashlist, btnpdata);
1125 btnpdata->instance = instance;
1126 btnpdata->start = default_val;
1127 g_signal_connect(G_OBJECT(widget), "button_press_event",
1128 G_CALLBACK(plugin_scale_btn_pressed),
1129 (gpointer) btnpdata);
1130 }
1131
1132 widget = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), step, dp);
1133 gtk_widget_set_size_request(widget, 70, -1);
1134 gtk_table_attach(GTK_TABLE(table), widget, 2, 3, i, i+1,
1135 GTK_FILL, GTK_FILL, 2, 2);
1136 gtk_widget_size_request(widget, &req);
1137 req.height += 2;
1138 if (req.height > max_height)
1139 max_height = req.height;
1140 }
1141 height += max_height;
1142 ++i;
1143 lrdf_free_setting_values(defs);
1144 }
1145 }
1146
1147
1148 if (((n_toggled) || (n_untoggled)) && (n_outctl)) {
1149 hseparator = gtk_hseparator_new();
1150 gtk_table_attach(GTK_TABLE(table), hseparator, 0, 3, i, i+1, GTK_FILL, GTK_FILL, 2, 2);
1151 ++i;
1152 gtk_widget_size_request(hseparator, &req);
1153 height += req.height + 5;
1154 }
1155
1156 if (n_outctl) {
1157 for (k = 0; k < MAX_KNOBS && k < plugin->PortCount; ++k) {
1158 int max_height = 0;
1159
1160 if (!LADSPA_IS_PORT_CONTROL(plugin->PortDescriptors[k]))
1161 continue;
1162 if (LADSPA_IS_PORT_INPUT(plugin->PortDescriptors[k]))
1163 continue;
1164 if (LADSPA_IS_HINT_TOGGLED(hints[k].HintDescriptor))
1165 continue;
1166
1167 widget = gtk_label_new(plugin->PortNames[k]);
1168 hbox = gtk_hbox_new(FALSE, 0);
1169 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
1170 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, i, i+1,
1171 GTK_FILL, GTK_FILL | GTK_EXPAND, 2, 2);
1172 gtk_widget_size_request(widget, &req);
1173 req.height += 2;
1174 if (req.width > max_width)
1175 max_width = req.width;
1176 if (req.height > max_height)
1177 max_height = req.height;
1178
1179 if (LADSPA_IS_HINT_SAMPLE_RATE(hints[k].HintDescriptor)) {
1180 fact = out_SR;
1181 } else {
1182 fact = 1.0f;
1183 }
1184
1185 if (LADSPA_IS_HINT_BOUNDED_BELOW(hints[k].HintDescriptor)) {
1186 min = hints[k].LowerBound * fact;
1187 } else {
1188 min = -10000.0f;
1189 }
1190
1191 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hints[k].HintDescriptor)) {
1192 max = hints[k].UpperBound * fact;
1193 } else {
1194 max = 10000.0f;
1195 }
1196
1197 /* infinity */
1198 if (10000.0f <= max - min) {
1199 dp = 1;
1200 step = 5.0f;
1201
1202 /* 100.0 ... lots */
1203 } else if (100.0f < max - min) {
1204 dp = 0;
1205 step = 1.0f;
1206
1207 /* 10.0 ... 100.0 */
1208 } else if (10.0f < max - min) {
1209 dp = 1;
1210 step = 0.1f;
1211
1212 /* 1.0 ... 10.0 */
1213 } else if (1.0f < max - min) {
1214 dp = 2;
1215 step = 0.01f;
1216
1217 /* 0.0 ... 1.0 */
1218 } else {
1219 dp = 3;
1220 step = 0.001f;
1221 }
1222
1223 if (LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1224 dp = 0;
1225 if (step < 1.0f) step = 1.0f;
1226 }
1227
1228 if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hints[k].HintDescriptor)) {
1229 start = min;
1230 } else if (LADSPA_IS_HINT_DEFAULT_LOW(hints[k].HintDescriptor)) {
1231 start = min * 0.75f + max * 0.25f;
1232 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hints[k].HintDescriptor)) {
1233 start = min * 0.5f + max * 0.5f;
1234 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hints[k].HintDescriptor)) {
1235 start = min * 0.25f + max * 0.75f;
1236 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hints[k].HintDescriptor)) {
1237 start = max;
1238 } else if (LADSPA_IS_HINT_DEFAULT_0(hints[k].HintDescriptor)) {
1239 start = 0.0f;
1240 } else if (LADSPA_IS_HINT_DEFAULT_1(hints[k].HintDescriptor)) {
1241 start = 1.0f;
1242 } else if (LADSPA_IS_HINT_DEFAULT_100(hints[k].HintDescriptor)) {
1243 start = 100.0f;
1244 } else if (LADSPA_IS_HINT_DEFAULT_440(hints[k].HintDescriptor)) {
1245 start = 440.0f;
1246 } else if (LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1247 start = min;
1248 } else if (max >= 0.0f && min <= 0.0f) {
1249 start = 0.0f;
1250 } else {
1251 start = min * 0.5f + max * 0.5f;
1252 }
1253
1254 instance->knobs[k] = start;
1255
1256 adjustment = gtk_adjustment_new(start, min, max, step, step * 50.0, 0.0);
1257 instance->adjustments[k] = GTK_ADJUSTMENT(adjustment);
1258
1259 if (!LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1260 widget = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
1261 gtk_widget_set_name(widget, "plugin_scale");
1262 gtk_widget_set_size_request(widget, 200, -1);
1263 gtk_scale_set_digits(GTK_SCALE(widget), dp);
1264 gtk_table_attach(GTK_TABLE(table), widget, 1, 2, i, i+1,
1265 GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 2);
1266 gtk_scale_set_draw_value(GTK_SCALE(widget), FALSE);
1267 gtk_widget_set_sensitive(widget, FALSE);
1268 gtk_widget_size_request(widget, &req);
1269 req.height += 2;
1270 if (req.height > max_height)
1271 max_height = req.height;
1272 }
1273
1274 widget = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), step, dp);
1275 gtk_widget_set_size_request(widget, 70, -1);
1276 gtk_widget_set_sensitive(widget, FALSE);
1277 gtk_table_attach(GTK_TABLE(table), widget, 2, 3, i, i+1,
1278 GTK_FILL, GTK_FILL, 2, 2);
1279 gtk_widget_size_request(widget, &req);
1280 req.height += 2;
1281 if (req.height > max_height)
1282 max_height = req.height;
1283 height += max_height;
1284 ++i;
1285 }
1286 }
1287
1288
1289 if (((n_toggled) || (n_untoggled) || (n_outctl)) && (n_outlat)) {
1290 hseparator = gtk_hseparator_new();
1291 gtk_table_attach(GTK_TABLE(table), hseparator, 0, 3, i, i+1, GTK_FILL, GTK_FILL, 2, 2);
1292 ++i;
1293 gtk_widget_size_request(hseparator, &req);
1294 height += req.height + 5;
1295 }
1296
1297 if (n_outlat) {
1298 for (k = 0; k < MAX_KNOBS && k < plugin->PortCount; ++k) {
1299 int max_height = 0;
1300
1301 if (!LADSPA_IS_PORT_CONTROL(plugin->PortDescriptors[k]))
1302 continue;
1303 if (LADSPA_IS_PORT_INPUT(plugin->PortDescriptors[k]))
1304 continue;
1305 if (LADSPA_IS_HINT_TOGGLED(hints[k].HintDescriptor))
1306 continue;
1307
1308 widget = gtk_label_new(plugin->PortNames[k]);
1309 hbox = gtk_hbox_new(FALSE, 0);
1310 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
1311 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, i, i+1,
1312 GTK_FILL, GTK_FILL | GTK_EXPAND, 2, 2);
1313 gtk_widget_size_request(widget, &req);
1314 req.height += 2;
1315 if (req.width > max_width)
1316 max_width = req.width;
1317 if (req.height > max_height)
1318 max_height = req.height;
1319
1320 if (LADSPA_IS_HINT_SAMPLE_RATE(hints[k].HintDescriptor)) {
1321 fact = out_SR;
1322 } else {
1323 fact = 1.0f;
1324 }
1325
1326 if (LADSPA_IS_HINT_BOUNDED_BELOW(hints[k].HintDescriptor)) {
1327 min = hints[k].LowerBound * fact;
1328 } else {
1329 min = -10000.0f;
1330 }
1331
1332 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hints[k].HintDescriptor)) {
1333 max = hints[k].UpperBound * fact;
1334 } else {
1335 max = 10000.0f;
1336 }
1337
1338 /* infinity */
1339 if (10000.0f <= max - min) {
1340 dp = 1;
1341 step = 5.0f;
1342
1343 /* 100.0 ... lots */
1344 } else if (100.0f < max - min) {
1345 dp = 0;
1346 step = 1.0f;
1347
1348 /* 10.0 ... 100.0 */
1349 } else if (10.0f < max - min) {
1350 dp = 1;
1351 step = 0.1f;
1352
1353 /* 1.0 ... 10.0 */
1354 } else if (1.0f < max - min) {
1355 dp = 2;
1356 step = 0.01f;
1357
1358 /* 0.0 ... 1.0 */
1359 } else {
1360 dp = 3;
1361 step = 0.001f;
1362 }
1363
1364 if (LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1365 dp = 0;
1366 if (step < 1.0f) step = 1.0f;
1367 }
1368
1369 if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hints[k].HintDescriptor)) {
1370 start = min;
1371 } else if (LADSPA_IS_HINT_DEFAULT_LOW(hints[k].HintDescriptor)) {
1372 start = min * 0.75f + max * 0.25f;
1373 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hints[k].HintDescriptor)) {
1374 start = min * 0.5f + max * 0.5f;
1375 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hints[k].HintDescriptor)) {
1376 start = min * 0.25f + max * 0.75f;
1377 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hints[k].HintDescriptor)) {
1378 start = max;
1379 } else if (LADSPA_IS_HINT_DEFAULT_0(hints[k].HintDescriptor)) {
1380 start = 0.0f;
1381 } else if (LADSPA_IS_HINT_DEFAULT_1(hints[k].HintDescriptor)) {
1382 start = 1.0f;
1383 } else if (LADSPA_IS_HINT_DEFAULT_100(hints[k].HintDescriptor)) {
1384 start = 100.0f;
1385 } else if (LADSPA_IS_HINT_DEFAULT_440(hints[k].HintDescriptor)) {
1386 start = 440.0f;
1387 } else if (LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1388 start = min;
1389 } else if (max >= 0.0f && min <= 0.0f) {
1390 start = 0.0f;
1391 } else {
1392 start = min * 0.5f + max * 0.5f;
1393 }
1394
1395 instance->knobs[k] = start;
1396
1397 adjustment = gtk_adjustment_new(start, min, max, step, step * 50.0, 0.0);
1398 instance->adjustments[k] = GTK_ADJUSTMENT(adjustment);
1399
1400 if (!LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
1401 widget = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
1402 gtk_widget_set_name(widget, "plugin_scale");
1403 gtk_widget_set_size_request(widget, 200, -1);
1404 gtk_scale_set_digits(GTK_SCALE(widget), dp);
1405 gtk_table_attach(GTK_TABLE(table), widget, 1, 2, i, i+1,
1406 GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 2);
1407 gtk_scale_set_draw_value(GTK_SCALE(widget), FALSE);
1408 gtk_widget_set_sensitive(widget, FALSE);
1409 gtk_widget_size_request(widget, &req);
1410 req.height += 2;
1411 if (req.height > max_height)
1412 max_height = req.height;
1413 }
1414
1415 widget = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), step, dp);
1416 gtk_widget_set_size_request(widget, 70, -1);
1417 gtk_widget_set_sensitive(widget, FALSE);
1418 gtk_table_attach(GTK_TABLE(table), widget, 2, 3, i, i+1,
1419 GTK_FILL, GTK_FILL, 2, 2);
1420 gtk_widget_size_request(widget, &req);
1421 req.height += 2;
1422 if (req.height > max_height)
1423 max_height = req.height;
1424 height += max_height;
1425 ++i;
1426 }
1427 }
1428
1429
1430 if ((!n_toggled) && (!n_untoggled) && (!n_outctl) && (!n_outlat)) {
1431 widget = gtk_label_new("This LADSPA plugin has no user controls");
1432 gtk_box_pack_start(GTK_BOX(inner_vbox), widget, TRUE, TRUE, 2);
1433 gtk_widget_size_request(widget, &req);
1434 gtk_widget_set_size_request(scrwin, req.width + 20, req.height + 20);
1435 } else {
1436 gtk_widget_set_size_request(scrwin, (max_width + 280) * 1.1,
1437 (height > 500) ? 500 : height * 1.1 + 10);
1438 }
1439
1440 if ((n_outctl) || (n_outlat)) {
1441 instance->timeout = aqualung_timeout_add(100, update_plugin_outputs, instance);
1442 } else {
1443 instance->timeout = 0;
1444 }
1445
1446 set_active_state();
1447
1448 g_signal_connect(G_OBJECT(instance->window), "delete_event", G_CALLBACK(close_plugin_window), NULL);
1449 }
1450
1451
1452 void
foreach_plugin_to_add(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1453 foreach_plugin_to_add(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data) {
1454
1455 GtkTreeIter running_iter;
1456 int n_ins;
1457 int n_outs;
1458 char filename[MAXLEN];
1459 int index;
1460 char * str_n_ins;
1461 char * str_n_outs;
1462 char * str_filename;
1463 char * str_index;
1464 plugin_instance * instance;
1465 char bypassed_name[MAXLEN];
1466
1467
1468 gtk_tree_model_get(GTK_TREE_MODEL(avail_store), iter, 3, &str_n_ins,
1469 4, &str_n_outs, 5, &str_filename, 6, &str_index, -1);
1470
1471 sscanf(str_n_ins, "%d", &n_ins);
1472 sscanf(str_n_outs, "%d", &n_outs);
1473 strncpy(filename, str_filename, MAXLEN-1);
1474 sscanf(str_index, "%d", &index);
1475
1476 if (((n_ins == 1) && (n_outs == 1)) ||
1477 ((n_ins == 2) && (n_outs == 2))) {
1478
1479 if (n_plugins >= MAX_PLUGINS) {
1480 fprintf(stderr,
1481 "Maximum number of running plugin instances (%d) reached; "
1482 "cannot add more.\n", MAX_PLUGINS);
1483 return;
1484 }
1485 instance = instantiate(filename, index);
1486 if (instance) {
1487 connect_port(instance);
1488 activate(instance);
1489 build_plugin_window(instance);
1490
1491 get_bypassed_name(instance, bypassed_name);
1492 added_plugin = 1; /* so resort handler will not do any harm */
1493 gtk_list_store_append(running_store, &running_iter);
1494 gtk_list_store_set(running_store, &running_iter,
1495 0, bypassed_name, 1, (gpointer)instance, -1);
1496
1497 refresh_plugin_vect(1);
1498 }
1499 } else {
1500 fprintf(stderr,
1501 "cannot add %s:%d -- it has %d ins and %d outs.\n",
1502 filename, index, n_ins, n_outs);
1503 }
1504 }
1505
1506
1507 gint
add_clicked(GtkWidget * widget,GdkEvent * event,gpointer data)1508 add_clicked(GtkWidget * widget, GdkEvent * event, gpointer data) {
1509
1510 gtk_tree_selection_selected_foreach(avail_select, foreach_plugin_to_add, NULL);
1511
1512 set_active_state();
1513 return TRUE;
1514 }
1515
1516
1517 gint
remove_clicked(GtkWidget * widget,GdkEvent * event,gpointer data)1518 remove_clicked(GtkWidget * widget, GdkEvent * event, gpointer data) {
1519
1520 GtkTreeIter iter;
1521 gpointer gp_instance;
1522 plugin_instance * instance;
1523
1524 if (gtk_tree_selection_get_selected(running_select, NULL, &iter)) {
1525
1526 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 1, &gp_instance, -1);
1527 gtk_list_store_remove(running_store, &iter);
1528 refresh_plugin_vect(-1);
1529
1530 instance = (plugin_instance *) gp_instance;
1531 if (instance->handle) {
1532 if (instance->descriptor->deactivate) {
1533 instance->descriptor->deactivate(instance->handle);
1534 }
1535 instance->descriptor->cleanup(instance->handle);
1536 instance->handle = NULL;
1537 }
1538 if (instance->handle2) {
1539 if (instance->descriptor->deactivate) {
1540 instance->descriptor->deactivate(instance->handle2);
1541 }
1542 instance->descriptor->cleanup(instance->handle2);
1543 instance->handle2 = NULL;
1544 }
1545 if (instance->timeout) {
1546 g_source_remove(instance->timeout);
1547 }
1548 if (instance->window) {
1549 gtk_widget_destroy(instance->window);
1550 unregister_toplevel_window(instance->window);
1551 }
1552
1553 dlclose(instance->library);
1554 trashlist_free(instance->trashlist);
1555 free(instance);
1556 }
1557
1558 set_active_state();
1559 return TRUE;
1560 }
1561
1562
1563 gint
conf_clicked(GtkWidget * widget,GdkEvent * event,gpointer data)1564 conf_clicked(GtkWidget * widget, GdkEvent * event, gpointer data) {
1565
1566 GtkTreeIter iter;
1567 gpointer gp_instance;
1568 plugin_instance * instance;
1569
1570 if (gtk_tree_selection_get_selected(running_select, NULL, &iter)) {
1571
1572 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 1, &gp_instance, -1);
1573 instance = (plugin_instance *) gp_instance;
1574 if (instance->window) {
1575 register_toplevel_window(instance->window, TOP_WIN_SKIN | TOP_WIN_TRAY);
1576 gtk_widget_show_all(instance->window);
1577 }
1578 }
1579
1580 return TRUE;
1581 }
1582
1583
1584
1585 gint
running_list_key_pressed(GtkWidget * widget,GdkEventKey * event)1586 running_list_key_pressed(GtkWidget * widget, GdkEventKey * event) {
1587
1588 switch (event->keyval) {
1589 case GDK_Delete:
1590 case GDK_KP_Delete:
1591 remove_clicked(NULL, NULL, NULL);
1592 return TRUE;
1593 break;
1594 }
1595
1596 return FALSE;
1597 }
1598
1599
1600 gint
running_list_button_pressed(GtkWidget * widget,GdkEventButton * event)1601 running_list_button_pressed(GtkWidget * widget, GdkEventButton * event) {
1602
1603 GtkTreeIter iter;
1604 GtkTreePath * path;
1605 GtkTreeViewColumn * column;
1606 gpointer gp_instance;
1607 plugin_instance * instance;
1608
1609 if (event->type == GDK_BUTTON_PRESS && event->button == 2) {
1610
1611 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(running_list), event->x, event->y,
1612 &path, &column, NULL, NULL)) {
1613
1614 gtk_tree_view_set_cursor(GTK_TREE_VIEW(running_list), path, NULL, FALSE);
1615 gtk_tree_selection_get_selected(running_select, NULL, &iter);
1616
1617 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 1, &gp_instance, -1);
1618 instance = (plugin_instance *) gp_instance;
1619 if (instance->bypass_button) {
1620 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(instance->bypass_button),
1621 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
1622 instance->bypass_button)));
1623 }
1624 }
1625 }
1626
1627 if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
1628 conf_clicked(NULL, NULL, NULL);
1629 }
1630
1631 if (event->type == GDK_BUTTON_PRESS && event->button == 3 &&
1632 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(running_store), &iter, NULL, 0)) {
1633
1634 gtk_menu_popup(GTK_MENU(rp_menu), NULL, NULL, NULL, NULL,
1635 event->button, event->time);
1636 return TRUE;
1637 }
1638
1639 return FALSE;
1640 }
1641
1642
1643 gint
refresh_on_list_changed_cb(gpointer data)1644 refresh_on_list_changed_cb(gpointer data) {
1645
1646 refresh_plugin_vect(0);
1647
1648 return FALSE;
1649 }
1650
1651
1652 void
running_list_row_inserted(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter)1653 running_list_row_inserted(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter) {
1654
1655 if (added_plugin) {
1656 added_plugin = 0;
1657 return;
1658 }
1659 aqualung_timeout_add(100, refresh_on_list_changed_cb, NULL);
1660 }
1661
1662
1663 gint
avail_key_pressed(GtkWidget * widget,GdkEventKey * event)1664 avail_key_pressed(GtkWidget * widget, GdkEventKey * event) {
1665
1666 switch (event->keyval) {
1667 case GDK_a:
1668 case GDK_A:
1669 add_clicked(NULL, NULL, NULL);
1670 return TRUE;
1671 break;
1672 }
1673
1674 return FALSE;
1675 }
1676
1677
1678 gint
avail_dblclicked(GtkWidget * widget,GdkEventButton * event)1679 avail_dblclicked(GtkWidget * widget, GdkEventButton * event) {
1680
1681 if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
1682 add_clicked(NULL, NULL, NULL);
1683 return TRUE;
1684 }
1685
1686 return FALSE;
1687 }
1688
1689 void
set_all_plugins_status(gint status)1690 set_all_plugins_status(gint status) {
1691
1692 GtkTreeIter iter;
1693 gpointer gp_instance;
1694 plugin_instance * instance;
1695 int i = 0;
1696
1697 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(running_store), &iter)) {
1698 do {
1699 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 1, &gp_instance, -1);
1700 instance = (plugin_instance *) gp_instance;
1701 if (instance->bypass_button) {
1702
1703 if (status != -1)
1704 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(instance->bypass_button), status);
1705 else
1706 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(instance->bypass_button),
1707 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(instance->bypass_button)));
1708 }
1709
1710 } while (i++, gtk_tree_model_iter_next(GTK_TREE_MODEL(running_store), &iter));
1711 }
1712 }
1713
1714 void
rp__enable_all_cb(gpointer data)1715 rp__enable_all_cb(gpointer data) {
1716
1717 set_all_plugins_status(FALSE);
1718 }
1719
1720 void
rp__disable_all_cb(gpointer data)1721 rp__disable_all_cb(gpointer data) {
1722
1723 set_all_plugins_status(TRUE);
1724 }
1725
1726 void
rp__toggle_all_cb(gpointer data)1727 rp__toggle_all_cb(gpointer data) {
1728
1729 set_all_plugins_status(-1);
1730 }
1731
1732 void
rp__clear_list_cb(gpointer data)1733 rp__clear_list_cb(gpointer data) {
1734
1735 GtkTreeIter iter;
1736 gpointer gp_instance;
1737 plugin_instance * instance;
1738 int i = 0;
1739
1740 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(running_store), &iter)) {
1741 do {
1742
1743 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 1, &gp_instance, -1);
1744 refresh_plugin_vect(-1);
1745
1746 instance = (plugin_instance *) gp_instance;
1747 if (instance->handle) {
1748 if (instance->descriptor->deactivate) {
1749 instance->descriptor->deactivate(instance->handle);
1750 }
1751 instance->descriptor->cleanup(instance->handle);
1752 instance->handle = NULL;
1753 }
1754 if (instance->handle2) {
1755 if (instance->descriptor->deactivate) {
1756 instance->descriptor->deactivate(instance->handle2);
1757 }
1758 instance->descriptor->cleanup(instance->handle2);
1759 instance->handle2 = NULL;
1760 }
1761 if (instance->timeout)
1762 g_source_remove(instance->timeout);
1763 if (instance->window)
1764 gtk_widget_destroy(instance->window);
1765
1766 trashlist_free(instance->trashlist);
1767 free(instance);
1768
1769 } while (i++, gtk_tree_model_iter_next(GTK_TREE_MODEL(running_store), &iter));
1770
1771 gtk_list_store_clear(running_store);
1772 }
1773
1774 set_active_state();
1775 }
1776
1777 void
create_fxbuilder(void)1778 create_fxbuilder(void) {
1779
1780 GtkWidget * hbox;
1781 GtkWidget * vbox;
1782 GtkWidget * frame_avail;
1783 GtkWidget * viewport_avail;
1784 GtkWidget * scrolled_win_avail;
1785
1786 GtkWidget * frame_running;
1787 GtkWidget * viewport_running;
1788
1789 GtkWidget * hbox_buttons;
1790
1791 GtkWidget * rp__enable_all;
1792 GtkWidget * rp__disable_all;
1793 GtkWidget * rp__toggle_all;
1794 GtkWidget * rp__separator1;
1795 GtkWidget * rp__separator2;
1796 GtkWidget * rp__clear_list;
1797
1798 GtkCellRenderer * renderer;
1799 GtkTreeViewColumn * column;
1800
1801 /* window creating stuff */
1802 fxbuilder_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1803 gtk_window_set_title(GTK_WINDOW(fxbuilder_window), _("LADSPA patch builder"));
1804 gtk_window_set_position(GTK_WINDOW(fxbuilder_window), GTK_WIN_POS_CENTER);
1805 g_signal_connect(G_OBJECT(fxbuilder_window), "delete_event", G_CALLBACK(fxbuilder_close), NULL);
1806 g_signal_connect(G_OBJECT(fxbuilder_window), "key_press_event", G_CALLBACK(fxbuilder_key_pressed), NULL);
1807 gtk_container_set_border_width(GTK_CONTAINER(fxbuilder_window), 2);
1808
1809 hbox = gtk_hbox_new(FALSE, 0);
1810 gtk_container_add(GTK_CONTAINER(fxbuilder_window), hbox);
1811
1812 frame_avail = gtk_frame_new(_("Available plugins"));
1813 gtk_box_pack_start(GTK_BOX(hbox), frame_avail, TRUE, TRUE, 5);
1814
1815 vbox = gtk_vbox_new(FALSE, 0);
1816 gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
1817 gtk_container_add(GTK_CONTAINER(frame_avail), vbox);
1818
1819 viewport_avail = gtk_viewport_new(NULL, NULL);
1820 gtk_box_pack_start(GTK_BOX(vbox), viewport_avail, TRUE, TRUE, 3);
1821
1822 add_button = gtk_button_new_from_stock (GTK_STOCK_ADD);
1823 g_signal_connect(add_button, "clicked", G_CALLBACK(add_clicked), NULL);
1824 gtk_box_pack_start(GTK_BOX(vbox), add_button, FALSE, TRUE, 3);
1825
1826 scrolled_win_avail = gtk_scrolled_window_new(NULL, NULL);
1827 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win_avail),
1828 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1829 gtk_container_add(GTK_CONTAINER(viewport_avail), scrolled_win_avail);
1830
1831 /* create store of available plugins */
1832 if (!avail_store) {
1833 avail_store = gtk_list_store_new(7,
1834 G_TYPE_STRING, /* 0: ID */
1835 G_TYPE_STRING, /* 1: Name */
1836 G_TYPE_STRING, /* 2: category */
1837 G_TYPE_STRING, /* 3: n_ins */
1838 G_TYPE_STRING, /* 4: n_outs */
1839 G_TYPE_STRING, /* 5: filename */
1840 G_TYPE_STRING); /* 6: index */
1841
1842 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(avail_store), 1, GTK_SORT_ASCENDING);
1843
1844 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(avail_store), 0, compare_func,
1845 GINT_TO_POINTER(0), NULL);
1846 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(avail_store), 1, compare_func,
1847 GINT_TO_POINTER(1), NULL);
1848 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(avail_store), 2, compare_func,
1849 GINT_TO_POINTER(2), NULL);
1850 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(avail_store), 3, compare_func,
1851 GINT_TO_POINTER(3), NULL);
1852 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(avail_store), 4, compare_func,
1853 GINT_TO_POINTER(4), NULL);
1854
1855 /* fill avail_store with data */
1856 parse_lrdf_data();
1857 find_all_plugins();
1858 }
1859
1860
1861 avail_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(avail_store));
1862 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(avail_list), FALSE);
1863 gtk_widget_set_size_request(avail_list, 400, 300);
1864 gtk_container_add(GTK_CONTAINER(scrolled_win_avail), avail_list);
1865
1866 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(avail_list), TRUE);
1867
1868 g_signal_connect(G_OBJECT(avail_list), "key_press_event", G_CALLBACK(avail_key_pressed), NULL);
1869 g_signal_connect(G_OBJECT(avail_list), "button_press_event", G_CALLBACK(avail_dblclicked), NULL);
1870
1871
1872 avail_select = gtk_tree_view_get_selection(GTK_TREE_VIEW(avail_list));
1873 gtk_tree_selection_set_mode(avail_select, GTK_SELECTION_MULTIPLE);
1874
1875 renderer = gtk_cell_renderer_text_new();
1876 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1877
1878 column = gtk_tree_view_column_new_with_attributes(_("ID"), renderer, "text", 0, NULL);
1879 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
1880 gtk_tree_view_append_column(GTK_TREE_VIEW(avail_list), column);
1881 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), 0);
1882
1883 if (options.simple_view_in_fx)
1884 gtk_tree_view_column_set_visible(GTK_TREE_VIEW_COLUMN (column), FALSE);
1885
1886 column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", 1, NULL);
1887 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
1888 gtk_tree_view_append_column(GTK_TREE_VIEW(avail_list), column);
1889 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), 1);
1890
1891 column = gtk_tree_view_column_new_with_attributes(_("Category"), renderer, "text", 2, NULL);
1892 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
1893 gtk_tree_view_append_column(GTK_TREE_VIEW(avail_list), column);
1894 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), 2);
1895
1896 if (options.simple_view_in_fx)
1897 gtk_tree_view_column_set_visible(GTK_TREE_VIEW_COLUMN (column), FALSE);
1898
1899 column = gtk_tree_view_column_new_with_attributes(_("Inputs"), renderer, "text", 3, NULL);
1900 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
1901 gtk_tree_view_append_column(GTK_TREE_VIEW(avail_list), column);
1902 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), 3);
1903
1904 if (options.simple_view_in_fx)
1905 gtk_tree_view_column_set_visible(GTK_TREE_VIEW_COLUMN (column), FALSE);
1906
1907 column = gtk_tree_view_column_new_with_attributes(_("Outputs"), renderer, "text", 4, NULL);
1908 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
1909 gtk_tree_view_append_column(GTK_TREE_VIEW(avail_list), column);
1910 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), 4);
1911
1912 if (options.simple_view_in_fx)
1913 gtk_tree_view_column_set_visible(GTK_TREE_VIEW_COLUMN (column), FALSE);
1914
1915 frame_running = gtk_frame_new(_("Running plugins"));
1916 gtk_box_pack_start(GTK_BOX(hbox), frame_running, TRUE, TRUE, 5);
1917
1918 vbox = gtk_vbox_new(FALSE, 0);
1919 gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
1920 gtk_container_add(GTK_CONTAINER(frame_running), vbox);
1921
1922 viewport_running = gtk_viewport_new(NULL, NULL);
1923 gtk_box_pack_start(GTK_BOX(vbox), viewport_running, TRUE, TRUE, 3);
1924
1925 hbox_buttons = gtk_hbox_new(TRUE, 0);
1926 gtk_box_pack_start(GTK_BOX(vbox), hbox_buttons, FALSE, TRUE, 3);
1927
1928 remove_button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
1929 g_signal_connect(remove_button, "clicked", G_CALLBACK(remove_clicked), NULL);
1930 gtk_box_pack_start(GTK_BOX(hbox_buttons), remove_button, TRUE, TRUE, 0);
1931
1932 conf_button = gui_stock_label_button(_("_Configure"), GTK_STOCK_PREFERENCES);
1933 g_signal_connect(conf_button, "clicked", G_CALLBACK(conf_clicked), NULL);
1934 gtk_box_pack_start(GTK_BOX(hbox_buttons), conf_button, TRUE, TRUE, 0);
1935
1936 scrolled_win_running = gtk_scrolled_window_new(NULL, NULL);
1937 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win_running),
1938 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1939 gtk_container_add(GTK_CONTAINER(viewport_running), scrolled_win_running);
1940
1941 /* create store of running plugins */
1942 if (!running_store) {
1943 running_store = gtk_list_store_new(2,
1944 G_TYPE_STRING, /* Name */
1945 G_TYPE_POINTER); /* instance */
1946
1947 g_signal_connect(G_OBJECT(running_store), "row_inserted",
1948 G_CALLBACK(running_list_row_inserted), NULL);
1949 }
1950
1951 running_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(running_store));
1952 gtk_widget_set_size_request(running_list, 200, 300);
1953 gtk_container_add(GTK_CONTAINER(scrolled_win_running), running_list);
1954
1955 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(running_list), TRUE);
1956 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(running_list), TRUE);
1957
1958 g_signal_connect(G_OBJECT(running_list), "key_press_event",
1959 G_CALLBACK(running_list_key_pressed), NULL);
1960 g_signal_connect(G_OBJECT(running_list), "button_press_event",
1961 G_CALLBACK(running_list_button_pressed), NULL);
1962
1963
1964 running_select = gtk_tree_view_get_selection(GTK_TREE_VIEW(running_list));
1965 gtk_tree_selection_set_mode(running_select, GTK_SELECTION_SINGLE);
1966
1967 renderer = gtk_cell_renderer_text_new();
1968 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1969
1970 column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", 0, NULL);
1971 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
1972 gtk_tree_view_append_column(GTK_TREE_VIEW(running_list), column);
1973
1974 /* running plugins menu */
1975
1976 rp_menu = gtk_menu_new();
1977
1978 rp__enable_all = gtk_menu_item_new_with_label(_("Enable all plugins"));
1979 rp__disable_all = gtk_menu_item_new_with_label(_("Disable all plugins"));
1980 rp__separator1 = gtk_separator_menu_item_new();
1981 rp__toggle_all = gtk_menu_item_new_with_label(_("Invert current state"));
1982 rp__separator2 = gtk_separator_menu_item_new();
1983 rp__clear_list = gtk_menu_item_new_with_label(_("Clear list"));
1984
1985 gtk_menu_shell_append(GTK_MENU_SHELL(rp_menu), rp__enable_all);
1986 gtk_menu_shell_append(GTK_MENU_SHELL(rp_menu), rp__disable_all);
1987 gtk_menu_shell_append(GTK_MENU_SHELL(rp_menu), rp__separator1);
1988 gtk_menu_shell_append(GTK_MENU_SHELL(rp_menu), rp__toggle_all);
1989 gtk_menu_shell_append(GTK_MENU_SHELL(rp_menu), rp__separator2);
1990 gtk_menu_shell_append(GTK_MENU_SHELL(rp_menu), rp__clear_list);
1991
1992 g_signal_connect_swapped(G_OBJECT(rp__enable_all), "activate", G_CALLBACK(rp__enable_all_cb), NULL);
1993 g_signal_connect_swapped(G_OBJECT(rp__disable_all), "activate", G_CALLBACK(rp__disable_all_cb), NULL);
1994 g_signal_connect_swapped(G_OBJECT(rp__toggle_all), "activate", G_CALLBACK(rp__toggle_all_cb), NULL);
1995 g_signal_connect_swapped(G_OBJECT(rp__clear_list), "activate", G_CALLBACK(rp__clear_list_cb), NULL);
1996
1997 gtk_widget_show(rp__enable_all);
1998 gtk_widget_show(rp__disable_all);
1999 gtk_widget_show(rp__separator1);
2000 gtk_widget_show(rp__toggle_all);
2001 gtk_widget_show(rp__separator2);
2002 gtk_widget_show(rp__clear_list);
2003
2004 }
2005
2006
2007 void
save_plugin_data(void)2008 save_plugin_data(void) {
2009
2010 int i = 0;
2011 int k;
2012 GtkTreeIter iter;
2013 gpointer gp_instance;
2014 plugin_instance * instance;
2015 xmlDocPtr doc;
2016 xmlNodePtr root;
2017 xmlNodePtr plugin_node;
2018 xmlNodePtr port_node;
2019 int c, d;
2020 FILE * fin;
2021 FILE * fout;
2022 char tmpname[MAXLEN];
2023 char plugin_file[MAXLEN];
2024 char str[32];
2025
2026
2027 sprintf(plugin_file, "%s/plugin.xml", options.confdir);
2028
2029 doc = xmlNewDoc((const xmlChar*) "1.0");
2030 root = xmlNewNode(NULL, (const xmlChar*) "aqualung_plugin");
2031 xmlDocSetRootElement(doc, root);
2032
2033 while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(running_store), &iter, NULL, i)) {
2034
2035 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 1, &gp_instance, -1);
2036 instance = (plugin_instance *) gp_instance;
2037
2038 plugin_node = xmlNewTextChild(root, NULL, (const xmlChar*) "plugin", NULL);
2039
2040 xmlNewTextChild(plugin_node, NULL, (const xmlChar*) "filename", (xmlChar*) instance->filename);
2041
2042 snprintf(str, 31, "%d", instance->index);
2043 xmlNewTextChild(plugin_node, NULL, (const xmlChar*) "index", (xmlChar*) str);
2044
2045 snprintf(str, 31, "%d", instance->is_bypassed);
2046 xmlNewTextChild(plugin_node, NULL, (const xmlChar*) "is_bypassed", (xmlChar*) str);
2047
2048 for (k = 0; k < MAX_KNOBS && k < instance->descriptor->PortCount; ++k) {
2049
2050 if (!LADSPA_IS_PORT_CONTROL(instance->descriptor->PortDescriptors[k]))
2051 continue;
2052 if (LADSPA_IS_PORT_OUTPUT(instance->descriptor->PortDescriptors[k]))
2053 continue;
2054
2055 port_node = xmlNewTextChild(plugin_node, NULL, (const xmlChar*) "port", NULL);
2056
2057 snprintf(str, 31, "%d", k);
2058 xmlNewTextChild(port_node, NULL, (const xmlChar*) "index", (xmlChar*) str);
2059
2060 snprintf(str, 31, "%f", instance->knobs[k]);
2061 xmlNewTextChild(port_node, NULL, (const xmlChar*) "value", (xmlChar*) str);
2062 }
2063 ++i;
2064 }
2065
2066 sprintf(tmpname, "%s/plugin.xml.temp", options.confdir);
2067 xmlSaveFormatFile(tmpname, doc, 1);
2068 xmlFreeDoc(doc);
2069
2070 if ((fin = fopen(plugin_file, "rt")) == NULL) {
2071 fprintf(stderr, "Error opening file: %s\n", plugin_file);
2072 return;
2073 }
2074 if ((fout = fopen(tmpname, "rt")) == NULL) {
2075 fprintf(stderr, "Error opening file: %s\n", tmpname);
2076 return;
2077 }
2078
2079 c = 0; d = 0;
2080 while (((c = fgetc(fin)) != EOF) && ((d = fgetc(fout)) != EOF)) {
2081 if (c != d) {
2082 fclose(fin);
2083 fclose(fout);
2084 unlink(plugin_file);
2085 rename(tmpname, plugin_file);
2086 return;
2087 }
2088 }
2089
2090 fclose(fin);
2091 fclose(fout);
2092 unlink(tmpname);
2093 }
2094
2095
2096 void
parse_plugin(xmlDocPtr doc,xmlNodePtr cur)2097 parse_plugin(xmlDocPtr doc, xmlNodePtr cur) {
2098
2099 xmlChar * key;
2100 int k;
2101 char filename[MAXLEN];
2102 int index = -1;
2103 int is_bypassed;
2104 GtkTreeIter running_iter;
2105 plugin_instance * instance = NULL;
2106 char bypassed_name[MAXLEN];
2107 LADSPA_Data knobs[MAX_KNOBS];
2108
2109 filename[0] = '\0';
2110
2111 cur = cur->xmlChildrenNode;
2112 while (cur != NULL) {
2113 if ((!xmlStrcmp(cur->name, (const xmlChar *)"filename"))) {
2114 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
2115 if (key != NULL)
2116 strncpy(filename, (char *) key, MAXLEN-1);
2117 xmlFree(key);
2118 if (filename[0] == '\0') {
2119 fprintf(stderr, "Error in XML aqualung_plugin: "
2120 "plugin <filename> is required, but NULL\n");
2121 }
2122 } else if ((!xmlStrcmp(cur->name, (const xmlChar *)"index"))) {
2123 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
2124 if (key != NULL)
2125 sscanf((char *) key, "%d", &index);
2126 xmlFree(key);
2127 } else if ((!xmlStrcmp(cur->name, (const xmlChar *)"is_bypassed"))) {
2128 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
2129 if (key != NULL)
2130 sscanf((char *) key, "%d", &is_bypassed);
2131 xmlFree(key);
2132 } else if ((!xmlStrcmp(cur->name, (const xmlChar *)"port"))) {
2133 int port_index = -1;
2134 float port_value = 0.0f;
2135 xmlNodePtr port_node = cur->xmlChildrenNode;
2136
2137 while (port_node != NULL) {
2138 if ((!xmlStrcmp(port_node->name, (const xmlChar *)"index"))) {
2139 key = xmlNodeListGetString(doc, port_node->xmlChildrenNode, 1);
2140 if (key != NULL)
2141 sscanf((char *) key, "%d", &port_index);
2142 xmlFree(key);
2143 } else if ((!xmlStrcmp(port_node->name, (const xmlChar *)"value"))) {
2144 key = xmlNodeListGetString(doc, port_node->xmlChildrenNode, 1);
2145 if (key != NULL)
2146 sscanf((char *) key, "%f", &port_value);
2147 xmlFree(key);
2148 }
2149 port_node = port_node->next;
2150 }
2151
2152 if ((port_index >= 0) && (port_index < MAX_KNOBS)) {
2153 knobs[port_index] = port_value;
2154 }
2155 }
2156 cur = cur->next;
2157 }
2158
2159
2160 if ((filename[0] != '\0') && (index >= 0)) { /* create plugin, restore settings */
2161
2162 if (n_plugins >= MAX_PLUGINS) {
2163 fprintf(stderr,
2164 "Maximum number of running plugin instances (%d) reached; "
2165 "cannot add more.\n", MAX_PLUGINS);
2166 return;
2167 }
2168 instance = instantiate(filename, index);
2169 if (instance) {
2170 connect_port(instance);
2171 activate(instance);
2172 for (k = 0; k < MAX_KNOBS && k < instance->descriptor->PortCount; ++k) {
2173 if (!LADSPA_IS_PORT_CONTROL(instance->descriptor->PortDescriptors[k]))
2174 continue;
2175 if (LADSPA_IS_PORT_OUTPUT(instance->descriptor->PortDescriptors[k]))
2176 continue;
2177 instance->knobs[k] = knobs[k];
2178 }
2179 instance->is_restored = 1;
2180 instance->is_bypassed = is_bypassed;
2181 build_plugin_window(instance);
2182
2183 get_bypassed_name(instance, bypassed_name);
2184 added_plugin = 1; /* so resort handler will not do any harm */
2185 gtk_list_store_append(running_store, &running_iter);
2186 gtk_list_store_set(running_store, &running_iter,
2187 0, bypassed_name, 1, (gpointer)instance, -1);
2188
2189 refresh_plugin_vect(1);
2190 }
2191 }
2192 return;
2193 }
2194
2195
2196 void
load_plugin_data(void)2197 load_plugin_data(void) {
2198
2199 xmlDocPtr doc;
2200 xmlNodePtr cur;
2201 xmlNodePtr root;
2202 char plugin_file[MAXLEN];
2203 FILE * f;
2204
2205 sprintf(plugin_file, "%s/plugin.xml", options.confdir);
2206
2207 if ((f = fopen(plugin_file, "rt")) == NULL) {
2208 fprintf(stderr, "No plugin.xml -- creating empty one: %s\n", plugin_file);
2209 doc = xmlNewDoc((const xmlChar*) "1.0");
2210 root = xmlNewNode(NULL, (const xmlChar*) "aqualung_plugin");
2211 xmlDocSetRootElement(doc, root);
2212 xmlSaveFormatFile(plugin_file, doc, 1);
2213 xmlFreeDoc(doc);
2214 return;
2215 }
2216 fclose(f);
2217
2218 doc = xmlParseFile(plugin_file);
2219 if (doc == NULL) {
2220 fprintf(stderr, "An XML error occured while parsing %s\n", plugin_file);
2221 return;
2222 }
2223
2224 cur = xmlDocGetRootElement(doc);
2225 if (cur == NULL) {
2226 fprintf(stderr, "load_config: empty XML document\n");
2227 xmlFreeDoc(doc);
2228 return;
2229 }
2230
2231 if (xmlStrcmp(cur->name, (const xmlChar *)"aqualung_plugin")) {
2232 fprintf(stderr,
2233 "load_config: XML document of the wrong type, "
2234 "root node != aqualung_plugin\n");
2235 xmlFreeDoc(doc);
2236 return;
2237 }
2238
2239 cur = cur->xmlChildrenNode;
2240 while (cur != NULL) {
2241 if ((!xmlStrcmp(cur->name, (const xmlChar *)"plugin"))) {
2242 parse_plugin(doc, cur);
2243 }
2244 cur = cur->next;
2245 }
2246
2247 xmlFreeDoc(doc);
2248 return;
2249 }
2250
2251
2252 // vim: shiftwidth=8:tabstop=8:softtabstop=8 :
2253
2254