comparison src/Effect/ladspa/ladspa.c @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children 248c90003c84
comparison
equal deleted inserted replaced
-1:000000000000 0:13389e613d67
1 /* xmms_ladspa - use LADSPA plugins from XMMS
2 Copyright (C) 2002,2003 Nick Lamb <njl195@zepler.org.uk>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /* BMP-ladspa port by Giacomo Lozito <city_hunter@users.sf.net> */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <float.h>
25 #include <dlfcn.h>
26 #include <dirent.h>
27 #include <sys/types.h>
28 #include <gtk/gtk.h>
29
30 #include <audacious/plugin.h>
31 #include <libaudacious/configdb.h>
32
33 #include "../../../config.h"
34 #include "ladspa.h"
35
36 #ifndef PATH_MAX
37 #define PATH_MAX 4096
38 #endif
39
40 #define PLUGIN_NAME "LADSPA host " PACKAGE_VERSION
41
42 #define MAX_SAMPLES 8192
43 #define MAX_KNOBS 64
44
45 typedef struct {
46 char *name;
47 char *filename;
48 long int id;
49 long int unique_id;
50 gboolean stereo;
51 } ladspa_plugin;
52
53 typedef struct {
54 void *library;
55 char *filename;
56 gboolean stereo;
57 gboolean restored;
58 const LADSPA_Descriptor *descriptor;
59 LADSPA_Handle *handle; /* left or mono */
60 LADSPA_Handle *handle2; /* right stereo */
61 GtkWidget *window;
62 guint timeout;
63 GtkAdjustment *adjustments[MAX_KNOBS];
64 LADSPA_Data knobs[MAX_KNOBS];
65 } plugin_instance;
66
67 static void start (void);
68 static void stop (void);
69 static int apply_effect (gpointer *d, gint length, AFormat afmt,
70 gint srate, gint nch);
71 static void configure(void);
72
73 static void restore (void);
74 static plugin_instance * add_plugin (ladspa_plugin *plugin);
75 static void find_all_plugins(void);
76 static void find_plugins(char *path_entry);
77 static ladspa_plugin *get_plugin_by_id(long id);
78 static plugin_instance * load (char *filename, long int num);
79 static void reboot_plugins (void);
80 static void boot_plugin (plugin_instance *instance);
81 static void port_assign(plugin_instance *instance);
82 static void shutdown (plugin_instance *instance);
83 static void unload (plugin_instance *instance);
84
85 static GtkWidget * make_plugin_clist(void);
86 static void make_run_clist(void);
87 static void sort_column(GtkCList *clist, gint column, gpointer user_data);
88 static void select_plugin(GtkCList *clist, gint row, gint column,
89 GdkEventButton *event, gpointer user_data);
90 static void unselect_plugin(GtkCList *clist, gint row, gint column,
91 GdkEventButton *event, gpointer user_data);
92 static void add_plugin_clicked (GtkButton *button, gpointer user_data);
93 static void remove_plugin_clicked (GtkButton *button, gpointer user_data);
94 static void configure_plugin_clicked (GtkButton *button, gpointer user_data);
95
96 static void draw_plugin(plugin_instance *instance);
97
98 static LADSPA_Data left[MAX_SAMPLES], right[MAX_SAMPLES], trash[MAX_SAMPLES];
99
100 G_LOCK_DEFINE_STATIC(running_plugins);
101
102 static GSList *plugin_list, *running_plugins;
103
104 static ladspa_plugin * selected_plugin;
105 static plugin_instance * selected_instance;
106
107 static struct {
108 AFormat afmt;
109 gint srate;
110 gint nch;
111 gboolean ignore;
112 gboolean running;
113 gboolean initialised;
114 } state = { 0, 0, 0, FALSE, FALSE, FALSE};
115
116 static GtkWidget *config_window = NULL, *run_clist = NULL;
117
118 static EffectPlugin xmms_plugin = {
119 NULL, NULL,
120 PLUGIN_NAME,
121 start,
122 stop,
123 NULL,
124 configure,
125 apply_effect,
126 NULL
127 };
128
129 EffectPlugin *get_eplugin_info (void)
130 {
131 return &xmms_plugin;
132 }
133
134 static void start (void)
135 {
136 if (state.initialised == FALSE) {
137 restore();
138 } else if (state.srate > 0) {
139 reboot_plugins();
140 }
141 state.running = TRUE;
142 }
143
144 static void restore (void)
145 {
146 ConfigDb *db;
147 gint k, plugins= 0;
148
149 db = bmp_cfg_db_open();
150
151 bmp_cfg_db_get_int(db, "ladspa", "plugins", &plugins);
152 for (k= 0; k < plugins; ++k) {
153 gint id;
154 int port, ports= 0;
155 plugin_instance *instance;
156 gchar *section = g_strdup_printf("ladspa_plugin%d", k);
157
158 bmp_cfg_db_get_int(db, section, "id", &id);
159 instance = add_plugin(get_plugin_by_id(id));
160 if (!instance) continue; /* couldn't load this plugin */
161 bmp_cfg_db_get_int(db, section, "ports", &ports);
162 for (port= 0; port < ports && port < MAX_KNOBS; ++port) {
163 gchar *key = g_strdup_printf("port%d", port);
164 bmp_cfg_db_get_float(db, section, key, &(instance->knobs[port]));
165 }
166 instance->restored = TRUE;
167 g_free(section);
168 }
169
170 state.initialised = TRUE;
171 bmp_cfg_db_close(db);
172 }
173
174 static ladspa_plugin *get_plugin_by_id(long id)
175 {
176 GSList *list;
177 ladspa_plugin *plugin;
178
179 if (plugin_list == NULL) {
180 find_all_plugins();
181 }
182
183 for (list= plugin_list; list != NULL; list = g_slist_next(list)) {
184 plugin = (ladspa_plugin *) list->data;
185 if (plugin->unique_id == id) {
186 return plugin;
187 }
188 }
189
190 return NULL;
191 }
192
193 static void find_all_plugins (void)
194 {
195 char *ladspa_path, *directory;
196
197 plugin_list = NULL; /* empty list */
198 ladspa_path= getenv("LADSPA_PATH");
199 if (ladspa_path == NULL) {
200 /* Fallback, look in obvious places */
201 find_plugins("/usr/lib/ladspa");
202 find_plugins("/usr/local/lib/ladspa");
203 } else {
204 ladspa_path = g_strdup(ladspa_path);
205
206 directory = strtok(ladspa_path, ":");
207 while (directory != NULL) {
208 find_plugins(directory);
209 directory = strtok(NULL, ":");
210 }
211 g_free(ladspa_path);
212 }
213 }
214
215 static plugin_instance * load (char *filename, long int num)
216 {
217 LADSPA_Descriptor_Function descriptor_fn;
218 plugin_instance *instance;
219
220 instance = g_new0(plugin_instance, 1);
221
222 instance->filename = filename;
223 instance->library = dlopen(filename, RTLD_NOW);
224 if (instance->library == NULL) {
225 g_free(instance);
226 return NULL;
227 }
228 descriptor_fn = dlsym(instance->library, "ladspa_descriptor");
229 if (descriptor_fn == NULL) {
230 g_free(instance);
231 return NULL;
232 }
233 instance->descriptor = descriptor_fn(num);
234
235 return instance;
236 }
237
238 static void unload (plugin_instance * instance)
239 {
240 if (instance->window) {
241 gtk_widget_destroy(instance->window);
242 instance->window = NULL;
243 }
244
245 if (instance->timeout) {
246 gtk_timeout_remove(instance->timeout);
247 }
248
249 shutdown(instance);
250
251 if (instance->library) {
252 dlclose(instance->library);
253 }
254 }
255
256 static void stop (void)
257 {
258 GSList *list;
259 ConfigDb *db;
260 gint plugins = 0;
261
262 if (state.running == FALSE) {
263 return;
264 }
265 state.running = FALSE;
266 db = bmp_cfg_db_open();
267 G_LOCK (running_plugins);
268 for (list= running_plugins; list != NULL; list = g_slist_next(list)) {
269 plugin_instance *instance = (plugin_instance *) list->data;
270 gchar *section = g_strdup_printf("ladspa_plugin%d", plugins++);
271 int port, ports= 0;
272
273 bmp_cfg_db_set_int(db, section, "id", instance->descriptor->UniqueID);
274 bmp_cfg_db_set_string(db, section, "file", instance->filename);
275 bmp_cfg_db_set_string(db, section, "label", (gchar *)
276 instance->descriptor->Label);
277
278 ports = instance->descriptor->PortCount;
279 if (ports > MAX_KNOBS) ports = MAX_KNOBS;
280 for (port= 0; port < ports; ++port) {
281 gchar *key = g_strdup_printf("port%d", port);
282 bmp_cfg_db_set_float(db, section, key, instance->knobs[port]);
283 g_free(key);
284 }
285 bmp_cfg_db_set_int(db, section, "ports", ports);
286 g_free(section);
287 shutdown (instance);
288 }
289 G_UNLOCK (running_plugins);
290
291 bmp_cfg_db_set_int(db, "ladspa", "plugins", plugins);
292 bmp_cfg_db_close(db);
293 }
294
295 static void shutdown (plugin_instance *instance)
296 {
297 const LADSPA_Descriptor * descriptor= instance->descriptor;
298
299 if (instance->handle) {
300 if (descriptor->deactivate) {
301 descriptor->deactivate(instance->handle);
302 }
303 descriptor->cleanup(instance->handle);
304 instance->handle = NULL;
305 }
306 if (instance->handle2) {
307 if (descriptor->deactivate) {
308 descriptor->deactivate(instance->handle2);
309 }
310 descriptor->cleanup(instance->handle2);
311 instance->handle2 = NULL;
312 }
313 }
314
315 static void boot_plugin (plugin_instance *instance)
316 {
317 const LADSPA_Descriptor * descriptor = instance->descriptor;
318
319 shutdown(instance);
320 instance->handle = descriptor->instantiate(descriptor, state.srate);
321 if (state.nch > 1 && !instance->stereo) {
322 /* Create an additional instance */
323 instance->handle2 = descriptor->instantiate(descriptor, state.srate);
324 }
325
326 port_assign(instance);
327
328 if (descriptor->activate) {
329 descriptor->activate(instance->handle);
330 if (instance->handle2) {
331 descriptor->activate(instance->handle2);
332 }
333 }
334 }
335
336 static void reboot_plugins (void)
337 {
338 GSList *list;
339
340 G_LOCK (running_plugins);
341 for (list= running_plugins; list != NULL; list = g_slist_next(list)) {
342 boot_plugin ((plugin_instance *) list->data);
343 }
344 G_UNLOCK (running_plugins);
345 }
346
347 static int apply_effect (gpointer *d, gint length, AFormat afmt,
348 gint srate, gint nch)
349 {
350 gint16 *raw16 = *d;
351 GSList *list;
352 plugin_instance *instance;
353 int k;
354
355 if (running_plugins == NULL || state.running == FALSE) {
356 return length;
357 }
358
359 if (state.afmt != afmt || state.srate != srate || state.nch != nch) {
360 state.afmt = afmt;
361 state.srate = srate;
362 state.nch = nch;
363
364 if (nch < 1 || nch > 2)
365 state.ignore = 1;
366 else if (afmt == FMT_S16_NE)
367 state.ignore = 0;
368 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
369 else if (afmt == FMT_S16_LE)
370 state.ignore = 0;
371 #elif G_BYTE_ORDER == G_BIG_ENDIAN
372 else if (afmt == FMT_S16_BE)
373 state.ignore = 0;
374 #endif
375 else
376 state.ignore = 1;
377
378 reboot_plugins();
379 }
380
381 if (state.ignore || length > MAX_SAMPLES * 2) {
382 return length;
383 }
384
385 if (state.nch == 1) {
386 for (k= 0; k < length / 2; ++k) {
387 left[k] = ((LADSPA_Data) raw16[k]) * (1.0f / 32768.0f);
388 }
389 G_LOCK (running_plugins);
390 for (list= running_plugins; list != NULL; list = g_slist_next(list)) {
391 instance = (plugin_instance *) list->data;
392 if (instance->handle) {
393 instance->descriptor->run(instance->handle, length / 2);
394 }
395 }
396 G_UNLOCK (running_plugins);
397 for (k= 0; k < length / 2; ++k) {
398 raw16[k] = CLAMP((int) (left[k] * 32768.0f), -32768, 32767);
399 }
400 } else {
401 for (k= 0; k < length / 2; k += 2) {
402 left[k/2] = ((LADSPA_Data) raw16[k]) * (1.0f / 32768.0f);
403 }
404 for (k= 1; k < length / 2; k += 2) {
405 right[k/2] = ((LADSPA_Data) raw16[k]) * (1.0f / 32768.0f);
406 }
407 G_LOCK (running_plugins);
408 for (list= running_plugins; list != NULL; list = g_slist_next(list)) {
409 instance = (plugin_instance *) list->data;
410 if (instance->handle) {
411 instance->descriptor->run(instance->handle, length / 4);
412 }
413 if (instance->handle2) {
414 instance->descriptor->run(instance->handle2, length / 4);
415 }
416 }
417 G_UNLOCK (running_plugins);
418 for (k= 0; k < length / 2; k += 2) {
419 raw16[k] = CLAMP((int) (left[k/2] * 32768.0f), -32768, 32767);
420 }
421 for (k= 1; k < length / 2; k += 2) {
422 raw16[k] = CLAMP((int) (right[k/2] * 32768.0f), -32768, 32767);
423 }
424 }
425
426 return length;
427 }
428
429 static void port_assign(plugin_instance * instance) {
430 unsigned long port;
431 unsigned long inputs= 0, outputs= 0;
432 const LADSPA_Descriptor * plugin = instance->descriptor;
433
434 for (port = 0; port < plugin->PortCount; ++port) {
435
436 if (LADSPA_IS_PORT_CONTROL(plugin->PortDescriptors[port])) {
437 if (port < MAX_KNOBS) {
438 plugin->connect_port(instance->handle, port, &(instance->knobs[port]));
439 if (instance->handle2)
440 plugin->connect_port(instance->handle2, port, &(instance->knobs[port]));
441 } else {
442 plugin->connect_port(instance->handle, port, trash);
443 if (instance->handle2)
444 plugin->connect_port(instance->handle2, port, trash);
445 }
446
447 } else if (LADSPA_IS_PORT_AUDIO(plugin->PortDescriptors[port])) {
448
449 if (LADSPA_IS_PORT_INPUT(plugin->PortDescriptors[port])) {
450 if (inputs == 0) {
451 plugin->connect_port(instance->handle, port, left);
452 if (instance->handle2)
453 plugin->connect_port(instance->handle2, port, right);
454 } else if (inputs == 1 && instance->stereo) {
455 plugin->connect_port(instance->handle, port, right);
456 } else {
457 plugin->connect_port(instance->handle, port, trash);
458 if (instance->handle2)
459 plugin->connect_port(instance->handle2, port, trash);
460 }
461 inputs++;
462
463 } else if (LADSPA_IS_PORT_OUTPUT(plugin->PortDescriptors[port])) {
464 if (outputs == 0) {
465 plugin->connect_port(instance->handle, port, left);
466 if (instance->handle2)
467 plugin->connect_port(instance->handle2, port, right);
468 } else if (outputs == 1 && instance->stereo) {
469 plugin->connect_port(instance->handle, port, right);
470 } else {
471 plugin->connect_port(instance->handle, port, trash);
472 if (instance->handle2)
473 plugin->connect_port(instance->handle2, port, trash);
474 }
475 outputs++;
476
477 }
478 }
479 }
480
481 }
482
483 static void find_plugins(char *path_entry)
484 {
485 ladspa_plugin *plugin;
486 void *library = NULL;
487 char lib_name[PATH_MAX];
488 LADSPA_Descriptor_Function descriptor_fn;
489 const LADSPA_Descriptor *descriptor;
490 DIR *dir;
491 struct dirent *dirent;
492 long int k;
493 unsigned long int port, input, output;
494
495 dir= opendir(path_entry);
496 if (dir == NULL) return;
497
498 while ((dirent= readdir(dir))) {
499 snprintf(lib_name, PATH_MAX, "%s/%s", path_entry, dirent->d_name);
500 library = dlopen(lib_name, RTLD_LAZY);
501 if (library == NULL) {
502 continue;
503 }
504 descriptor_fn = dlsym(library, "ladspa_descriptor");
505 if (descriptor_fn == NULL) {
506 dlclose(library);
507 continue;
508 }
509
510 for (k= 0;; ++k) {
511 descriptor= descriptor_fn(k);
512 if (descriptor == NULL) {
513 break;
514 }
515 plugin = g_new(ladspa_plugin, 1);
516 plugin->name= g_strdup(descriptor->Name);
517 plugin->filename= g_strdup(lib_name);
518 plugin->id= k;
519 plugin->unique_id= descriptor->UniqueID;
520 for (input = output = port = 0; port < descriptor->PortCount; ++port) {
521 if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[port])) {
522 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port]))
523 input++;
524 if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[port]))
525 output++;
526 } else if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[port])) {
527 }
528 }
529 if (input >= 2 && output >= 2) {
530 plugin->stereo= TRUE;
531 } else {
532 plugin->stereo= FALSE;
533 }
534 plugin_list = g_slist_prepend(plugin_list, plugin);
535 }
536 dlclose(library);
537 }
538
539 closedir(dir);
540 return;
541 }
542
543 static void value_changed(GtkAdjustment *adjustment, gpointer *user_data)
544 {
545 LADSPA_Data *data = (LADSPA_Data *) user_data;
546
547 G_LOCK (running_plugins);
548 *data = (LADSPA_Data) adjustment->value;
549 G_UNLOCK (running_plugins);
550 }
551
552 static void toggled(GtkToggleButton *togglebutton, gpointer *user_data)
553 {
554 LADSPA_Data *data = (LADSPA_Data *) user_data;
555
556 if (gtk_toggle_button_get_active(togglebutton)) {
557 G_LOCK (running_plugins);
558 *data = (LADSPA_Data) 1.0f;
559 G_UNLOCK (running_plugins);
560 } else {
561 G_LOCK (running_plugins);
562 *data = (LADSPA_Data) -1.0f;
563 G_UNLOCK (running_plugins);
564 }
565 }
566
567 static int update_instance (gpointer data)
568 {
569 plugin_instance *instance = (plugin_instance *) data;
570 unsigned long k;
571
572 G_LOCK (running_plugins);
573 for (k = 0; k < MAX_KNOBS && k < instance->descriptor->PortCount; ++k) {
574 if (LADSPA_IS_PORT_OUTPUT(instance->descriptor->PortDescriptors[k])
575 && LADSPA_IS_PORT_CONTROL(instance->descriptor->PortDescriptors[k])) {
576 instance->adjustments[k]->value = instance->knobs[k];
577 gtk_adjustment_value_changed(instance->adjustments[k]);
578 }
579 }
580 G_UNLOCK (running_plugins);
581 return TRUE;
582 }
583
584 static void draw_plugin(plugin_instance *instance)
585 {
586 const LADSPA_Descriptor *plugin = instance->descriptor;
587 const LADSPA_PortRangeHint *hints = plugin->PortRangeHints;
588 LADSPA_Data fact, min, max, step, start;
589 int dp;
590 unsigned long k;
591 gboolean no_ui = TRUE;
592 GtkWidget *widget, *vbox, *hbox;
593 GtkObject *adjustment;
594
595 if (instance->window != NULL) {
596 /* Just show window */
597 gtk_widget_show(instance->window);
598 return;
599 }
600
601 instance->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
602 gtk_window_set_title(GTK_WINDOW(instance->window), plugin->Name);
603
604 vbox= gtk_vbox_new(FALSE, 3);
605
606 for (k = 0; k < MAX_KNOBS && k < plugin->PortCount; ++k) {
607 if (! LADSPA_IS_PORT_CONTROL(plugin->PortDescriptors[k]))
608 continue;
609 no_ui = FALSE;
610 hbox = gtk_hbox_new(FALSE, 3);
611 widget = gtk_label_new(plugin->PortNames[k]);
612 gtk_container_add(GTK_CONTAINER(hbox), widget);
613
614 if (LADSPA_IS_HINT_TOGGLED(hints[k].HintDescriptor)) {
615 widget = gtk_toggle_button_new_with_label("Press");
616 g_signal_connect(G_OBJECT(widget), "toggled",
617 G_CALLBACK(toggled), &(instance->knobs[k]));
618 gtk_container_add(GTK_CONTAINER(hbox), widget);
619 gtk_container_add(GTK_CONTAINER(vbox), hbox);
620 continue;
621 }
622
623 if (LADSPA_IS_HINT_SAMPLE_RATE(hints[k].HintDescriptor)) {
624 fact = state.srate ? state.srate : 44100.0f;
625 } else {
626 fact = 1.0f;
627 }
628
629 if (LADSPA_IS_HINT_BOUNDED_BELOW(hints[k].HintDescriptor)) {
630 min= hints[k].LowerBound * fact;
631 } else {
632 min= -10000.0f;
633 }
634
635 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hints[k].HintDescriptor)) {
636 max= hints[k].UpperBound * fact;
637 } else {
638 max= 10000.0f;
639 }
640
641 /* infinity */
642 if (10000.0f <= max - min) {
643 dp = 1;
644 step = 5.0f;
645
646 /* 100.0 ... lots */
647 } else if (100.0f < max - min) {
648 dp = 0;
649 step = 5.0f;
650
651 /* 10.0 ... 100.0 */
652 } else if (10.0f < max - min) {
653 dp = 1;
654 step = 0.5f;
655
656 /* 1.0 ... 10.0 */
657 } else if (1.0f < max - min) {
658 dp = 2;
659 step = 0.05f;
660
661 /* 0.0 ... 1.0 */
662 } else {
663 dp = 3;
664 step = 0.005f;
665 }
666
667 if (LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
668 dp = 0;
669 if (step < 1.0f) step = 1.0f;
670 }
671
672 if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hints[k].HintDescriptor)) {
673 start = min;
674 } else if (LADSPA_IS_HINT_DEFAULT_LOW(hints[k].HintDescriptor)) {
675 start = min * 0.75f + max * 0.25f;
676 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hints[k].HintDescriptor)) {
677 start = min * 0.5f + max * 0.5f;
678 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hints[k].HintDescriptor)) {
679 start = min * 0.25f + max * 0.75f;
680 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hints[k].HintDescriptor)) {
681 start = max;
682 } else if (LADSPA_IS_HINT_DEFAULT_0(hints[k].HintDescriptor)) {
683 start = 0.0f;
684 } else if (LADSPA_IS_HINT_DEFAULT_1(hints[k].HintDescriptor)) {
685 start = 1.0f;
686 } else if (LADSPA_IS_HINT_DEFAULT_100(hints[k].HintDescriptor)) {
687 start = 100.0f;
688 } else if (LADSPA_IS_HINT_DEFAULT_440(hints[k].HintDescriptor)) {
689 start = 440.0f;
690 } else if (LADSPA_IS_HINT_INTEGER(hints[k].HintDescriptor)) {
691 start = min;
692 } else if (max >= 0.0f && min <= 0.0f) {
693 start = 0.0f;
694 } else {
695 start = min * 0.5f + max * 0.5f;
696 }
697
698 if (instance->restored) {
699 start = instance->knobs[k];
700 } else {
701 instance->knobs[k] = start;
702 }
703 adjustment = gtk_adjustment_new(start, min, max, step, step * 10.0, 0.0);
704 instance->adjustments[k] = GTK_ADJUSTMENT(adjustment);
705 widget = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), step, dp);
706 if (LADSPA_IS_PORT_OUTPUT(plugin->PortDescriptors[k])) {
707 gtk_widget_set_sensitive(widget, FALSE);
708 } else {
709 g_signal_connect(adjustment, "value-changed",
710 G_CALLBACK(value_changed), &(instance->knobs[k]));
711 }
712 gtk_container_add(GTK_CONTAINER(hbox), widget);
713 widget = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
714 gtk_scale_set_digits(GTK_SCALE(widget), dp);
715 if (LADSPA_IS_PORT_OUTPUT(plugin->PortDescriptors[k])) {
716 gtk_widget_set_sensitive(widget, FALSE);
717 }
718 gtk_container_add(GTK_CONTAINER(hbox), widget);
719
720 gtk_container_add(GTK_CONTAINER(vbox), hbox);
721 }
722
723 if (no_ui) {
724 widget = gtk_label_new("This LADSPA plugin has no user controls");
725 gtk_container_add(GTK_CONTAINER(vbox), widget);
726 }
727
728 instance->timeout = gtk_timeout_add(100, update_instance, instance);
729
730 gtk_container_add(GTK_CONTAINER(instance->window), vbox);
731
732 g_signal_connect (G_OBJECT (instance->window), "delete_event",
733 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
734 gtk_widget_show_all(instance->window);
735 }
736
737 static void sort_column(GtkCList *clist, gint column, gpointer user_data)
738 {
739 gtk_clist_set_sort_column(clist, column);
740 gtk_clist_sort(clist);
741 }
742
743 static void unselect_instance(GtkCList *clist, gint row, gint column,
744 GdkEventButton *event, gpointer user_data)
745 {
746 selected_instance= NULL;
747 }
748
749 static void select_instance(GtkCList *clist, gint row, gint column,
750 GdkEventButton *event, gpointer user_data)
751 {
752 selected_instance= (plugin_instance *) gtk_clist_get_row_data(clist, row);
753 }
754
755 static void reorder_instance(GtkCList *clist, gint from, gint to,
756 gpointer user_data)
757 {
758 void *data;
759
760 G_LOCK (running_plugins);
761 data = g_slist_nth_data(running_plugins, from);
762 running_plugins= g_slist_remove(running_plugins, data);
763 running_plugins= g_slist_insert(running_plugins, data, to);
764 G_UNLOCK (running_plugins);
765 }
766
767 static void make_run_clist(void)
768 {
769 char * titles[1] = { "Name" };
770 GSList *list;
771
772 run_clist = gtk_clist_new_with_titles(1, titles);
773 gtk_clist_column_titles_passive(GTK_CLIST (run_clist));
774 gtk_clist_set_reorderable(GTK_CLIST (run_clist), TRUE);
775 g_signal_connect(G_OBJECT(run_clist), "select-row",
776 G_CALLBACK(select_instance), NULL);
777 g_signal_connect(G_OBJECT(run_clist), "unselect-row",
778 G_CALLBACK(unselect_instance), NULL);
779 g_signal_connect(G_OBJECT(run_clist), "row-move",
780 G_CALLBACK(reorder_instance), NULL);
781
782 G_LOCK (running_plugins);
783 for (list= running_plugins; list != NULL; list = g_slist_next(list)) {
784 gint row;
785 gchar *line[1];
786 plugin_instance *instance = (plugin_instance *) list->data;
787
788 line[0] = (char *) instance->descriptor->Name;
789 row = gtk_clist_append(GTK_CLIST (run_clist), line);
790 gtk_clist_set_row_data(GTK_CLIST (run_clist), row, (gpointer) instance);
791 gtk_clist_select_row(GTK_CLIST(run_clist), row, 0);
792 }
793 G_UNLOCK (running_plugins);
794 }
795
796 static plugin_instance * add_plugin (ladspa_plugin *plugin)
797 {
798 plugin_instance *instance;
799 char * line[1];
800 gint row;
801
802 if (plugin == NULL) {
803 return NULL;
804 }
805
806 instance = load(plugin->filename, plugin->id);
807 if (instance == NULL) {
808 return NULL;
809 }
810
811 instance->stereo = plugin->stereo;
812 if (state.srate && state.running) {
813 /* Jump right in */
814 boot_plugin(instance);
815 }
816
817 if (run_clist) {
818 line[0] = (char *) instance->descriptor->Name;
819 row = gtk_clist_append(GTK_CLIST (run_clist), line);
820 gtk_clist_set_row_data(GTK_CLIST (run_clist), row, (gpointer) instance);
821 gtk_clist_select_row(GTK_CLIST(run_clist), row, 0);
822 draw_plugin(instance);
823 }
824 G_LOCK (running_plugins);
825 running_plugins = g_slist_append(running_plugins, instance);
826 G_UNLOCK (running_plugins);
827
828 return instance;
829 }
830
831
832 static void unselect_plugin(GtkCList *clist, gint row, gint column,
833 GdkEventButton *event, gpointer user_data)
834 {
835 selected_plugin= NULL;
836 }
837
838 static void select_plugin(GtkCList *clist, gint row, gint column,
839 GdkEventButton *event, gpointer user_data)
840 {
841 selected_plugin = (ladspa_plugin *) gtk_clist_get_row_data(clist, row);
842 gtk_clist_unselect_all(GTK_CLIST(run_clist));
843 if (event->type == GDK_2BUTTON_PRESS) {
844 /* Double click */
845 add_plugin(selected_plugin);
846 }
847 }
848
849 static GtkWidget * make_plugin_clist(void)
850 {
851 ladspa_plugin *plugin;
852 GSList *list;
853 GtkWidget *clist;
854 char number[14];
855 char * titles[2] = { "UID", "Name" };
856 char * line[2];
857 gint row;
858
859 find_all_plugins();
860
861 clist = gtk_clist_new_with_titles(2, titles);
862 gtk_clist_column_titles_active(GTK_CLIST (clist));
863 gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, TRUE);
864 gtk_clist_set_sort_column(GTK_CLIST (clist), 1);
865
866 for (list= plugin_list; list != NULL; list = g_slist_next(list)) {
867 plugin = (ladspa_plugin *) list->data;
868 snprintf(number, sizeof(number), "%ld", plugin->unique_id);
869 line[0] = number;
870 line[1] = plugin->name;
871 row = gtk_clist_append(GTK_CLIST (clist), line);
872 gtk_clist_set_row_data(GTK_CLIST (clist), row, (gpointer) plugin);
873 }
874 gtk_clist_sort(GTK_CLIST (clist));
875
876 g_signal_connect(G_OBJECT(clist), "click-column",
877 G_CALLBACK(sort_column), NULL);
878 g_signal_connect(G_OBJECT(clist), "select-row",
879 G_CALLBACK(select_plugin), NULL);
880 g_signal_connect(G_OBJECT(clist), "unselect-row",
881 G_CALLBACK(unselect_plugin), NULL);
882
883 return clist;
884 }
885
886 static void add_plugin_clicked (GtkButton *button, gpointer user_data)
887 {
888 add_plugin(selected_plugin);
889 }
890
891 static void remove_plugin_clicked (GtkButton *button, gpointer user_data)
892 {
893 plugin_instance *instance = selected_instance;
894 gint row;
895
896 if (instance == NULL) {
897 return;
898 }
899 row = gtk_clist_find_row_from_data(GTK_CLIST(run_clist), (gpointer) instance);
900 gtk_clist_remove(GTK_CLIST(run_clist), row);
901
902 G_LOCK (running_plugins);
903 running_plugins = g_slist_remove(running_plugins, instance);
904 unload(instance);
905 G_UNLOCK (running_plugins);
906 selected_instance= NULL;
907 }
908
909 static void configure_plugin_clicked (GtkButton *button, gpointer user_data)
910 {
911 if (selected_instance) {
912 draw_plugin(selected_instance);
913 }
914 }
915
916 static void configure(void)
917 {
918 GtkWidget *widget, *vbox, *hbox, *bbox, *frame;
919
920 if (config_window) {
921 /* just show the window */
922 gtk_widget_show(config_window);
923 return;
924 }
925
926 config_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
927 vbox= gtk_vbox_new(FALSE, 0);
928 hbox= gtk_hbox_new(TRUE, 0);
929
930 frame= gtk_frame_new("Installed plugins");
931 widget = gtk_scrolled_window_new(NULL, NULL);
932 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
933 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
934 gtk_container_add(GTK_CONTAINER(widget), make_plugin_clist());
935 gtk_container_add(GTK_CONTAINER(frame), widget);
936 gtk_container_add(GTK_CONTAINER(hbox), frame);
937
938
939 frame= gtk_frame_new("Running plugins");
940 widget = gtk_scrolled_window_new(NULL, NULL);
941 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
942 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
943 if (run_clist == NULL) {
944 make_run_clist();
945 }
946 gtk_container_add(GTK_CONTAINER(widget), run_clist);
947 gtk_container_add(GTK_CONTAINER(frame), widget);
948 gtk_container_add(GTK_CONTAINER(hbox), frame);
949 gtk_container_add(GTK_CONTAINER(vbox), hbox);
950
951 /* Buttons */
952 bbox = gtk_hbutton_box_new();
953 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
954 widget = gtk_button_new_with_label("Add");
955 g_signal_connect(G_OBJECT(widget), "clicked",
956 G_CALLBACK(add_plugin_clicked), NULL);
957 gtk_box_pack_end_defaults(GTK_BOX(bbox), widget);
958 widget = gtk_button_new_with_label("Remove");
959 g_signal_connect(G_OBJECT(widget), "clicked",
960 G_CALLBACK(remove_plugin_clicked), NULL);
961 gtk_box_pack_end_defaults(GTK_BOX(bbox), widget);
962 widget = gtk_button_new_with_label("Configure");
963 g_signal_connect(G_OBJECT(widget), "clicked",
964 G_CALLBACK(configure_plugin_clicked), NULL);
965 gtk_box_pack_end_defaults(GTK_BOX(bbox), widget);
966
967 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
968
969 gtk_container_add(GTK_CONTAINER(config_window), vbox);
970
971 gtk_window_set_title(GTK_WINDOW(config_window), "LADSPA Plugin Catalog");
972 gtk_widget_set_usize(config_window, 380, 400);
973 g_signal_connect (G_OBJECT (config_window), "delete_event",
974 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
975
976 gtk_widget_show_all(config_window);
977 }