1 /* FluidSynth - A Software Synthesizer
2  *
3  * Copyright (C) 2003  Peter Hanappe and others.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public License
7  * as published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA
19  */
20 
21 
22 
23 /*
24  2002 : API design by Peter Hanappe and Antoine Schmitt
25  August 2002 : Implementation by Antoine Schmitt as@gratin.org
26                as part of the infiniteCD author project
27                http://www.infiniteCD.org/
28 */
29 
30 #include "fluidsynth_priv.h"
31 #include "fluid_synth.h"
32 #include "fluid_midi.h"
33 #include "fluid_event_priv.h"
34 
35  /***************************************************************
36  *
37  *                           SEQUENCER BINDING
38  */
39 
40 struct _fluid_seqbind_t {
41 	fluid_synth_t* synth;
42 	fluid_sequencer_t* seq;
43 	fluid_sample_timer_t* sample_timer;
44 	short client_id;
45 };
46 typedef struct _fluid_seqbind_t fluid_seqbind_t;
47 
48 
49 int fluid_seqbind_timer_callback(void* data, unsigned int msec);
50 void fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* event, fluid_sequencer_t* seq, void* data);
51 
52 /* Proper cleanup of the seqbind struct. */
53 void
delete_fluid_seqbind(fluid_seqbind_t * seqbind)54 delete_fluid_seqbind(fluid_seqbind_t* seqbind)
55 {
56 	if (seqbind == NULL) {
57 		return;
58 	}
59 
60 	if ((seqbind->client_id != -1) && (seqbind->seq != NULL)) {
61 		fluid_sequencer_unregister_client(seqbind->seq, seqbind->client_id);
62 		seqbind->client_id = -1;
63 	}
64 
65 	if ((seqbind->sample_timer != NULL) && (seqbind->synth != NULL)) {
66 		delete_fluid_sample_timer(seqbind->synth, seqbind->sample_timer);
67 		seqbind->sample_timer = NULL;
68 	}
69 
70 	FLUID_FREE(seqbind);
71 }
72 
73 /**
74  * Registers a synthesizer as a destination client of the given sequencer.
75  * The \a synth is registered with the name "fluidsynth".
76  * @param seq Sequencer instance
77  * @param synth Synthesizer instance
78  * @returns Sequencer client ID, or #FLUID_FAILED on error.
79  */
80 short
fluid_sequencer_register_fluidsynth(fluid_sequencer_t * seq,fluid_synth_t * synth)81 fluid_sequencer_register_fluidsynth (fluid_sequencer_t* seq, fluid_synth_t* synth)
82 {
83 	fluid_seqbind_t* seqbind;
84 
85 	seqbind = FLUID_NEW(fluid_seqbind_t);
86 	if (seqbind == NULL) {
87 		fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
88 		return FLUID_FAILED;
89 	}
90 
91 	seqbind->synth = synth;
92 	seqbind->seq = seq;
93 	seqbind->sample_timer = NULL;
94 	seqbind->client_id = -1;
95 
96 	/* set up the sample timer */
97 	if (!fluid_sequencer_get_use_system_timer(seq)) {
98 		seqbind->sample_timer =
99 			new_fluid_sample_timer(synth, fluid_seqbind_timer_callback, (void *) seqbind);
100 		if (seqbind->sample_timer == NULL) {
101 			fluid_log(FLUID_PANIC, "sequencer: Out of memory\n");
102 			delete_fluid_seqbind(seqbind);
103 			return FLUID_FAILED;
104 		}
105 	}
106 
107 	/* register fluidsynth itself */
108 	seqbind->client_id =
109 		fluid_sequencer_register_client(seq, "fluidsynth", fluid_seq_fluidsynth_callback, (void *)seqbind);
110 	if (seqbind->client_id == -1) {
111 		delete_fluid_seqbind(seqbind);
112 		return FLUID_FAILED;
113 	}
114 
115 	return seqbind->client_id;
116 }
117 
118 /* Callback for sample timer */
119 int
fluid_seqbind_timer_callback(void * data,unsigned int msec)120 fluid_seqbind_timer_callback(void* data, unsigned int msec)
121 {
122 	fluid_seqbind_t* seqbind = (fluid_seqbind_t *) data;
123 	fluid_sequencer_process(seqbind->seq, msec);
124 	return 1;
125 }
126 
127 /* Callback for midi events */
128 void
fluid_seq_fluidsynth_callback(unsigned int time,fluid_event_t * evt,fluid_sequencer_t * seq,void * data)129 fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_sequencer_t* seq, void* data)
130 {
131 	fluid_synth_t* synth;
132 	fluid_seqbind_t* seqbind = (fluid_seqbind_t *) data;
133 	synth = seqbind->synth;
134 
135   switch (fluid_event_get_type(evt)) {
136 
137   case FLUID_SEQ_NOTEON:
138   	fluid_synth_noteon(synth, fluid_event_get_channel(evt), fluid_event_get_key(evt), fluid_event_get_velocity(evt));
139   	break;
140 
141   case FLUID_SEQ_NOTEOFF:
142   	fluid_synth_noteoff(synth, fluid_event_get_channel(evt), fluid_event_get_key(evt));
143   	break;
144 
145   case FLUID_SEQ_NOTE:
146 	  {
147 	  	unsigned int dur;
148 	  	fluid_synth_noteon(synth, fluid_event_get_channel(evt), fluid_event_get_key(evt), fluid_event_get_velocity(evt));
149 	  	dur = fluid_event_get_duration(evt);
150 	  	fluid_event_noteoff(evt, fluid_event_get_channel(evt), fluid_event_get_key(evt));
151 	  	fluid_sequencer_send_at(seq, evt, dur, 0);
152 	  }
153   	break;
154 
155 	case FLUID_SEQ_ALLSOUNDSOFF:
156 		/* NYI */
157   	break;
158 
159   case FLUID_SEQ_ALLNOTESOFF:
160   	fluid_synth_cc(synth, fluid_event_get_channel(evt), 0x7B, 0);
161   	break;
162 
163   case FLUID_SEQ_BANKSELECT:
164   	fluid_synth_bank_select(synth, fluid_event_get_channel(evt), fluid_event_get_bank(evt));
165   	break;
166 
167   case FLUID_SEQ_PROGRAMCHANGE:
168   	fluid_synth_program_change(synth, fluid_event_get_channel(evt), fluid_event_get_program(evt));
169   	break;
170 
171   case FLUID_SEQ_PROGRAMSELECT:
172   	fluid_synth_program_select(synth, fluid_event_get_channel(evt), fluid_event_get_sfont_id(evt),
173 		fluid_event_get_bank(evt), fluid_event_get_program(evt));
174   	break;
175 
176   case FLUID_SEQ_ANYCONTROLCHANGE:
177   	/* nothing = only used by remove_events */
178   	break;
179 
180   case FLUID_SEQ_PITCHBEND:
181   	fluid_synth_pitch_bend(synth, fluid_event_get_channel(evt), fluid_event_get_pitch(evt));
182   	break;
183 
184   case FLUID_SEQ_PITCHWHHELSENS:
185   	fluid_synth_pitch_wheel_sens(synth, fluid_event_get_channel(evt), fluid_event_get_value(evt));
186   	break;
187 
188   case FLUID_SEQ_CONTROLCHANGE:
189 	 fluid_synth_cc(synth, fluid_event_get_channel(evt), fluid_event_get_control(evt), fluid_event_get_value(evt));
190   	break;
191 
192   case FLUID_SEQ_MODULATION:
193 	  {
194 	  	short ctrl = 0x01;	// MODULATION_MSB
195 	  	fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
196 	  }
197   	break;
198 
199   case FLUID_SEQ_SUSTAIN:
200 	  {
201 	  	short ctrl = 0x40;	// SUSTAIN_SWITCH
202 	  	fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
203 	  }
204   	break;
205 
206   case FLUID_SEQ_PAN:
207 	  {
208 	  	short ctrl = 0x0A;	// PAN_MSB
209 	  	fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
210 	  }
211   	break;
212 
213   case FLUID_SEQ_VOLUME:
214 	  {
215 	  	short ctrl = 0x07;	// VOLUME_MSB
216 	  	fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
217 	  }
218   	break;
219 
220   case FLUID_SEQ_REVERBSEND:
221 	  {
222 	  	short ctrl = 0x5B;	// EFFECTS_DEPTH1
223 	  	fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
224 	  }
225   	break;
226 
227   case FLUID_SEQ_CHORUSSEND:
228 	  {
229 	  	short ctrl = 0x5D;	// EFFECTS_DEPTH3
230 	  	fluid_synth_cc(synth, fluid_event_get_channel(evt), ctrl, fluid_event_get_value(evt));
231 	  }
232   	break;
233 
234   case FLUID_SEQ_CHANNELPRESSURE:
235 	  {
236 		fluid_synth_channel_pressure(synth, fluid_event_get_channel(evt), fluid_event_get_value(evt));
237 	  }
238 	break;
239 
240   case FLUID_SEQ_SYSTEMRESET:
241 	  {
242 		fluid_synth_system_reset(synth);
243 	  }
244 	break;
245 
246   case FLUID_SEQ_UNREGISTERING: /* free ourselves */
247 	  {
248 		seqbind->client_id = -1; /* avoid recursive call to fluid_sequencer_unregister_client */
249 	        delete_fluid_seqbind(seqbind);
250 	  }
251 	break;
252 
253   case FLUID_SEQ_TIMER:
254 	  /* nothing in fluidsynth */
255   	break;
256 
257 	default:
258   	break;
259 	}
260 }
261 
get_fluidsynth_dest(fluid_sequencer_t * seq)262 static int get_fluidsynth_dest(fluid_sequencer_t* seq)
263 {
264 	int i, id;
265 	char* name;
266 	int j = fluid_sequencer_count_clients(seq);
267 	for (i = 0; i < j; i++) {
268 		id = fluid_sequencer_get_client_id(seq, i);
269 		name = fluid_sequencer_get_client_name(seq, id);
270 		if (strcmp(name, "fluidsynth") == 0) {
271 			return id;
272 		}
273 	}
274 	return -1;
275 }
276 
277 /**
278  * Transforms an incoming midi event (from a midi driver or midi router) to a
279  * sequencer event and adds it to the sequencer queue for sending as soon as possible.
280  * @param data The sequencer, must be a valid #fluid_sequencer_t
281  * @param event MIDI event
282  * @return #FLUID_OK or #FLUID_FAILED
283  * @since 1.1.0
284  */
285 int
fluid_sequencer_add_midi_event_to_buffer(void * data,fluid_midi_event_t * event)286 fluid_sequencer_add_midi_event_to_buffer(void* data, fluid_midi_event_t* event)
287 {
288 	fluid_event_t evt;
289 	fluid_sequencer_t* seq = (fluid_sequencer_t*) data;
290 	int chan = fluid_midi_event_get_channel(event);
291 
292 	fluid_event_clear(&evt);
293 	fluid_event_set_time(&evt, fluid_sequencer_get_tick(seq));
294 	fluid_event_set_dest(&evt, get_fluidsynth_dest(seq));
295 
296 	switch (fluid_midi_event_get_type(event)) {
297 	case NOTE_OFF:
298 		fluid_event_noteoff(&evt, chan, fluid_midi_event_get_key(event));
299 		break;
300 	case NOTE_ON:
301 		fluid_event_noteon(&evt, fluid_midi_event_get_channel(event),
302 		                   fluid_midi_event_get_key(event), fluid_midi_event_get_velocity(event));
303 		break;
304 	case CONTROL_CHANGE:
305 		fluid_event_control_change(&evt, chan, fluid_midi_event_get_control(event),
306 		                           fluid_midi_event_get_value(event));
307 		break;
308 	case PROGRAM_CHANGE:
309 		fluid_event_program_change(&evt, chan, fluid_midi_event_get_program(event));
310 		break;
311 	case PITCH_BEND:
312 		fluid_event_pitch_bend(&evt, chan, fluid_midi_event_get_pitch(event));
313 		break;
314 	case CHANNEL_PRESSURE:
315 		fluid_event_channel_pressure(&evt, chan, fluid_midi_event_get_program(event));
316 		break;
317 	case MIDI_SYSTEM_RESET:
318 		fluid_event_system_reset(&evt);
319 		break;
320 	default:  /* Not yet implemented */
321 		return FLUID_FAILED;
322 	}
323 
324 	/* Schedule for sending at next call to fluid_sequencer_process */
325 	return fluid_sequencer_send_at(seq, &evt, 0, 0);
326 }
327 
328 
329