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