1 /* FluidSynth DSSI software synthesizer GUI
2  *
3  * Copyright (C) 2004-2008 Sean Bolton and others.
4  *
5  * Portions of this file may have come from FluidSynth, copyright
6  * (C) 2003 Peter Hanappe and others.
7  * Portions of this file may have come from Chris Cannam and Steve
8  * Harris's public domain DSSI example code.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be
16  * useful, but WITHOUT ANY WARRANTY; without even the implied
17  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
18  * PURPOSE.  See the GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public
21  * License along with this program; if not, write to the Free
22  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301 USA.
24  */
25 
26 #define _BSD_SOURCE    1
27 #define _SVID_SOURCE   1
28 #define _ISOC99_SOURCE 1
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <math.h>
40 
41 #include <glib.h>
42 #include <gtk/gtk.h>
43 #include <ladspa.h>
44 #include <dssi.h>
45 #include <lo/lo.h>
46 
47 #include "load_soundfont_metadata.h"
48 
49 /* ==== debugging ==== */
50 
51 /* DSSI interface debugging -- choose one: */
52 #define DEBUG_DSSI(fmt...)
53 // #define DEBUG_DSSI(fmt...) { fprintf(stderr, fmt); }
54 
55 /* audio debugging -- define if desired: */
56 // #define DEBUG_AUDIO
57 
58 /* ==== end of debugging ==== */
59 
60 /* -FIX- These should be in a header file shared with fluidsynth-dssi.c: */
61 #define FSD_MAX_POLYPHONY     256
62 #define FSD_DEFAULT_POLYPHONY 256
63 
64 /* in locate_soundfont.c: */
65 char *fsd_locate_soundfont_file(const char *origpath,
66                                 const char *projectDirectory);
67 
68 char **fsd_get_known_soundfonts(const char *projectDirectory, int *rn);
69 
70 /* forward: */
71 int  load_soundfont(char *filename);
72 void update_from_program_select(int bank, int program);
73 void rebuild_preset_clist(SFData *sfdata);
74 
75 /* ==== global variables ==== */
76 
77 char *     osc_self_url;
78 lo_address osc_host_address;
79 char *     osc_configure_path;
80 char *     osc_control_path;
81 char *     osc_exiting_path;
82 char *     osc_hide_path;
83 char *     osc_midi_path;
84 char *     osc_program_path;
85 char *     osc_quit_path;
86 char *     osc_rate_path;
87 char *     osc_show_path;
88 char *     osc_update_path;
89 
90 SFData *      soundfont_data = NULL;
91 char *        soundfont_filename = NULL;
92 char *        project_directory = NULL;
93 unsigned long preset_count = 0;
94 SFPreset **   presets_by_row = NULL;
95 
96 unsigned char test_note_noteon_key = 60;
97 unsigned char test_note_noteoff_key;
98 unsigned char test_note_velocity = 96;
99 
100 GtkWidget *main_window;
101 GtkWidget *soundfont_label;
102 GtkWidget *preset_clist;
103 GtkObject *gain_adj;
104 #ifdef USE_AUGMENTED_FLUIDSYNTH_API
105 GtkObject *polyphony_adj;
106 #endif
107 GtkWidget *file_selection;
108 GtkWidget *notice_window;
109 GtkWidget *notice_label_1;
110 GtkWidget *notice_label_2;
111 GtkWidget *choose_soundfont_combo;
112 
113 int internal_gui_update_only = 0;
114 int host_requested_quit = 0;
115 int gui_test_mode = 0;
116 
117 /* ==== OSC handling ==== */
118 
119 static char *
osc_build_path(char * base_path,char * method)120 osc_build_path(char *base_path, char *method)
121 {
122     char buffer[256];
123     char *full_path;
124 
125     snprintf(buffer, 256, "%s%s", base_path, method);
126     if (!(full_path = strdup(buffer))) {
127         DEBUG_DSSI("fsd-gui: out of memory!\n");
128         exit(1);
129     }
130     return full_path;
131 }
132 
133 static void
osc_error(int num,const char * msg,const char * path)134 osc_error(int num, const char *msg, const char *path)
135 {
136     DEBUG_DSSI("fsd-gui error: liblo server error %d in path \"%s\": %s\n",
137             num, (path ? path : "(null)"), msg);
138 }
139 
140 int
osc_debug_handler(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * user_data)141 osc_debug_handler(const char *path, const char *types, lo_arg **argv,
142                   int argc, lo_message msg, void *user_data)
143 {
144     int i;
145 
146     DEBUG_DSSI("fsd-gui warning: unhandled OSC message to <%s>:\n", path);
147 
148     for (i = 0; i < argc; ++i) {
149         fprintf(stderr, "arg %d: type '%c': ", i, types[i]);
150 fflush(stderr);
151         lo_arg_pp((lo_type)types[i], argv[i]);  /* -FIX- Ack, mixing stderr and stdout... */
152         fprintf(stdout, "\n");
153 fflush(stdout);
154     }
155 
156     return 1;  /* try any other handlers */
157 }
158 
159 int
osc_action_handler(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * user_data)160 osc_action_handler(const char *path, const char *types, lo_arg **argv,
161                   int argc, lo_message msg, void *user_data)
162 {
163     if (!strcmp(user_data, "show")) {
164 
165         /* DEBUG_DSSI("fsd-gui osc_action_handler: received 'show' message\n"); */
166         if (!GTK_WIDGET_MAPPED(main_window))
167             gtk_widget_show(main_window);
168         else
169             gdk_window_raise(main_window->window);
170 
171     } else if (!strcmp(user_data, "hide")) {
172 
173         /* DEBUG_DSSI("fsd-gui osc_action_handler: received 'hide' message\n"); */
174         gtk_widget_hide(main_window);
175 
176     } else if (!strcmp(user_data, "quit")) {
177 
178         /* DEBUG_DSSI("fsd-gui osc_action_handler: received 'quit' message\n"); */
179         host_requested_quit = 1;
180         gtk_main_quit();
181 
182     } else if (!strcmp(user_data, "sample-rate")) {
183 
184         /* DEBUG_DSSI("fsd-gui osc_action_handler: received 'sample-rate' message, rate is %d\n", argv[0]->i); */
185         /* ignore it */
186 
187     } else {
188 
189         return osc_debug_handler(path, types, argv, argc, msg, user_data);
190 
191     }
192     return 0;
193 }
194 
195 int
osc_configure_handler(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * user_data)196 osc_configure_handler(const char *path, const char *types, lo_arg **argv,
197                   int argc, lo_message msg, void *user_data)
198 {
199     if (argc < 2) {
200         DEBUG_DSSI("fsd-gui error: too few arguments to osc_configure_handler\n");
201         return 1;
202     }
203 
204     if (!strcmp(&argv[0]->s, "load")) {
205 
206         char *path = fsd_locate_soundfont_file(&argv[1]->s, project_directory);
207         int result = 0;
208 
209         if (path) {
210             internal_gui_update_only = 1;
211             result = load_soundfont(path);
212             internal_gui_update_only = 0;
213         }
214 
215         if (!path || !result) {
216             DEBUG_DSSI("fsd-gui osc_configure_handler: load_soundfont() failed!\n");
217             gtk_label_set_text (GTK_LABEL (notice_label_1), "Unable to load the soundfont requested by the host!");
218             gtk_label_set_text (GTK_LABEL (notice_label_2), &argv[1]->s);
219             gtk_widget_show(notice_window);
220         }
221         /* Note: if SF2_PATH or the project directory was used to find the
222          * soundfont, this does not inform the user here (other than the path
223          * widget displaying the substituted path), because the plugin has
224          * probably passed an error to the host stating the same thing. */
225 
226         if (path) free(path);
227 
228         return 0;
229 
230     } else if (!strcmp(&argv[0]->s, DSSI_GLOBAL_CONFIGURE_PREFIX "gain")) {
231 
232         float new_gain = atof(&argv[1]->s);
233 
234         if (new_gain <= 0.0f) {
235             return 0;  /* gain out of range */
236         }
237         new_gain = log10f(new_gain) * 20.0f;
238         if (new_gain < -96.0f)
239             new_gain = -96.0f;
240         else if (new_gain > 20.0f)
241             new_gain = 20.0f;
242 
243         internal_gui_update_only = 1;
244 
245         GTK_ADJUSTMENT(gain_adj)->value = new_gain;
246         gtk_signal_emit_by_name (GTK_OBJECT (gain_adj), "value_changed");  /* causes call to on_gain_slider_change */
247 
248         internal_gui_update_only = 0;
249 
250         return 0;
251 
252 #ifdef USE_AUGMENTED_FLUIDSYNTH_API
253     } else if (!strcmp(&argv[0]->s, DSSI_GLOBAL_CONFIGURE_PREFIX "polyphony")) {
254 
255         int new_poly = atol(&argv[1]->s);
256 
257         if (new_poly < 1 || new_poly > FSD_MAX_POLYPHONY) {
258             return 0;  /* polyphony out of range */
259         }
260 
261         internal_gui_update_only = 1;
262 
263         GTK_ADJUSTMENT(polyphony_adj)->value = new_poly;
264         gtk_signal_emit_by_name (GTK_OBJECT (polyphony_adj), "value_changed");  /* causes call to on_polyphony_slider_change */
265 
266         internal_gui_update_only = 0;
267 
268         return 0;
269 #endif
270 
271     } else if (!strcmp(&argv[0]->s, DSSI_PROJECT_DIRECTORY_KEY)) {
272 
273         if (project_directory)
274             free(project_directory);
275         project_directory = strdup(&argv[1]->s);
276 
277 	return 0;
278 
279     } else {
280 
281         return osc_debug_handler(path, types, argv, argc, msg, user_data);
282 
283     }
284 }
285 
286 int
osc_control_handler(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * user_data)287 osc_control_handler(const char *path, const char *types, lo_arg **argv,
288                   int argc, lo_message msg, void *user_data)
289 {
290     /* though for now, we have no controls to handle.... */
291     int port;
292     float value;
293 
294     if (argc < 2) {
295         DEBUG_DSSI("fsd-gui error: too few arguments to osc_control_handler\n");
296         return 1;
297     }
298 
299     port = argv[0]->i;
300     value = argv[1]->f;
301 
302     DEBUG_DSSI("fsd-gui osc_control_handler: (bogus) control %d now %f\n", port, value);
303 
304     /* update_voice_widget(port, value); */
305 
306     return 0;
307 }
308 
309 int
osc_program_handler(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * user_data)310 osc_program_handler(const char *path, const char *types, lo_arg **argv,
311                   int argc, lo_message msg, void *user_data)
312 {
313     int bank, program;
314 
315     if (argc < 2) {
316         DEBUG_DSSI("fsd-gui error: too few arguments to osc_program_handler\n");
317         return 1;
318     }
319 
320     bank = argv[0]->i;
321     program = argv[1]->i;
322 
323     if (bank < 0 || bank > 16383 || program < 0 || program > 127) {
324         DEBUG_DSSI("fsd-gui: out-of-range program select (bank %d, program %d)\n", bank, program);
325         return 0;
326     }
327 
328     DEBUG_DSSI("fsd-gui osc_program_handler: received program change, bank %d, program %d\n", bank, program);
329 
330     update_from_program_select(bank, program);
331 
332     return 0;
333 }
334 
335 void
osc_data_on_socket_callback(gpointer data,gint source,GdkInputCondition condition)336 osc_data_on_socket_callback(gpointer data, gint source,
337                             GdkInputCondition condition)
338 {
339     lo_server server = (lo_server)data;
340 
341     lo_server_recv_noblock(server, 0);
342 }
343 
344 gint
update_request_timeout_callback(gpointer data)345 update_request_timeout_callback(gpointer data)
346 {
347     if (!gui_test_mode) {
348 
349         /* send our update request */
350         lo_send(osc_host_address, osc_update_path, "s", osc_self_url);
351 
352     } else {
353 
354         gtk_widget_show(main_window);
355 
356     }
357 
358     return FALSE;  /* don't need to do this again */
359 }
360 
361 /* ==== GTK+ widget callbacks ==== */
362 
363 gint
on_delete_event_wrapper(GtkWidget * widget,GdkEvent * event,gpointer data)364 on_delete_event_wrapper( GtkWidget *widget, GdkEvent *event, gpointer data )
365 {
366     void (*handler)(GtkWidget *, gpointer) = (void (*)(GtkWidget *, gpointer))data;
367 
368     /* call our 'close', 'dismiss' or 'cancel' callback (which must not need the user data) */
369     (*handler)(widget, NULL);
370 
371     /* tell GTK+ to NOT emit 'destroy' */
372     return TRUE;
373 }
374 
375 void
on_load_soundfont_button_press(GtkWidget * widget,gpointer data)376 on_load_soundfont_button_press(GtkWidget *widget, gpointer data)
377 {
378     if (soundfont_filename) {
379         gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_selection),
380                                         soundfont_filename);
381     } else if (project_directory) {
382         if (project_directory[strlen(project_directory) - 1] != '/') {
383             char buffer[PATH_MAX];
384             snprintf(buffer, PATH_MAX, "%s/", project_directory);
385             gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_selection),
386                                             buffer);
387         } else {
388             gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_selection),
389                                             project_directory);
390         }
391     }
392     gtk_widget_show(file_selection);
393 }
394 
395 int
load_soundfont(char * filename)396 load_soundfont(char *filename)
397 {
398     SFData *sfdata;
399 
400     if ((sfdata = fsd_sfload_file(filename))) {
401 
402         /* free the old soundfont data, if any */
403         if (soundfont_data)
404             fsd_sfont_free_data(soundfont_data);
405 
406         soundfont_data = sfdata;
407         if (soundfont_filename)
408             free(soundfont_filename);
409         soundfont_filename = strdup(filename);
410 
411         gtk_label_set_text (GTK_LABEL (soundfont_label), filename);
412 
413         rebuild_preset_clist(sfdata);
414 
415         if (!internal_gui_update_only) {
416             lo_send(osc_host_address, osc_configure_path, "ss", "load",
417                     filename);
418         }
419 
420         return 1;
421     }
422     return 0;
423 }
424 
425 void
on_file_selection_ok(GtkWidget * widget,gpointer data)426 on_file_selection_ok( GtkWidget *widget, gpointer data )
427 {
428     gchar *filename = (gchar *)gtk_file_selection_get_filename(
429                                    GTK_FILE_SELECTION(file_selection));
430 
431     gtk_widget_hide(file_selection);
432 
433     DEBUG_DSSI("fsd-gui on_file_selection_ok: file '%s' selected\n",
434                filename);
435 
436     if (!load_soundfont(filename)) {
437 
438         DEBUG_DSSI("fsd-gui on_file_selection_ok: load_soundfont() failed!\n");
439         gtk_label_set_text (GTK_LABEL (notice_label_1), "Unable to load the selected soundfont!");
440         gtk_label_set_text (GTK_LABEL (notice_label_2), filename);
441         gtk_widget_show(notice_window);
442 
443     } else {
444 	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(choose_soundfont_combo)->entry),
445 			   "(other)");
446     }
447 }
448 
449 void
on_file_selection_cancel(GtkWidget * widget,gpointer data)450 on_file_selection_cancel( GtkWidget *widget, gpointer data )
451 {
452     /* DEBUG_DSSI("fsd-gui: on_file_selection_cancel called\n"); */
453     gtk_widget_hide(file_selection);
454 }
455 
456 void
on_preset_selection(GtkWidget * clist,gint row,gint column,GdkEventButton * event,gpointer data)457 on_preset_selection(GtkWidget      *clist,
458                     gint            row,
459                     gint            column,
460                     GdkEventButton *event,
461                     gpointer        data )
462 {
463     if (internal_gui_update_only) {
464         /* DEBUG_DSSI("fsd-gui on_preset_selection: skipping further action\n"); */
465         return;
466     }
467 
468     if ((unsigned long)row < preset_count) {
469 
470         DEBUG_DSSI("fsd-gui on_preset_selection: preset %d selected => bank %d program %d\n",
471                    row, presets_by_row[row]->bank, presets_by_row[row]->prenum);
472 
473         lo_send(osc_host_address, osc_program_path, "ii",
474                 presets_by_row[row]->bank, presets_by_row[row]->prenum);
475 
476     } else {
477 
478         DEBUG_DSSI("fsd-gui on_preset_selection: out-of-range preset %d selected\n", row);
479 
480     }
481 }
482 
483 void
on_gain_slider_change(GtkWidget * widget,gpointer data)484 on_gain_slider_change(GtkWidget *widget, gpointer data)
485 {
486     float db = GTK_ADJUSTMENT(widget)->value;
487     float gain = powf(10.0f, db / 20.0f);
488     char buffer[10];
489 
490     if (internal_gui_update_only) {
491         /* DEBUG_DSSI("fsd-gui on_gain_slider_change: skipping further action\n"); */
492         return;
493     }
494 
495     DEBUG_DSSI("fsd-gui on_gain_slider_change: new gain %f => %f\n", db, gain);
496 
497     snprintf(buffer, 10, "%9.6f", gain);
498     lo_send(osc_host_address, osc_configure_path, "ss",
499             DSSI_GLOBAL_CONFIGURE_PREFIX "gain", buffer);
500 }
501 
502 #ifdef USE_AUGMENTED_FLUIDSYNTH_API
503 void
on_polyphony_slider_change(GtkWidget * widget,gpointer data)504 on_polyphony_slider_change(GtkWidget *widget, gpointer data)
505 {
506     int polyphony = lrintf(GTK_ADJUSTMENT(widget)->value);
507     char buffer[10];
508 
509     if (internal_gui_update_only) {
510         /* DEBUG_DSSI("fsd-gui on_polyphony_slider_change: skipping further action\n"); */
511         return;
512     }
513 
514     DEBUG_DSSI("fsd-gui on_polyphony_slider_change: new polyphony %d\n", polyphony);
515 
516     snprintf(buffer, 10, "%d", polyphony);
517     lo_send(osc_host_address, osc_configure_path, "ss",
518             DSSI_GLOBAL_CONFIGURE_PREFIX "polyphony", buffer);
519 }
520 #endif
521 
522 void
on_soundfont_combo_changed(GtkWidget * widget,gpointer data)523 on_soundfont_combo_changed(GtkWidget *widget, gpointer data)
524 {
525     char *filename =
526 	(char *)gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(data)->entry));
527     char *path;
528 
529     if (!strcmp(filename, "(other)")) return;
530 
531     path = fsd_locate_soundfont_file(filename, project_directory);
532 
533     if (!path) {
534         gtk_label_set_text (GTK_LABEL (notice_label_1), "Unable to find the selected soundfont!");
535         gtk_label_set_text (GTK_LABEL (notice_label_2), filename);
536         gtk_widget_show(notice_window);
537 	free(path);
538 	return;
539     }
540 
541     if (!load_soundfont(path)) {
542 
543         gtk_label_set_text (GTK_LABEL (notice_label_1), "Unable to load the selected soundfont!");
544         gtk_label_set_text (GTK_LABEL (notice_label_2), path);
545         gtk_widget_show(notice_window);
546     }
547 
548     free(path);
549 }
550 
551 void
on_test_note_slider_change(GtkWidget * widget,gpointer data)552 on_test_note_slider_change(GtkWidget *widget, gpointer data)
553 {
554     unsigned char value = lrintf(GTK_ADJUSTMENT(widget)->value);
555 
556     if ((int)data == 0) {  /* key */
557 
558         test_note_noteon_key = value;
559         DEBUG_DSSI("fsd-gui on_test_note_slider_change: new test note key %d\n", test_note_noteon_key);
560 
561     } else {  /* velocity */
562 
563         test_note_velocity = value;
564         DEBUG_DSSI("fsd-gui on_test_note_slider_change: new test note velocity %d\n", test_note_velocity);
565 
566     }
567 }
568 
569 void
on_test_note_button_press(GtkWidget * widget,gpointer data)570 on_test_note_button_press(GtkWidget *widget, gpointer data)
571 {
572     unsigned char midi[4];
573 
574     if ((int)data) {  /* button pressed */
575 
576         midi[0] = 0;
577         midi[1] = 0x90;
578         midi[2] = test_note_noteon_key;
579         midi[3] = test_note_velocity;
580         lo_send(osc_host_address, osc_midi_path, "m", midi);
581         test_note_noteoff_key = test_note_noteon_key;
582 
583     } else { /* button released */
584 
585         midi[0] = 0;
586         midi[1] = 0x80;
587         midi[2] = test_note_noteoff_key;
588         midi[3] = 0x40;
589         lo_send(osc_host_address, osc_midi_path, "m", midi);
590 
591     }
592 }
593 
594 void
on_notice_dismiss(GtkWidget * widget,gpointer data)595 on_notice_dismiss( GtkWidget *widget, gpointer data )
596 {
597     gtk_widget_hide(notice_window);
598 }
599 
600 void
update_from_program_select(int bank,int program)601 update_from_program_select(int bank, int program)
602 {
603     unsigned long i;
604 
605     /* find the preset */
606     for (i = 0; i < preset_count; i++) {
607         if (presets_by_row[i]->bank == bank &&
608             presets_by_row[i]->prenum == program) {
609             break;
610         }
611     }
612 
613     if (i < preset_count) {
614 
615         internal_gui_update_only = 1;
616         gtk_clist_select_row (GTK_CLIST(preset_clist), i, 0);
617         internal_gui_update_only = 0;
618 
619     } else {  /* not found */
620 
621         gtk_clist_unselect_all (GTK_CLIST(preset_clist));
622 
623     }
624 }
625 
626 void
rebuild_preset_clist(SFData * sfdata)627 rebuild_preset_clist(SFData *sfdata)
628 {
629     fluid_list_t *p;
630     SFPreset *sfpreset;
631     char bank[6], program[4], name[31];
632     char *data[3] = { bank, program, name };
633     unsigned long i;
634 
635     /* DEBUG_DSSI("fsd-gui: rebuild_preset_clist called\n"); */
636 
637     gtk_clist_freeze(GTK_CLIST(preset_clist));
638     gtk_clist_clear(GTK_CLIST(preset_clist));
639 
640     /* count presets */
641     preset_count = 0;
642     p = sfdata->preset;
643     while (p != NULL) {
644         preset_count++;
645         p = fluid_list_next(p);
646     }
647 
648     /* build presets_by_row */
649     if (presets_by_row)
650         free(presets_by_row);
651     presets_by_row = (SFPreset **)malloc(preset_count * sizeof(SFPreset *));
652     if (!presets_by_row) {
653         preset_count = 0;
654         gtk_clist_thaw(GTK_CLIST(preset_clist));
655         return;
656     }
657     i = 0;
658     p = sfdata->preset;
659     while (p != NULL) {
660         presets_by_row[i] = (SFPreset *)p->data;
661         i++;
662         p = fluid_list_next(p);
663     }
664 
665     /* build clist */
666     for (i = 0; i < preset_count; i++) {
667         sfpreset = presets_by_row[i];
668         snprintf(bank, 6, "%d", sfpreset->bank);
669         snprintf(program, 4, "%d", sfpreset->prenum);
670         if (sfpreset->name && strlen(sfpreset->name) > 0) {
671             strncpy(name, sfpreset->name, 31);
672         } else {
673             snprintf(name, 31, "preset %d:%d", sfpreset->bank, sfpreset->prenum);
674         }
675         gtk_clist_append(GTK_CLIST(preset_clist), data);
676     }
677 
678     gtk_clist_thaw(GTK_CLIST(preset_clist));
679 }
680 
681 /* ==== GTK+ widget creation ==== */
682 
683 GtkWidget*
create_main_window(const char * tag)684 create_main_window (const char *tag)
685 {
686   GtkWidget *vbox4;
687   GtkWidget *frame2;
688   GtkWidget *frame4;
689   GtkWidget *frame3;
690   GtkWidget *scrolledwindow1;
691   GtkWidget *label11;
692   GtkWidget *label12;
693   GtkWidget *label13;
694   GtkWidget *frame5;
695   GtkWidget *table1;
696   GtkWidget *label1;
697   GtkWidget *table6;
698   GtkWidget *label6;
699   GtkWidget *label7;
700   GtkWidget *gain_scale;
701 #ifdef USE_AUGMENTED_FLUIDSYNTH_API
702   GtkWidget *polyphony_label;
703   GtkWidget *polyphony_scale;
704 #endif
705   GtkWidget *key_scale;
706   GtkWidget *velocity_scale;
707   GtkWidget *frame6;
708   GtkWidget *table7;
709   GtkWidget *hbox1;
710   GtkWidget *load_soundfont_button;
711   GtkWidget *test_note_button;
712   GList *sf_items = NULL;
713   char **list;
714   int i, n;
715 
716   main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
717   gtk_object_set_data (GTK_OBJECT (main_window), "main_window", main_window);
718   gtk_window_set_title (GTK_WINDOW (main_window), tag);
719 
720   vbox4 = gtk_vbox_new (FALSE, 0);
721   gtk_widget_ref (vbox4);
722   gtk_object_set_data_full (GTK_OBJECT (main_window), "vbox4", vbox4,
723                             (GtkDestroyNotify) gtk_widget_unref);
724   gtk_widget_show (vbox4);
725   gtk_container_add (GTK_CONTAINER (main_window), vbox4);
726 
727   frame6 = gtk_frame_new ("SoundFonts in SF2 Path");
728   gtk_widget_ref (frame6);
729   gtk_object_set_data_full (GTK_OBJECT (main_window), "frame6", frame6,
730                             (GtkDestroyNotify) gtk_widget_unref);
731   gtk_box_pack_start (GTK_BOX (vbox4), frame6, FALSE, FALSE, 0);
732   gtk_container_set_border_width (GTK_CONTAINER (frame6), 5);
733 
734   table7 = gtk_table_new (2, 2, FALSE);
735   gtk_widget_ref (table7);
736   gtk_object_set_data_full (GTK_OBJECT (main_window), "table7", table7,
737                             (GtkDestroyNotify) gtk_widget_unref);
738   gtk_container_add (GTK_CONTAINER (frame6), table7);
739   gtk_container_set_border_width (GTK_CONTAINER (table7), 4);
740 
741   choose_soundfont_combo = gtk_combo_new ();
742   sf_items = g_list_append(sf_items, "(other)");
743   list = fsd_get_known_soundfonts(project_directory, &n);
744   for (i = 0; i < n; ++i) {
745       sf_items = g_list_append(sf_items, strdup(list[i]));
746   }
747   gtk_combo_set_popdown_strings (GTK_COMBO (choose_soundfont_combo), sf_items);
748   gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(choose_soundfont_combo)->entry), FALSE);
749   gtk_table_attach (GTK_TABLE (table7), choose_soundfont_combo, 1, 2, 0, 1,
750                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
751                     (GtkAttachOptions) (GTK_FILL), 0, 0);
752   if (n > 0) {
753       gtk_widget_show (choose_soundfont_combo);
754       gtk_widget_show (table7);
755       gtk_widget_show (frame6);
756   }
757 
758   frame2 = gtk_frame_new ("Current SoundFont");
759   gtk_widget_ref (frame2);
760   gtk_object_set_data_full (GTK_OBJECT (main_window), "frame2", frame2,
761                             (GtkDestroyNotify) gtk_widget_unref);
762   gtk_widget_show (frame2);
763   gtk_box_pack_start (GTK_BOX (vbox4), frame2, FALSE, TRUE, 0);
764   gtk_container_set_border_width (GTK_CONTAINER (frame2), 5);
765 
766   soundfont_label = gtk_label_new ("<none loaded>");
767   gtk_widget_ref (soundfont_label);
768   gtk_object_set_data_full (GTK_OBJECT (main_window), "soundfont_label", soundfont_label,
769                             (GtkDestroyNotify) gtk_widget_unref);
770   gtk_widget_show (soundfont_label);
771   gtk_container_add (GTK_CONTAINER (frame2), soundfont_label);
772   gtk_misc_set_padding (GTK_MISC (soundfont_label), 6, 0);
773 
774   frame4 = gtk_frame_new ("Preset");
775   gtk_widget_ref (frame4);
776   gtk_object_set_data_full (GTK_OBJECT (main_window), "frame4", frame4,
777                             (GtkDestroyNotify) gtk_widget_unref);
778   gtk_widget_show (frame4);
779   gtk_box_pack_start (GTK_BOX (vbox4), frame4, TRUE, TRUE, 0);
780   gtk_container_set_border_width (GTK_CONTAINER (frame4), 5);
781 
782   scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
783   gtk_widget_ref (scrolledwindow1);
784   gtk_object_set_data_full (GTK_OBJECT (main_window), "scrolledwindow1", scrolledwindow1,
785                             (GtkDestroyNotify) gtk_widget_unref);
786   gtk_widget_show (scrolledwindow1);
787   gtk_container_add (GTK_CONTAINER (frame4), scrolledwindow1);
788   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
789 
790   preset_clist = gtk_clist_new (3);
791   gtk_widget_ref (preset_clist);
792   gtk_object_set_data_full (GTK_OBJECT (main_window), "preset_clist", preset_clist,
793                             (GtkDestroyNotify) gtk_widget_unref);
794   gtk_widget_show (preset_clist);
795   gtk_container_add (GTK_CONTAINER (scrolledwindow1), preset_clist);
796   gtk_widget_set_usize (preset_clist, 300, 150);
797   gtk_clist_set_column_width (GTK_CLIST (preset_clist), 0, 80);
798   gtk_clist_set_column_width (GTK_CLIST (preset_clist), 1, 80);
799   gtk_clist_set_column_width (GTK_CLIST (preset_clist), 2, 80);
800   gtk_clist_column_titles_show (GTK_CLIST (preset_clist));
801 
802   label11 = gtk_label_new ("Bank");
803   gtk_widget_ref (label11);
804   gtk_object_set_data_full (GTK_OBJECT (main_window), "label11", label11,
805                             (GtkDestroyNotify) gtk_widget_unref);
806   gtk_widget_show (label11);
807   gtk_clist_set_column_widget (GTK_CLIST (preset_clist), 0, label11);
808 
809   label12 = gtk_label_new ("Program");
810   gtk_widget_ref (label12);
811   gtk_object_set_data_full (GTK_OBJECT (main_window), "label12", label12,
812                             (GtkDestroyNotify) gtk_widget_unref);
813   gtk_widget_show (label12);
814   gtk_clist_set_column_widget (GTK_CLIST (preset_clist), 1, label12);
815 
816   label13 = gtk_label_new ("Name");
817   gtk_widget_ref (label13);
818   gtk_object_set_data_full (GTK_OBJECT (main_window), "label13", label13,
819                             (GtkDestroyNotify) gtk_widget_unref);
820   gtk_widget_show (label13);
821   gtk_clist_set_column_widget (GTK_CLIST (preset_clist), 2, label13);
822 
823   frame3 = gtk_frame_new ("Global Settings");
824   gtk_widget_ref (frame3);
825   gtk_object_set_data_full (GTK_OBJECT (main_window), "frame3", frame3,
826                             (GtkDestroyNotify) gtk_widget_unref);
827   gtk_widget_show (frame3);
828   gtk_box_pack_start (GTK_BOX (vbox4), frame3, FALSE, TRUE, 0);
829   gtk_container_set_border_width (GTK_CONTAINER (frame3), 5);
830 
831   table1 = gtk_table_new (2, 2, FALSE);
832   gtk_widget_ref (table1);
833   gtk_object_set_data_full (GTK_OBJECT (main_window), "table1", table1,
834                             (GtkDestroyNotify) gtk_widget_unref);
835   gtk_widget_show (table1);
836   gtk_container_add (GTK_CONTAINER (frame3), table1);
837   gtk_container_set_border_width (GTK_CONTAINER (table1), 4);
838 
839   label1 = gtk_label_new ("gain (dB)");
840   gtk_widget_ref (label1);
841   gtk_object_set_data_full (GTK_OBJECT (main_window), "label1", label1,
842                             (GtkDestroyNotify) gtk_widget_unref);
843   gtk_widget_show (label1);
844   gtk_table_attach (GTK_TABLE (table1), label1, 0, 1, 0, 1,
845                     (GtkAttachOptions) (GTK_FILL),
846                     (GtkAttachOptions) (0), 0, 0);
847   gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5);
848   gtk_misc_set_padding (GTK_MISC (label1), 5, 0);
849 
850     gain_adj = gtk_adjustment_new (-14, -96, 30, 1, 10, 10);
851   gain_scale = gtk_hscale_new (GTK_ADJUSTMENT (gain_adj));
852   gtk_widget_ref (gain_scale);
853   gtk_object_set_data_full (GTK_OBJECT (main_window), "gain_scale", gain_scale,
854                             (GtkDestroyNotify) gtk_widget_unref);
855   gtk_widget_show (gain_scale);
856   gtk_table_attach (GTK_TABLE (table1), gain_scale, 1, 2, 0, 1,
857                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
858                     (GtkAttachOptions) (GTK_FILL), 0, 0);
859   gtk_scale_set_value_pos (GTK_SCALE (gain_scale), GTK_POS_RIGHT);
860   gtk_scale_set_digits (GTK_SCALE (gain_scale), 0);
861     gtk_range_set_update_policy (GTK_RANGE (gain_scale), GTK_UPDATE_DELAYED);
862 
863 #ifdef USE_AUGMENTED_FLUIDSYNTH_API
864     polyphony_label = gtk_label_new ("polyphony");
865     gtk_widget_ref (polyphony_label);
866     gtk_object_set_data_full (GTK_OBJECT (main_window), "polyphony_label", polyphony_label,
867                               (GtkDestroyNotify) gtk_widget_unref);
868     gtk_widget_show (polyphony_label);
869     gtk_table_attach (GTK_TABLE (table1), polyphony_label, 0, 1, 1, 2,
870                       (GtkAttachOptions) (GTK_FILL),
871                       (GtkAttachOptions) (0), 0, 0);
872     gtk_misc_set_alignment (GTK_MISC (polyphony_label), 0, 0.5);
873     gtk_misc_set_padding (GTK_MISC (polyphony_label), 5, 0);
874 
875     polyphony_adj = gtk_adjustment_new (FSD_MAX_POLYPHONY, 1, FSD_MAX_POLYPHONY+10, 1, 10, 10);
876     polyphony_scale = gtk_hscale_new (GTK_ADJUSTMENT (polyphony_adj));
877     gtk_widget_ref (polyphony_scale);
878     gtk_object_set_data_full (GTK_OBJECT (main_window), "polyphony_scale", polyphony_scale,
879                               (GtkDestroyNotify) gtk_widget_unref);
880     gtk_widget_show (polyphony_scale);
881     gtk_table_attach (GTK_TABLE (table1), polyphony_scale, 1, 2, 1, 2,
882                       (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
883                       (GtkAttachOptions) (GTK_FILL), 0, 0);
884     gtk_scale_set_value_pos (GTK_SCALE (polyphony_scale), GTK_POS_RIGHT);
885     gtk_scale_set_digits (GTK_SCALE (polyphony_scale), 0);
886     gtk_range_set_update_policy (GTK_RANGE (polyphony_scale), GTK_UPDATE_DELAYED);
887 #endif
888 
889   frame5 = gtk_frame_new ("Test Note");
890   gtk_widget_ref (frame5);
891   gtk_object_set_data_full (GTK_OBJECT (main_window), "frame5", frame5,
892                             (GtkDestroyNotify) gtk_widget_unref);
893   gtk_widget_show (frame5);
894   gtk_box_pack_start (GTK_BOX (vbox4), frame5, FALSE, FALSE, 0);
895   gtk_container_set_border_width (GTK_CONTAINER (frame5), 5);
896 
897   table6 = gtk_table_new (2, 2, FALSE);
898   gtk_widget_ref (table6);
899   gtk_object_set_data_full (GTK_OBJECT (main_window), "table6", table6,
900                             (GtkDestroyNotify) gtk_widget_unref);
901   gtk_widget_show (table6);
902   gtk_container_add (GTK_CONTAINER (frame5), table6);
903   gtk_container_set_border_width (GTK_CONTAINER (table6), 4);
904 
905   label6 = gtk_label_new ("key");
906   gtk_widget_ref (label6);
907   gtk_object_set_data_full (GTK_OBJECT (main_window), "label6", label6,
908                             (GtkDestroyNotify) gtk_widget_unref);
909   gtk_widget_show (label6);
910   gtk_table_attach (GTK_TABLE (table6), label6, 0, 1, 0, 1,
911                     (GtkAttachOptions) (GTK_FILL),
912                     (GtkAttachOptions) (0), 0, 0);
913   gtk_misc_set_alignment (GTK_MISC (label6), 0, 0.5);
914   gtk_misc_set_padding (GTK_MISC (label6), 5, 0);
915 
916   label7 = gtk_label_new ("velocity");
917   gtk_widget_ref (label7);
918   gtk_object_set_data_full (GTK_OBJECT (main_window), "label7", label7,
919                             (GtkDestroyNotify) gtk_widget_unref);
920   gtk_widget_show (label7);
921   gtk_table_attach (GTK_TABLE (table6), label7, 0, 1, 1, 2,
922                     (GtkAttachOptions) (GTK_FILL),
923                     (GtkAttachOptions) (0), 0, 0);
924   gtk_misc_set_alignment (GTK_MISC (label7), 0, 0.5);
925   gtk_misc_set_padding (GTK_MISC (label7), 5, 0);
926 
927   key_scale = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (60, 12, 132, 1, 12, 12)));
928   gtk_widget_ref (key_scale);
929   gtk_object_set_data_full (GTK_OBJECT (main_window), "key_scale", key_scale,
930                             (GtkDestroyNotify) gtk_widget_unref);
931   gtk_widget_show (key_scale);
932   gtk_table_attach (GTK_TABLE (table6), key_scale, 1, 2, 0, 1,
933                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
934                     (GtkAttachOptions) (GTK_FILL), 0, 0);
935   gtk_scale_set_value_pos (GTK_SCALE (key_scale), GTK_POS_RIGHT);
936   gtk_scale_set_digits (GTK_SCALE (key_scale), 0);
937     gtk_range_set_update_policy (GTK_RANGE (key_scale), GTK_UPDATE_DELAYED);
938 
939   velocity_scale = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (96, 1, 137, 1, 10, 10)));
940   gtk_widget_ref (velocity_scale);
941   gtk_object_set_data_full (GTK_OBJECT (main_window), "velocity_scale", velocity_scale,
942                             (GtkDestroyNotify) gtk_widget_unref);
943   gtk_widget_show (velocity_scale);
944   gtk_table_attach (GTK_TABLE (table6), velocity_scale, 1, 2, 1, 2,
945                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
946                     (GtkAttachOptions) (GTK_FILL), 0, 0);
947   gtk_scale_set_value_pos (GTK_SCALE (velocity_scale), GTK_POS_RIGHT);
948   gtk_scale_set_digits (GTK_SCALE (velocity_scale), 0);
949     gtk_range_set_update_policy (GTK_RANGE (velocity_scale), GTK_UPDATE_DELAYED);
950 
951   hbox1 = gtk_hbox_new (FALSE, 40);
952   gtk_widget_ref (hbox1);
953   gtk_object_set_data_full (GTK_OBJECT (main_window), "hbox1", hbox1,
954                             (GtkDestroyNotify) gtk_widget_unref);
955   gtk_widget_show (hbox1);
956   gtk_box_pack_start (GTK_BOX (vbox4), hbox1, FALSE, FALSE, 0);
957 
958   load_soundfont_button = gtk_button_new_with_label ("Load SoundFont...");
959   gtk_widget_ref (load_soundfont_button);
960   gtk_object_set_data_full (GTK_OBJECT (main_window), "load_soundfont_button", load_soundfont_button,
961                             (GtkDestroyNotify) gtk_widget_unref);
962   gtk_widget_show (load_soundfont_button);
963   gtk_box_pack_start (GTK_BOX (hbox1), load_soundfont_button, FALSE, FALSE, 0);
964   gtk_container_set_border_width (GTK_CONTAINER (load_soundfont_button), 8);
965 
966   test_note_button = gtk_button_new_with_label ("Send Test Note");
967   gtk_widget_ref (test_note_button);
968   gtk_object_set_data_full (GTK_OBJECT (main_window), "test_note_button", test_note_button,
969                             (GtkDestroyNotify) gtk_widget_unref);
970   gtk_widget_show (test_note_button);
971   gtk_box_pack_end (GTK_BOX (hbox1), test_note_button, FALSE, FALSE, 0);
972   gtk_container_set_border_width (GTK_CONTAINER (test_note_button), 8);
973 
974     /* connect main window */
975     gtk_signal_connect(GTK_OBJECT(main_window), "destroy",
976                        GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
977     gtk_signal_connect (GTK_OBJECT (main_window), "delete_event",
978                         (GtkSignalFunc)on_delete_event_wrapper,
979                         (gpointer)gtk_main_quit);
980 
981     /* connect select soundfont button */
982     gtk_signal_connect (GTK_OBJECT (load_soundfont_button), "clicked",
983                         GTK_SIGNAL_FUNC (on_load_soundfont_button_press),
984                         NULL);
985 
986     /* connect preset clist */
987     gtk_signal_connect(GTK_OBJECT(preset_clist), "select_row",
988                        GTK_SIGNAL_FUNC(on_preset_selection),
989                        NULL);
990 
991     /* connect settings widgets */
992     gtk_signal_connect (GTK_OBJECT(gain_adj), "value_changed",
993                         GTK_SIGNAL_FUNC(on_gain_slider_change),
994                         NULL);
995 #ifdef USE_AUGMENTED_FLUIDSYNTH_API
996     gtk_signal_connect (GTK_OBJECT(polyphony_adj), "value_changed",
997                         GTK_SIGNAL_FUNC(on_polyphony_slider_change),
998                         NULL);
999 #endif
1000 
1001     /* connect soundfont combo widget */
1002     gtk_signal_connect(GTK_OBJECT(GTK_COMBO(choose_soundfont_combo)->popwin), "hide",
1003                         GTK_SIGNAL_FUNC(on_soundfont_combo_changed), choose_soundfont_combo);
1004 
1005     /* connect test note widgets */
1006     gtk_signal_connect (GTK_OBJECT (gtk_range_get_adjustment (GTK_RANGE (key_scale))),
1007                         "value_changed", GTK_SIGNAL_FUNC(on_test_note_slider_change),
1008                         (gpointer)0);
1009     gtk_signal_connect (GTK_OBJECT (gtk_range_get_adjustment (GTK_RANGE (velocity_scale))),
1010                         "value_changed", GTK_SIGNAL_FUNC(on_test_note_slider_change),
1011                         (gpointer)1);
1012     gtk_signal_connect (GTK_OBJECT (test_note_button), "pressed",
1013                         GTK_SIGNAL_FUNC (on_test_note_button_press),
1014                         (gpointer)1);
1015     gtk_signal_connect (GTK_OBJECT (test_note_button), "released",
1016                         GTK_SIGNAL_FUNC (on_test_note_button_press),
1017                         (gpointer)0);
1018 
1019   return main_window;
1020 }
1021 
1022 GtkWidget*
create_file_selection(const char * tag)1023 create_file_selection (const char *tag)
1024 {
1025   char      *title;
1026   GtkWidget *ok_button1;
1027   GtkWidget *cancel_button1;
1028 
1029     title = (char *)malloc(strlen(tag) + 20);
1030     sprintf(title, "%s - Select SoundFont", tag);
1031     file_selection = gtk_file_selection_new (title);
1032     free(title);
1033   gtk_object_set_data (GTK_OBJECT (file_selection), "file_selection", file_selection);
1034   gtk_container_set_border_width (GTK_CONTAINER (file_selection), 10);
1035 
1036   ok_button1 = GTK_FILE_SELECTION (file_selection)->ok_button;
1037   gtk_object_set_data (GTK_OBJECT (file_selection), "ok_button1", ok_button1);
1038   gtk_widget_show (ok_button1);
1039   GTK_WIDGET_SET_FLAGS (ok_button1, GTK_CAN_DEFAULT);
1040 
1041   cancel_button1 = GTK_FILE_SELECTION (file_selection)->cancel_button;
1042   gtk_object_set_data (GTK_OBJECT (file_selection), "cancel_button1", cancel_button1);
1043   gtk_widget_show (cancel_button1);
1044   GTK_WIDGET_SET_FLAGS (cancel_button1, GTK_CAN_DEFAULT);
1045 
1046     gtk_signal_connect (GTK_OBJECT (file_selection), "destroy",
1047                         GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
1048     gtk_signal_connect (GTK_OBJECT (file_selection), "delete_event",
1049                         (GtkSignalFunc)on_delete_event_wrapper,
1050                         (gpointer)on_file_selection_cancel);
1051     gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_selection)->ok_button),
1052                         "clicked", (GtkSignalFunc)on_file_selection_ok,
1053                         NULL);
1054     gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_selection)->cancel_button),
1055                         "clicked", (GtkSignalFunc)on_file_selection_cancel,
1056                         NULL);
1057 
1058   return file_selection;
1059 }
1060 
1061 GtkWidget*
create_notice_window(const char * tag)1062 create_notice_window (const char *tag)
1063 {
1064   char      *title;
1065   GtkWidget *vbox3;
1066   GtkWidget *hbox1;
1067   GtkWidget *notice_dismiss;
1068 
1069     notice_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1070     gtk_object_set_data (GTK_OBJECT (notice_window), "notice_window", notice_window);
1071     title = (char *)malloc(strlen(tag) + 8);
1072     sprintf(title, "%s Notice", tag);
1073     gtk_window_set_title (GTK_WINDOW (notice_window), title);
1074     free(title);
1075     gtk_window_set_position (GTK_WINDOW (notice_window), GTK_WIN_POS_MOUSE);
1076     gtk_window_set_modal (GTK_WINDOW (notice_window), TRUE);
1077 
1078   vbox3 = gtk_vbox_new (FALSE, 0);
1079   gtk_widget_ref (vbox3);
1080   gtk_object_set_data_full (GTK_OBJECT (notice_window), "vbox3", vbox3,
1081                             (GtkDestroyNotify) gtk_widget_unref);
1082   gtk_widget_show (vbox3);
1083   gtk_container_add (GTK_CONTAINER (notice_window), vbox3);
1084 
1085   notice_label_1 = gtk_label_new ("Some message\ngoes here");
1086   gtk_widget_ref (notice_label_1);
1087   gtk_object_set_data_full (GTK_OBJECT (notice_window), "notice_label_1", notice_label_1,
1088                             (GtkDestroyNotify) gtk_widget_unref);
1089   gtk_widget_show (notice_label_1);
1090   gtk_box_pack_start (GTK_BOX (vbox3), notice_label_1, TRUE, TRUE, 0);
1091   gtk_label_set_line_wrap (GTK_LABEL (notice_label_1), TRUE);
1092   gtk_misc_set_padding (GTK_MISC (notice_label_1), 10, 5);
1093 
1094   notice_label_2 = gtk_label_new ("more text\ngoes here");
1095   gtk_widget_ref (notice_label_2);
1096   gtk_object_set_data_full (GTK_OBJECT (notice_window), "notice_label_2", notice_label_2,
1097                             (GtkDestroyNotify) gtk_widget_unref);
1098   gtk_widget_show (notice_label_2);
1099   gtk_box_pack_start (GTK_BOX (vbox3), notice_label_2, FALSE, FALSE, 0);
1100   gtk_label_set_line_wrap (GTK_LABEL (notice_label_2), TRUE);
1101   gtk_misc_set_padding (GTK_MISC (notice_label_2), 10, 5);
1102 
1103   hbox1 = gtk_hbox_new (FALSE, 0);
1104   gtk_widget_ref (hbox1);
1105   gtk_object_set_data_full (GTK_OBJECT (notice_window), "hbox1", hbox1,
1106                             (GtkDestroyNotify) gtk_widget_unref);
1107   gtk_widget_show (hbox1);
1108   gtk_box_pack_start (GTK_BOX (vbox3), hbox1, FALSE, FALSE, 0);
1109 
1110   notice_dismiss = gtk_button_new_with_label ("Dismiss");
1111   gtk_widget_ref (notice_dismiss);
1112   gtk_object_set_data_full (GTK_OBJECT (notice_window), "notice_dismiss", notice_dismiss,
1113                             (GtkDestroyNotify) gtk_widget_unref);
1114   gtk_widget_show (notice_dismiss);
1115   gtk_box_pack_start (GTK_BOX (hbox1), notice_dismiss, TRUE, FALSE, 0);
1116   gtk_container_set_border_width (GTK_CONTAINER (notice_dismiss), 7);
1117 
1118     gtk_signal_connect (GTK_OBJECT (notice_window), "destroy",
1119                         GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
1120     gtk_signal_connect (GTK_OBJECT (notice_window), "delete_event",
1121                         GTK_SIGNAL_FUNC (on_delete_event_wrapper),
1122                         (gpointer)on_notice_dismiss);
1123     gtk_signal_connect (GTK_OBJECT (notice_dismiss), "clicked",
1124                         GTK_SIGNAL_FUNC (on_notice_dismiss),
1125                         NULL);
1126 
1127     return notice_window;
1128 }
1129 
1130 void
create_windows(const char * instance_tag)1131 create_windows(const char *instance_tag)
1132 {
1133     char tag[50];
1134 
1135     /* build a nice identifier string for the window titles */
1136     if (strlen(instance_tag) == 0) {
1137         strcpy(tag, "FluidSynth-DSSI");
1138     } else if (strstr(instance_tag, "FluidSynth-DSSI") ||
1139                strstr(instance_tag, "fluidsynth-dssi")) {
1140         if (strlen(instance_tag) > 49) {
1141             snprintf(tag, 50, "...%s", instance_tag + strlen(instance_tag) - 46); /* hope the unique info is at the end */
1142         } else {
1143             strcpy(tag, instance_tag);
1144         }
1145     } else {
1146         if (strlen(instance_tag) > 33) {
1147             snprintf(tag, 50, "FluidSynth-DSSI ...%s", instance_tag + strlen(instance_tag) - 30);
1148         } else {
1149             snprintf(tag, 50, "FluidSynth-DSSI %s", instance_tag);
1150         }
1151     }
1152 
1153     create_main_window (tag);
1154     create_file_selection (tag);
1155     create_notice_window (tag);
1156 }
1157 
1158 /* ==== main ==== */
1159 
1160 int
main(int argc,char * argv[])1161 main (int argc, char *argv[])
1162 {
1163     static char *test_argv[5] = { NULL, NULL, "-", "-", "FluidSynth-DSSI" };
1164     char *host, *port, *path, *tmp_url;
1165     lo_server osc_server;
1166     gint osc_server_socket_tag;
1167     gint update_request_timeout_tag;
1168 
1169     fprintf(stderr, "fsd-gui starting (pid %d)...\n", getpid());
1170 
1171     gtk_set_locale ();
1172     gtk_init (&argc, &argv);
1173 
1174     if (!strcmp(argv[1], "-test")) {
1175         gui_test_mode = 1;
1176         test_argv[0] = argv[0];
1177         test_argv[1] = "osc.udp://localhost:9/test/mode";
1178         if (argc >= 5)
1179             test_argv[4] = argv[4];
1180         argc = 5;
1181         argv = test_argv;
1182     } else if (argc != 5) {
1183         fprintf(stderr, "usage: %s <osc url> <plugin dllname> <plugin label> <user-friendly id>\n"
1184                         "   or: %s -test\n", argv[0], argv[0]);
1185         exit(1);
1186     }
1187 
1188     /* set up OSC support */
1189     host = lo_url_get_hostname(argv[1]);
1190     port = lo_url_get_port(argv[1]);
1191     path = lo_url_get_path(argv[1]);
1192     osc_host_address = lo_address_new(host, port);
1193     osc_configure_path = osc_build_path(path, "/configure");
1194     osc_control_path   = osc_build_path(path, "/control");
1195     osc_exiting_path   = osc_build_path(path, "/exiting");
1196     osc_hide_path      = osc_build_path(path, "/hide");
1197     osc_midi_path      = osc_build_path(path, "/midi");
1198     osc_program_path   = osc_build_path(path, "/program");
1199     osc_quit_path      = osc_build_path(path, "/quit");
1200     osc_rate_path      = osc_build_path(path, "/sample-rate");
1201     osc_show_path      = osc_build_path(path, "/show");
1202     osc_update_path    = osc_build_path(path, "/update");
1203 
1204     osc_server = lo_server_new(NULL, osc_error);
1205     lo_server_add_method(osc_server, osc_configure_path, "ss", osc_configure_handler, NULL);
1206     lo_server_add_method(osc_server, osc_control_path, "if", osc_control_handler, NULL);
1207     lo_server_add_method(osc_server, osc_hide_path, "", osc_action_handler, "hide");
1208     lo_server_add_method(osc_server, osc_program_path, "ii", osc_program_handler, NULL);
1209     lo_server_add_method(osc_server, osc_quit_path, "", osc_action_handler, "quit");
1210     lo_server_add_method(osc_server, osc_rate_path, "i", osc_action_handler, "sample-rate");
1211     lo_server_add_method(osc_server, osc_show_path, "", osc_action_handler, "show");
1212     lo_server_add_method(osc_server, NULL, NULL, osc_debug_handler, NULL);
1213 
1214     tmp_url = lo_server_get_url(osc_server);
1215     osc_self_url = osc_build_path(tmp_url, (strlen(path) > 1 ? path + 1 : path));
1216     free(tmp_url);
1217 
1218     /* set up GTK+ */
1219     create_windows(argv[4]);
1220 
1221     /* add OSC server socket to GTK+'s watched I/O */
1222     if (lo_server_get_socket_fd(osc_server) < 0) {
1223         fprintf(stderr, "fsd-gui fatal: OSC transport does not support exposing socket fd\n");
1224         exit(1);
1225     }
1226     osc_server_socket_tag = gdk_input_add(lo_server_get_socket_fd(osc_server),
1227                                           GDK_INPUT_READ,
1228                                           osc_data_on_socket_callback,
1229                                           osc_server);
1230 
1231     /* schedule our update request */
1232     update_request_timeout_tag = gtk_timeout_add(50,
1233                                                  update_request_timeout_callback,
1234                                                  NULL);
1235 
1236     /* let GTK+ take it from here */
1237     gtk_main();
1238 
1239     /* clean up and exit */
1240     DEBUG_DSSI("fsd-gui: yep, we got to the cleanup!\n");
1241 
1242     /* GTK+ cleanup */
1243     gtk_timeout_remove(update_request_timeout_tag);
1244     gdk_input_remove(osc_server_socket_tag);
1245 
1246     /* say bye-bye */
1247     if (!host_requested_quit) {
1248         lo_send(osc_host_address, osc_exiting_path, "");
1249     }
1250 
1251     /* free soundfont data, if any */
1252     if (soundfont_data)
1253         fsd_sfont_free_data(soundfont_data);
1254     if (soundfont_filename)
1255         free(soundfont_filename);
1256     if (project_directory)
1257         free(project_directory);
1258     if (presets_by_row)
1259         free(presets_by_row);
1260 
1261     /* clean up OSC support */
1262     lo_server_free(osc_server);
1263     free(host);
1264     free(port);
1265     free(path);
1266     free(osc_configure_path);
1267     free(osc_control_path);
1268     free(osc_exiting_path);
1269     free(osc_hide_path);
1270     free(osc_midi_path);
1271     free(osc_program_path);
1272     free(osc_quit_path);
1273     free(osc_rate_path);
1274     free(osc_show_path);
1275     free(osc_update_path);
1276     free(osc_self_url);
1277 
1278     return 0;
1279 }
1280 
1281