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