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