1 #ifdef _HAVE_FLUIDSYNTH_
2 /*
3 * fluid.c
4 * JACK audio and MIDI backends.
5 *
6 * for Denemo, a gtk+ frontend to GNU Lilypond
7 * Copyright (C) 2011 Dominic Sacré
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 */
14
15 #include "audio/fluid.h"
16 #include "audio/midi.h"
17 #include "audio/pitchentry.h"
18
19 #include <fluidsynth.h>
20 #include <glib.h>
21 #include "core/utils.h"
22
23 static fluid_settings_t *settings = NULL;
24 static fluid_synth_t *synth = NULL;
25 static int sfont_id = -1;
26
reset_synth_channels(void)27 void reset_synth_channels (void)
28 {
29 // select bank 0 and preset 0 in the soundfont we just loaded on channel 0
30 fluid_synth_program_select (synth, 0, sfont_id, 0, 0);
31 gint i;
32 for (i = 0; i < 16; i++)
33 fluid_synth_program_change (synth, i, 0);
34 if (Denemo.project && Denemo.project->movement)
35 {
36 DenemoMovement *si = Denemo.project->movement;
37 GList *curstaff;
38 for (curstaff = si->thescore; curstaff; curstaff=curstaff->next)
39 {
40 DenemoStaff *curstaffstruct = (DenemoStaff *) curstaff->data;//g_print ("Reset staff program chan %d to prog %d\n", curstaffstruct->midi_channel, curstaffstruct->midi_prognum);
41 fluid_synth_program_change (synth, curstaffstruct->midi_channel, curstaffstruct->midi_prognum);
42 }
43 }
44 if (Denemo.prefs.pitchspellingchannel)
45 fluid_synth_program_change (synth, Denemo.prefs.pitchspellingchannel, Denemo.prefs.pitchspellingprogram);
46 set_tuning ();
47 }
48
49 int
fluidsynth_init(DenemoPrefs * config,unsigned int samplerate)50 fluidsynth_init (DenemoPrefs * config, unsigned int samplerate)
51 {
52 g_debug ("Starting FLUIDSYNTH");
53
54 settings = new_fluid_settings ();
55 if (!settings)
56 {
57 g_warning ("Failed to create the settings");
58 return -1;
59 }
60
61 fluid_settings_setnum (settings, "synth.sample-rate", (double) samplerate);
62
63 fluid_settings_setint (settings, "synth.reverb.active", config->fluidsynth_reverb ? 1 : 0);
64 fluid_settings_setint (settings, "synth.chorus.active", config->fluidsynth_chorus ? 1 : 0);
65
66 // create the synthesizer
67 synth = new_fluid_synth (settings);
68 if (!synth)
69 {
70 g_warning ("Failed to create the settings");
71 fluidsynth_shutdown ();
72 return -1;
73 }
74
75 if(g_file_test(config->fluidsynth_soundfont->str, G_FILE_TEST_EXISTS))
76 sfont_id = fluid_synth_sfload (synth, config->fluidsynth_soundfont->str, FALSE);
77
78 if (sfont_id == -1)
79 {
80 g_debug ("Failed to load the user soundfont. Now trying the default soundfont.");
81 gchar *default_soundfont = find_denemo_file(DENEMO_DIR_SOUNDFONTS, "A320U.sf2");
82 if(default_soundfont)
83 sfont_id = fluid_synth_sfload (synth, default_soundfont, FALSE);
84 g_string_assign (Denemo.prefs.fluidsynth_soundfont, default_soundfont);
85 g_free (default_soundfont);
86 }
87 if (sfont_id == -1)
88 {
89 fluidsynth_shutdown ();
90 return -1;
91 }
92 else
93 {
94 g_message ("The default fluidsynth soundfont has been loaded");
95 }
96 reset_synth_channels ();
97
98 return 0;
99 }
100
101
102 void
fluidsynth_shutdown()103 fluidsynth_shutdown ()
104 {
105 g_debug ("\nStopping FLUIDSYNTH\n");
106
107 if (sfont_id != -1)
108 {
109 fluid_synth_sfunload (synth, sfont_id, FALSE);
110 }
111
112 if (synth)
113 {
114 delete_fluid_synth (synth);
115 }
116 synth = NULL;
117
118 if (settings)
119 {
120 delete_fluid_settings (settings);
121 }
122 settings = NULL;
123 }
124
125
126 void
fluidsynth_feed_midi(unsigned char * event_data,size_t event_length)127 fluidsynth_feed_midi (unsigned char *event_data, size_t event_length)
128 {
129 int channel = (event_data[0] & 0x0f);
130 int type = (event_data[0] & 0xf0);
131
132 switch (type)
133 {
134 case MIDI_NOTE_ON:
135 {
136 int velocity = ((int) (Denemo.project->movement->master_volume * event_data[2]));
137 if (velocity > 0x7F)
138 velocity = 0x7F;
139 fluid_synth_noteon (synth, channel, event_data[1], velocity);
140 }
141 break;
142 case MIDI_NOTE_OFF:
143 fluid_synth_noteoff (synth, channel, event_data[1]);
144 break;
145 case MIDI_CONTROL_CHANGE:
146 fluid_synth_cc (synth, channel, event_data[1], event_data[2]);
147 break;
148 case MIDI_PROGRAM_CHANGE:
149 fluid_synth_program_change (synth, channel, event_data[1]);
150 break;
151 case MIDI_PITCH_BEND:
152 fluid_synth_pitch_bend (synth, channel, event_data[1] + (event_data[2] << 7));
153 break;
154 case SYS_EXCLUSIVE_MESSAGE1:
155 //g_debug("length %d\n", event_length);
156 fluid_synth_sysex (synth, (const char*) event_data + 1, event_length - 1, NULL, 0, NULL, FALSE);
157 break;
158 default:
159 g_warning ("MIDI message type %x not handled", type);
160 }
161 }
162
163
164 static void
fluid_all_notes_off_channel(gint chan)165 fluid_all_notes_off_channel (gint chan)
166 {
167 // fluid_event_all_sounds_off (fluid_event_t *evt, int channel)!!!!!!!!!!!
168 // fluid_event_t evt;
169 // fluid_event_all_notes_off (&evt, chan)
170 gint i;
171 for (i = 0; i < 128; i++)
172 fluid_synth_noteoff (synth, chan, i);
173 }
174
175 static void
fluid_all_notes_off(void)176 fluid_all_notes_off (void)
177 {
178 gint chan;
179 for (chan = 0; chan < 16; chan++)
180 fluid_all_notes_off_channel (chan);
181 }
182
183
184 void
fluidsynth_all_notes_off()185 fluidsynth_all_notes_off ()
186 {
187 // FIXME: this call has the potential to cause an xrun and/or disconnect us from JACK
188 //FIXME: this unsets the channel settings for immediate playback (fixed below) and more ...????
189 //fluid_synth_system_reset(synth);
190 fluid_all_notes_off ();
191 // if(Denemo.prefs.pitchspellingchannel)
192 // fluid_synth_program_change(synth, Denemo.prefs.pitchspellingchannel, Denemo.prefs.pitchspellingprogram);
193 }
194
195 void
fluidsynth_render_audio(unsigned int nframes,float * left_channel,float * right_channel)196 fluidsynth_render_audio (unsigned int nframes, float *left_channel, float *right_channel)
197 {
198 //printf("\nsynth == %d, nframes == %d, left_channel == %f right_channel == %f\n",synth, nframes, left_channel, right_channel);
199 fluid_synth_write_float (synth, nframes, left_channel, 0, 1, right_channel, 0, 1);
200 }
201
202 /**
203 * Select the soundfont to use for playback
204 */
205 void
choose_sound_font(GtkWidget * widget,GtkWidget * fluidsynth_soundfont)206 choose_sound_font (GtkWidget * widget, GtkWidget * fluidsynth_soundfont)
207 {
208 GtkWidget *sf;
209 //GtkFileFilter *filter;
210
211 sf = gtk_file_chooser_dialog_new (_("Choose SoundFont File"), GTK_WINDOW (Denemo.window), GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), GTK_RESPONSE_REJECT, _("_Open"), GTK_RESPONSE_ACCEPT, NULL);
212
213 //TODO Should we filter????
214 //filter = gtk_file_filter_new ();
215 //gtk_file_filter_set_name (filter, "Soundfont file");
216 //gtk_file_filter_add_pattern (filter, "*.sf");
217 //gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fs), filter);
218
219 gtk_widget_show_all (sf);
220 if (gtk_dialog_run (GTK_DIALOG (sf)) == GTK_RESPONSE_ACCEPT)
221 {
222 g_string_assign (Denemo.prefs.fluidsynth_soundfont, gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (sf)));
223 /* this will only work for 1 sound font */
224 gtk_entry_set_text (GTK_ENTRY (fluidsynth_soundfont), Denemo.prefs.fluidsynth_soundfont->str);
225
226 }
227 gtk_widget_destroy (sf);
228 }
229
230 #endif //_HAVE_FLUIDSYNTH_
231