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  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18  * 02111-1307, USA
19  */
20 
21 #include "fluid_ramsfont.h"
22 #include "fluid_sys.h"
23 #include "fluid_synth.h"
24 
25 /* thenumber of samples before the start and after the end */
26 #define SAMPLE_LOOP_MARGIN 8
27 
28 /* Prototypes */
29 int fluid_rampreset_add_sample(fluid_rampreset_t* preset, fluid_sample_t* sample, int lokey, int hikey);
30 int fluid_rampreset_izone_set_gen(fluid_rampreset_t* preset, fluid_sample_t* sample, int gen_type, float value);
31 int fluid_rampreset_izone_set_loop(fluid_rampreset_t* preset, fluid_sample_t* sample, int on, float loopstart, float loopend);
32 int fluid_rampreset_remove_izone(fluid_rampreset_t* preset, fluid_sample_t* sample);
33 void fluid_rampreset_updatevoices(fluid_rampreset_t* preset, int gen_type, float val);
34 
35 /*
36  * fluid_ramsfont_create_sfont
37  */
38 fluid_sfont_t*
fluid_ramsfont_create_sfont()39 fluid_ramsfont_create_sfont()
40 {
41 	fluid_sfont_t* sfont;
42 	fluid_ramsfont_t* ramsfont;
43 
44 	ramsfont = new_fluid_ramsfont();
45 	if (ramsfont == NULL) {
46     return NULL;
47   }
48 
49   sfont = FLUID_NEW(fluid_sfont_t);
50   if (sfont == NULL) {
51     FLUID_LOG(FLUID_ERR, "Out of memory");
52     return NULL;
53   }
54 
55   sfont->data = ramsfont;
56   sfont->free = fluid_ramsfont_sfont_delete;
57   sfont->get_name = fluid_ramsfont_sfont_get_name;
58   sfont->get_preset = fluid_ramsfont_sfont_get_preset;
59   sfont->iteration_start = fluid_ramsfont_sfont_iteration_start;
60   sfont->iteration_next = fluid_ramsfont_sfont_iteration_next;
61 
62   return sfont;
63 
64 }
65 
66 /***************************************************************
67  *
68  *                           PUBLIC INTERFACE
69  */
70 
fluid_ramsfont_sfont_delete(fluid_sfont_t * sfont)71 int fluid_ramsfont_sfont_delete(fluid_sfont_t* sfont)
72 {
73 	if (delete_fluid_ramsfont(sfont->data) != 0)
74 		return -1;
75 	FLUID_FREE(sfont);
76 	return 0;
77 }
78 
fluid_ramsfont_sfont_get_name(fluid_sfont_t * sfont)79 char* fluid_ramsfont_sfont_get_name(fluid_sfont_t* sfont)
80 {
81   return fluid_ramsfont_get_name((fluid_ramsfont_t*) sfont->data);
82 }
83 
fluid_ramsfont_sfont_get_preset(fluid_sfont_t * sfont,unsigned int bank,unsigned int prenum)84 fluid_preset_t* fluid_ramsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum)
85 {
86   fluid_preset_t* preset;
87   fluid_rampreset_t* rampreset;
88 
89   rampreset = fluid_ramsfont_get_preset((fluid_ramsfont_t*) sfont->data, bank, prenum);
90 
91   if (rampreset == NULL) {
92     return NULL;
93   }
94 
95   preset = FLUID_NEW(fluid_preset_t);
96   if (preset == NULL) {
97     FLUID_LOG(FLUID_ERR, "Out of memory");
98     return NULL;
99   }
100 
101   preset->sfont = sfont;
102   preset->data = rampreset;
103   preset->free = fluid_rampreset_preset_delete;
104   preset->get_name = fluid_rampreset_preset_get_name;
105   preset->get_banknum = fluid_rampreset_preset_get_banknum;
106   preset->get_num = fluid_rampreset_preset_get_num;
107   preset->noteon = fluid_rampreset_preset_noteon;
108   preset->notify = NULL;
109 
110   return preset;
111 }
112 
fluid_ramsfont_sfont_iteration_start(fluid_sfont_t * sfont)113 void fluid_ramsfont_sfont_iteration_start(fluid_sfont_t* sfont)
114 {
115   fluid_ramsfont_iteration_start((fluid_ramsfont_t*) sfont->data);
116 }
117 
fluid_ramsfont_sfont_iteration_next(fluid_sfont_t * sfont,fluid_preset_t * preset)118 int fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset)
119 {
120   preset->free = fluid_rampreset_preset_delete;
121   preset->get_name = fluid_rampreset_preset_get_name;
122   preset->get_banknum = fluid_rampreset_preset_get_banknum;
123   preset->get_num = fluid_rampreset_preset_get_num;
124   preset->noteon = fluid_rampreset_preset_noteon;
125   preset->notify = NULL;
126 
127   return fluid_ramsfont_iteration_next((fluid_ramsfont_t*) sfont->data, preset);
128 }
129 
fluid_rampreset_preset_delete(fluid_preset_t * preset)130 int fluid_rampreset_preset_delete(fluid_preset_t* preset)
131 {
132   FLUID_FREE(preset);
133 
134 /* TODO: free modulators */
135 
136   return 0;
137 }
138 
fluid_rampreset_preset_get_name(fluid_preset_t * preset)139 char* fluid_rampreset_preset_get_name(fluid_preset_t* preset)
140 {
141   return fluid_rampreset_get_name((fluid_rampreset_t*) preset->data);
142 }
143 
fluid_rampreset_preset_get_banknum(fluid_preset_t * preset)144 int fluid_rampreset_preset_get_banknum(fluid_preset_t* preset)
145 {
146   return fluid_rampreset_get_banknum((fluid_rampreset_t*) preset->data);
147 }
148 
fluid_rampreset_preset_get_num(fluid_preset_t * preset)149 int fluid_rampreset_preset_get_num(fluid_preset_t* preset)
150 {
151   return fluid_rampreset_get_num((fluid_rampreset_t*) preset->data);
152 }
153 
fluid_rampreset_preset_noteon(fluid_preset_t * preset,fluid_synth_t * synth,int chan,int key,int vel)154 int fluid_rampreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel)
155 {
156   return fluid_rampreset_noteon((fluid_rampreset_t*) preset->data, synth, chan, key, vel);
157 }
158 
159 
160 
161 
162 /***************************************************************
163  *
164  *                           SFONT
165  */
166 
167 /*
168  * new_fluid_ramsfont
169  */
new_fluid_ramsfont()170 fluid_ramsfont_t* new_fluid_ramsfont()
171 {
172   fluid_ramsfont_t* sfont;
173 
174   sfont = FLUID_NEW(fluid_ramsfont_t);
175   if (sfont == NULL) {
176     FLUID_LOG(FLUID_ERR, "Out of memory");
177     return NULL;
178   }
179 
180   sfont->name[0] = 0;
181   sfont->sample = NULL;
182   sfont->preset = NULL;
183 
184   return sfont;
185 }
186 
187 /*
188  * delete_fluid_ramsfont
189  */
delete_fluid_ramsfont(fluid_ramsfont_t * sfont)190 int delete_fluid_ramsfont(fluid_ramsfont_t* sfont)
191 {
192   fluid_list_t *list;
193   fluid_rampreset_t* preset;
194 
195   /* Check that no samples are currently used */
196   for (list = sfont->sample; list; list = fluid_list_next(list)) {
197     fluid_sample_t* sam = (fluid_sample_t*) fluid_list_get(list);
198     if (fluid_sample_refcount(sam) != 0) {
199       return -1;
200     }
201   }
202 
203   for (list = sfont->sample; list; list = fluid_list_next(list)) {
204   	/* in ram soundfonts, the samples hold their data : so we should free it ourselves */
205   	fluid_sample_t* sam = (fluid_sample_t*)fluid_list_get(list);
206     delete_fluid_ramsample(sam);
207   }
208 
209   if (sfont->sample) {
210     delete_fluid_list(sfont->sample);
211   }
212 
213   preset = sfont->preset;
214   while (preset != NULL) {
215     sfont->preset = preset->next;
216     delete_fluid_rampreset(preset);
217     preset = sfont->preset;
218   }
219 
220   FLUID_FREE(sfont);
221   return FLUID_OK;
222 }
223 
224 /*
225  * fluid_ramsfont_get_name
226  */
fluid_ramsfont_get_name(fluid_ramsfont_t * sfont)227 char* fluid_ramsfont_get_name(fluid_ramsfont_t* sfont)
228 {
229   return sfont->name;
230 }
231 
232 /*
233  * fluid_ramsfont_set_name
234  */
235 int
fluid_ramsfont_set_name(fluid_ramsfont_t * sfont,char * name)236 fluid_ramsfont_set_name(fluid_ramsfont_t* sfont, char * name)
237 {
238   FLUID_MEMCPY(sfont->name, name, 20);
239   return FLUID_OK;
240 }
241 
242 
243 /* fluid_ramsfont_add_preset
244  *
245  * Add a preset to the SoundFont
246  */
fluid_ramsfont_add_preset(fluid_ramsfont_t * sfont,fluid_rampreset_t * preset)247 int fluid_ramsfont_add_preset(fluid_ramsfont_t* sfont, fluid_rampreset_t* preset)
248 {
249   fluid_rampreset_t *cur, *prev;
250   if (sfont->preset == NULL) {
251     preset->next = NULL;
252     sfont->preset = preset;
253   } else {
254     /* sort them as we go along. very basic sorting trick. */
255     cur = sfont->preset;
256     prev = NULL;
257     while (cur != NULL) {
258       if ((preset->bank < cur->bank)
259 	  || ((preset->bank == cur->bank) && (preset->num < cur->num))) {
260 	if (prev == NULL) {
261 	  preset->next = cur;
262 	  sfont->preset = preset;
263 	} else {
264 	  preset->next = cur;
265 	  prev->next = preset;
266 	}
267 	return FLUID_OK;
268       }
269       prev = cur;
270       cur = cur->next;
271     }
272     preset->next = NULL;
273     prev->next = preset;
274   }
275   return FLUID_OK;
276 }
277 
278 /*
279  * fluid_ramsfont_add_ramsample
280  */
fluid_ramsfont_add_izone(fluid_ramsfont_t * sfont,unsigned int bank,unsigned int num,fluid_sample_t * sample,int lokey,int hikey)281 int fluid_ramsfont_add_izone(fluid_ramsfont_t* sfont,
282 				unsigned int bank, unsigned int num, fluid_sample_t* sample,
283 				int lokey, int hikey)
284 {
285 	/*- find or create a preset
286 		- add it the sample using the fluid_rampreset_add_sample fucntion
287 		- add the sample to the list of samples
288 	*/
289 	int err;
290 
291 	fluid_rampreset_t* preset = fluid_ramsfont_get_preset(sfont, bank, num);
292 	if (preset == NULL) {
293 		// Create it
294 		preset = new_fluid_rampreset(sfont);
295 		if (preset == NULL) {
296 			return FLUID_FAILED;
297 		}
298 
299 		preset->bank = bank;
300 		preset->num = num;
301 
302 		err = fluid_rampreset_add_sample(preset, sample, lokey, hikey);
303 		if (err != FLUID_OK) {
304 			return FLUID_FAILED;
305 		}
306 
307 		// sort the preset
308 		fluid_ramsfont_add_preset(sfont, preset);
309 
310 	} else {
311 
312 		// just add it
313 		err = fluid_rampreset_add_sample(preset, sample, lokey, hikey);
314 		if (err != FLUID_OK) {
315 			return FLUID_FAILED;
316 		}
317 	}
318 
319   sfont->sample = fluid_list_append(sfont->sample, sample);
320   return FLUID_OK;
321 }
322 
fluid_ramsfont_remove_izone(fluid_ramsfont_t * sfont,unsigned int bank,unsigned int num,fluid_sample_t * sample)323 int fluid_ramsfont_remove_izone(fluid_ramsfont_t* sfont,
324          unsigned int bank, unsigned int num, fluid_sample_t* sample) {
325 	int err;
326 	fluid_rampreset_t* preset = fluid_ramsfont_get_preset(sfont, bank, num);
327 	if (preset == NULL) {
328 		return FLUID_FAILED;
329 	}
330 
331 	// Fixed a crash bug : remove the sample from the sfont list after
332 	// removing the izone (aschmitt august 2005)
333 	err = fluid_rampreset_remove_izone(preset, sample);
334 	if (err != FLUID_OK)
335 		return err;
336 
337 	// now we must remove the sample from sfont->sample
338 	sfont->sample = fluid_list_remove(sfont->sample, sample);
339 
340 	return FLUID_OK;
341 }
342 
343 
344 /* Note for version 2.0 : missing API fluid_ramsfont_izone_get_gen - Antoine Schmitt May 2003 */
fluid_ramsfont_izone_set_gen(fluid_ramsfont_t * sfont,unsigned int bank,unsigned int num,fluid_sample_t * sample,int gen_type,float value)345 int fluid_ramsfont_izone_set_gen(fluid_ramsfont_t* sfont,
346 				unsigned int bank, unsigned int num, fluid_sample_t* sample,
347 				int gen_type, float value) {
348 
349 	fluid_rampreset_t* preset = fluid_ramsfont_get_preset(sfont, bank, num);
350 	if (preset == NULL) {
351 			return FLUID_FAILED;
352 	}
353 
354 	return fluid_rampreset_izone_set_gen(preset, sample, gen_type, value);
355 }
356 
357 /* Note for version 2.0 : missing API fluid_ramsfont_izone_get_loop - Antoine Schmitt May 2003 */
fluid_ramsfont_izone_set_loop(fluid_ramsfont_t * sfont,unsigned int bank,unsigned int num,fluid_sample_t * sample,int on,float loopstart,float loopend)358 int fluid_ramsfont_izone_set_loop(fluid_ramsfont_t* sfont,
359 				unsigned int bank, unsigned int num, fluid_sample_t* sample,
360 				int on, float loopstart, float loopend) {
361 	fluid_rampreset_t* preset = fluid_ramsfont_get_preset(sfont, bank, num);
362 	if (preset == NULL) {
363 			return FLUID_FAILED;
364 	}
365 
366 	return fluid_rampreset_izone_set_loop(preset, sample, on, loopstart, loopend);
367 }
368 
369 /*
370  * fluid_ramsfont_get_preset
371  */
fluid_ramsfont_get_preset(fluid_ramsfont_t * sfont,unsigned int bank,unsigned int num)372 fluid_rampreset_t* fluid_ramsfont_get_preset(fluid_ramsfont_t* sfont, unsigned int bank, unsigned int num)
373 {
374   fluid_rampreset_t* preset = sfont->preset;
375   while (preset != NULL) {
376     if ((preset->bank == bank) && ((preset->num == num))) {
377       return preset;
378     }
379     preset = preset->next;
380   }
381   return NULL;
382 }
383 
384 /*
385  * fluid_ramsfont_iteration_start
386  */
fluid_ramsfont_iteration_start(fluid_ramsfont_t * sfont)387 void fluid_ramsfont_iteration_start(fluid_ramsfont_t* sfont)
388 {
389   sfont->iter_cur = sfont->preset;
390 }
391 
392 /*
393  * fluid_ramsfont_iteration_next
394  */
fluid_ramsfont_iteration_next(fluid_ramsfont_t * sfont,fluid_preset_t * preset)395 int fluid_ramsfont_iteration_next(fluid_ramsfont_t* sfont, fluid_preset_t* preset)
396 {
397   if (sfont->iter_cur == NULL) {
398     return 0;
399   }
400 
401   preset->data = (void*) sfont->iter_cur;
402   sfont->iter_cur = fluid_rampreset_next(sfont->iter_cur);
403   return 1;
404 }
405 
406 /***************************************************************
407  *
408  *                           PRESET
409  */
410 
411 typedef struct _fluid_rampreset_voice_t fluid_rampreset_voice_t;
412 struct _fluid_rampreset_voice_t {
413 	fluid_voice_t *voice;
414 	unsigned int voiceID;
415 };
416 
417 /*
418  * new_fluid_rampreset
419  */
420 fluid_rampreset_t*
new_fluid_rampreset(fluid_ramsfont_t * sfont)421 new_fluid_rampreset(fluid_ramsfont_t* sfont)
422 {
423   fluid_rampreset_t* preset = FLUID_NEW(fluid_rampreset_t);
424   if (preset == NULL) {
425     FLUID_LOG(FLUID_ERR, "Out of memory");
426     return NULL;
427   }
428   preset->next = NULL;
429   preset->sfont = sfont;
430   preset->name[0] = 0;
431   preset->bank = 0;
432   preset->num = 0;
433   preset->global_zone = NULL;
434   preset->zone = NULL;
435   preset->presetvoices = NULL;
436   return preset;
437 }
438 
439 /*
440  * delete_fluid_rampreset
441  */
442 int
delete_fluid_rampreset(fluid_rampreset_t * preset)443 delete_fluid_rampreset(fluid_rampreset_t* preset)
444 {
445   int err = FLUID_OK;
446   fluid_preset_zone_t* zone;
447   fluid_rampreset_voice_t *data;
448 
449   if (preset->global_zone != NULL) {
450     if (delete_fluid_preset_zone(preset->global_zone) != FLUID_OK) {
451       err = FLUID_FAILED;
452     }
453     preset->global_zone = NULL;
454   }
455   zone = preset->zone;
456   while (zone != NULL) {
457     preset->zone = zone->next;
458     if (delete_fluid_preset_zone(zone) != FLUID_OK) {
459       err = FLUID_FAILED;
460     }
461     zone = preset->zone;
462   }
463 
464   if (preset->presetvoices != NULL) {
465   	fluid_list_t *tmp = preset->presetvoices, *next;
466   	while (tmp) {
467   		data = (fluid_rampreset_voice_t *)(tmp->data);
468   		FLUID_FREE(data);
469 
470   		next = tmp->next;
471   		FLUID_FREE(tmp);
472   		tmp = next;
473   	}
474   }
475   preset->presetvoices = NULL;
476 
477   FLUID_FREE(preset);
478   return err;
479 }
480 
481 int
fluid_rampreset_get_banknum(fluid_rampreset_t * preset)482 fluid_rampreset_get_banknum(fluid_rampreset_t* preset)
483 {
484   return preset->bank;
485 }
486 
487 int
fluid_rampreset_get_num(fluid_rampreset_t * preset)488 fluid_rampreset_get_num(fluid_rampreset_t* preset)
489 {
490   return preset->num;
491 }
492 
493 char*
fluid_rampreset_get_name(fluid_rampreset_t * preset)494 fluid_rampreset_get_name(fluid_rampreset_t* preset)
495 {
496   return preset->name;
497 }
498 
499 /*
500  * fluid_rampreset_next
501  */
502 fluid_rampreset_t*
fluid_rampreset_next(fluid_rampreset_t * preset)503 fluid_rampreset_next(fluid_rampreset_t* preset)
504 {
505   return preset->next;
506 }
507 
508 
509 /*
510  * fluid_rampreset_add_zone
511  */
512 int
fluid_rampreset_add_zone(fluid_rampreset_t * preset,fluid_preset_zone_t * zone)513 fluid_rampreset_add_zone(fluid_rampreset_t* preset, fluid_preset_zone_t* zone)
514 {
515   if (preset->zone == NULL) {
516     zone->next = NULL;
517     preset->zone = zone;
518   } else {
519     zone->next = preset->zone;
520     preset->zone = zone;
521   }
522   return FLUID_OK;
523 }
524 
525 
526 /*
527  * fluid_rampreset_add_sample
528  */
fluid_rampreset_add_sample(fluid_rampreset_t * preset,fluid_sample_t * sample,int lokey,int hikey)529 int fluid_rampreset_add_sample(fluid_rampreset_t* preset, fluid_sample_t* sample, int lokey, int hikey)
530 {
531 	/* create a new instrument zone, with the given sample */
532 
533 	/* one preset zone */
534 	if (preset->zone == NULL) {
535 		fluid_preset_zone_t* zone;
536 		zone = new_fluid_preset_zone("");
537 		if (zone == NULL) {
538 			return FLUID_FAILED;
539 		}
540 
541 		/* its instrument */
542 		zone->inst = (fluid_inst_t*) new_fluid_inst();
543     if (zone->inst == NULL) {
544       delete_fluid_preset_zone(zone);
545       return FLUID_FAILED;
546     }
547 
548 		fluid_rampreset_add_zone(preset, zone);
549 	}
550 
551 	/* add an instrument zone for each sample */
552 	{
553 		fluid_inst_t* inst = fluid_preset_zone_get_inst(preset->zone);
554 		fluid_inst_zone_t* izone = new_fluid_inst_zone("");
555 		if (izone == NULL) {
556 			return FLUID_FAILED;
557 		}
558 
559 		if (fluid_inst_add_zone(inst, izone) != FLUID_OK) {
560 			delete_fluid_inst_zone(izone);
561 			return FLUID_FAILED;
562 		}
563 
564 		izone->sample = sample;
565 		izone->keylo = lokey;
566 		izone->keyhi = hikey;
567 
568 		// give the preset the name of the sample
569 		FLUID_MEMCPY(preset->name, sample->name, 20);
570 	}
571 
572 	return FLUID_OK;
573 }
574 
fluid_rampreset_izoneforsample(fluid_rampreset_t * preset,fluid_sample_t * sample)575 fluid_inst_zone_t* fluid_rampreset_izoneforsample(fluid_rampreset_t* preset, fluid_sample_t* sample)
576 {
577 	fluid_inst_t* inst;
578 	fluid_inst_zone_t* izone;
579 
580 	if (preset->zone == NULL) return NULL;
581 
582 	inst = fluid_preset_zone_get_inst(preset->zone);
583 	izone = inst->zone;
584 	while (izone) {
585 		if (izone->sample == sample)
586 			return izone;
587 		izone = izone->next;
588 	}
589 	return NULL;
590 }
591 
fluid_rampreset_izone_set_loop(fluid_rampreset_t * preset,fluid_sample_t * sample,int on,float loopstart,float loopend)592 int fluid_rampreset_izone_set_loop(fluid_rampreset_t* preset, fluid_sample_t* sample,
593        int on, float loopstart, float loopend) {
594 	fluid_inst_zone_t* izone = fluid_rampreset_izoneforsample(preset, sample);
595 	short coarse, fine;
596 
597 	if (izone == NULL)
598 			return FLUID_FAILED;
599 
600 	if (!on) {
601 		izone->gen[GEN_SAMPLEMODE].flags = GEN_SET;
602 		izone->gen[GEN_SAMPLEMODE].val = FLUID_UNLOOPED;
603 		fluid_rampreset_updatevoices(preset, GEN_SAMPLEMODE, FLUID_UNLOOPED);
604 		return FLUID_OK;
605 }
606 
607 	/* NOTE : We should check that (sample->startloop + loopStart <= sample->endloop - loopend - 32) */
608 
609 	/* loopstart */
610 	if (loopstart > 32767. || loopstart < -32767.) {
611 		coarse = (short)(loopstart/32768.);
612 		fine = (short)(loopstart - (float)(coarse)*32768.);
613 	} else {
614 		coarse = 0;
615 		fine = (short)loopstart;
616 	}
617 	izone->gen[GEN_STARTLOOPADDROFS].flags = GEN_SET;
618 	izone->gen[GEN_STARTLOOPADDROFS].val = fine;
619 	fluid_rampreset_updatevoices(preset, GEN_STARTLOOPADDROFS, fine);
620 	if (coarse) {
621 		izone->gen[GEN_STARTLOOPADDRCOARSEOFS].flags = GEN_SET;
622 		izone->gen[GEN_STARTLOOPADDRCOARSEOFS].val = coarse;
623 	} else {
624 		izone->gen[GEN_STARTLOOPADDRCOARSEOFS].flags = GEN_UNUSED;
625 	}
626 	fluid_rampreset_updatevoices(preset, GEN_STARTLOOPADDRCOARSEOFS, coarse);
627 
628 	/* loopend */
629 	if (loopend > 32767. || loopend < -32767.) {
630 		coarse = (short)(loopend/32768.);
631 		fine = (short)(loopend - (float)(coarse)*32768.);
632 	} else {
633 		coarse = 0;
634 		fine = (short)loopend;
635 	}
636 	izone->gen[GEN_ENDLOOPADDROFS].flags = GEN_SET;
637 	izone->gen[GEN_ENDLOOPADDROFS].val = fine;
638 	fluid_rampreset_updatevoices(preset, GEN_ENDLOOPADDROFS, fine);
639 	if (coarse) {
640 		izone->gen[GEN_ENDLOOPADDRCOARSEOFS].flags = GEN_SET;
641 		izone->gen[GEN_ENDLOOPADDRCOARSEOFS].val = coarse;
642 	} else {
643 		izone->gen[GEN_ENDLOOPADDRCOARSEOFS].flags = GEN_UNUSED;
644 	}
645 	fluid_rampreset_updatevoices(preset, GEN_ENDLOOPADDRCOARSEOFS, coarse);
646 
647 	izone->gen[GEN_SAMPLEMODE].flags = GEN_SET;
648 	izone->gen[GEN_SAMPLEMODE].val = FLUID_LOOP_DURING_RELEASE;
649 	fluid_rampreset_updatevoices(preset, GEN_SAMPLEMODE, FLUID_LOOP_DURING_RELEASE);
650 
651 	/* If the loop points are the whole samples, we are supposed to
652 	   copy the frames around in the margins (the start to the end margin and
653 	   the end to the start margin), but it works fine without this. Maybe some time
654 	   it will be needed (see SAMPLE_LOOP_MARGIN) -- Antoie Schmitt May 2003 */
655 
656 	return FLUID_OK;
657 }
658 
fluid_rampreset_izone_set_gen(fluid_rampreset_t * preset,fluid_sample_t * sample,int gen_type,float value)659 int fluid_rampreset_izone_set_gen(fluid_rampreset_t* preset, fluid_sample_t* sample,
660        int gen_type, float value) {
661 	fluid_inst_zone_t* izone = fluid_rampreset_izoneforsample(preset, sample);
662 	if (izone == NULL)
663 			return FLUID_FAILED;
664 
665 	izone->gen[gen_type].flags = GEN_SET;
666 	izone->gen[gen_type].val = value;
667 
668 	fluid_rampreset_updatevoices(preset, gen_type, value);
669 
670 	return FLUID_OK;
671 }
672 
fluid_rampreset_remove_izone(fluid_rampreset_t * preset,fluid_sample_t * sample)673 int fluid_rampreset_remove_izone(fluid_rampreset_t* preset, fluid_sample_t* sample) {
674 	fluid_inst_t* inst;
675 	fluid_inst_zone_t* izone, * prev;
676 	int found = 0;
677 
678 	if (preset->zone == NULL) return FLUID_FAILED;
679 	inst = fluid_preset_zone_get_inst(preset->zone);
680 	izone = inst->zone;
681 	prev = NULL;
682 	while (izone && !found) {
683 		if (izone->sample == sample) {
684 			if (prev == NULL) {
685 				inst->zone = izone->next;
686 			} else {
687 				prev->next = izone->next;
688 			}
689 			izone->next = NULL;
690 			delete_fluid_inst_zone(izone);
691 			found = 1;
692 		} else {
693 			prev = izone;
694 			izone = izone->next;
695 		}
696 	}
697 	if (!found)
698 		return FLUID_FAILED;
699 
700 	// stop all the voices that use this sample, so that
701 	// the sample can be cleared up
702 	{
703 		fluid_list_t *tmp = preset->presetvoices;
704 		while (tmp) {
705 			fluid_rampreset_voice_t *presetvoice = (fluid_rampreset_voice_t *)(tmp->data);
706 			fluid_voice_t *voice = presetvoice->voice;
707 			if (fluid_voice_is_playing(voice) && (fluid_voice_get_id(voice) == presetvoice->voiceID)) {
708 				// still belongs to the preset
709 				if (voice->sample == sample) {
710 					// uses this sample : turn it off.
711 					// our presetvoices struct will be cleaneup at the next update
712 					fluid_voice_off(voice);
713 				}
714 			}
715 			tmp = tmp->next;
716 		}
717 	}
718 	return FLUID_OK;
719 }
720 
721 /*
722  * fluid_rampreset_remembervoice
723  */
724 int
fluid_rampreset_remembervoice(fluid_rampreset_t * preset,fluid_voice_t * voice)725 fluid_rampreset_remembervoice(fluid_rampreset_t* preset, fluid_voice_t* voice) {
726 	/* stores the voice and the its ID in the preset for later update on gen_set */
727 	fluid_rampreset_voice_t *presetvoice = FLUID_NEW(fluid_rampreset_voice_t);
728 	if (presetvoice == NULL) {
729     FLUID_LOG(FLUID_ERR, "Out of memory");
730     return FLUID_FAILED;
731   }
732 
733   presetvoice->voice = voice;
734   presetvoice->voiceID = fluid_voice_get_id(voice);
735 
736   preset->presetvoices = fluid_list_append(preset->presetvoices, (void *)presetvoice);
737   if (preset->presetvoices == NULL) {
738   	FLUID_FREE(presetvoice);
739     FLUID_LOG(FLUID_ERR, "Out of memory");
740     return FLUID_FAILED;
741   }
742   return FLUID_OK;
743 }
744 
745 /*
746  * fluid_rampreset_updatevoice
747  */
748 void
fluid_rampreset_updatevoices(fluid_rampreset_t * preset,int gen_type,float val)749 fluid_rampreset_updatevoices(fluid_rampreset_t* preset, int gen_type, float val) {
750 	fluid_list_t *tmp = preset->presetvoices, *prev = NULL, *next;
751 
752 	/* walk the presetvoice to update them if they are still active and ours.
753 	   If their ID has changed or their state is not playing, they are not ours, so we forget them
754 	*/
755 	while (tmp) {
756 		fluid_rampreset_voice_t *presetvoice = (fluid_rampreset_voice_t *)(tmp->data);
757 		fluid_voice_t *voice = presetvoice->voice;
758 		if (!fluid_voice_is_playing(voice) || (fluid_voice_get_id(voice) != presetvoice->voiceID)) {
759 			/* forget it */
760   		FLUID_FREE(presetvoice);
761 
762 			/* unlink it */
763 			next = tmp->next;
764   		FLUID_FREE(tmp);
765 			if (prev) {
766 				prev->next = next;
767 			} else {
768 				preset->presetvoices = next;
769 			}
770   		tmp = next;
771 
772 		} else {
773 
774 			/* update */
775 			fluid_voice_gen_set(voice, gen_type, val);
776 			fluid_voice_update_param(voice, gen_type);
777 
778 			/* next */
779 			prev = tmp;
780 			tmp = tmp->next;
781 		}
782 	}
783 }
784 
785 
786 /*
787  * fluid_rampreset_noteon
788  */
789 int
fluid_rampreset_noteon(fluid_rampreset_t * preset,fluid_synth_t * synth,int chan,int key,int vel)790 fluid_rampreset_noteon(fluid_rampreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel)
791 {
792   fluid_preset_zone_t *preset_zone;
793   fluid_inst_t* inst;
794   fluid_inst_zone_t *inst_zone, *global_inst_zone, *z;
795   fluid_sample_t* sample;
796   fluid_voice_t* voice;
797   fluid_mod_t * mod;
798   fluid_mod_t * mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */
799   int mod_list_count;
800   int i;
801 
802   /* run thru all the zones of this preset */
803   preset_zone = preset->zone;
804   while (preset_zone != NULL) {
805 
806     /* check if the note falls into the key and velocity range of this
807        preset */
808     if (fluid_preset_zone_inside_range(preset_zone, key, vel)) {
809 
810       inst = fluid_preset_zone_get_inst(preset_zone);
811       global_inst_zone = fluid_inst_get_global_zone(inst);
812 
813       /* run thru all the zones of this instrument */
814       inst_zone = fluid_inst_get_zone(inst);
815       while (inst_zone != NULL) {
816 
817 	/* make sure this instrument zone has a valid sample */
818 	sample = fluid_inst_zone_get_sample(inst_zone);
819 	if (fluid_sample_in_rom(sample) || (sample == NULL)) {
820 	  inst_zone = fluid_inst_zone_next(inst_zone);
821 	  continue;
822 	}
823 
824 	/* check if the note falls into the key and velocity range of this
825 	   instrument */
826 
827 	if (fluid_inst_zone_inside_range(inst_zone, key, vel) && (sample != NULL)) {
828 
829 	  /* this is a good zone. allocate a new synthesis process and
830              initialize it */
831 
832 	  voice = fluid_synth_alloc_voice(synth, sample, chan, key, vel);
833 	  if (voice == NULL) {
834 	    return FLUID_FAILED;
835 	  }
836 
837 	  if (fluid_rampreset_remembervoice(preset, voice) != FLUID_OK) {
838 	    return FLUID_FAILED;
839 	  }
840 
841 	  z = inst_zone;
842 
843 	  /* Instrument level, generators */
844 
845 	  for (i = 0; i < GEN_LAST; i++) {
846 
847 	    /* SF 2.01 section 9.4 'bullet' 4:
848 	     *
849 	     * A generator in a local instrument zone supersedes a
850 	     * global instrument zone generator.  Both cases supersede
851 	     * the default generator -> voice_gen_set */
852 
853 	    if (inst_zone->gen[i].flags){
854 	      fluid_voice_gen_set(voice, i, inst_zone->gen[i].val);
855 
856 	    } else if (global_inst_zone != NULL && global_inst_zone->gen[i].flags){
857 	      fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val);
858 
859 	    } else {
860 	      /* The generator has not been defined in this instrument.
861 	       * Do nothing, leave it at the default.
862 	       */
863 	    };
864 
865 	  }; /* for all generators */
866 
867 	  /* global instrument zone, modulators: Put them all into a
868 	   * list. */
869 
870 	  mod_list_count = 0;
871 
872 	  if (global_inst_zone){
873 	    mod = global_inst_zone->mod;
874 	    while (mod){
875 	      mod_list[mod_list_count++] = mod;
876 	      mod = mod->next;
877 	    };
878 	  };
879 
880 	  /* local instrument zone, modulators.
881 	   * Replace modulators with the same definition in the list:
882 	   * SF 2.01 page 69, 'bullet' 8
883 	   */
884 	  mod = inst_zone->mod;
885 
886 	  while (mod){
887 
888 	    /* 'Identical' modulators will be deleted by setting their
889 	     *  list entry to NULL.  The list length is known, NULL
890 	     *  entries will be ignored later.  SF2.01 section 9.5.1
891 	     *  page 69, 'bullet' 3 defines 'identical'.  */
892 
893 	    for (i = 0; i < mod_list_count; i++){
894 	      if (fluid_mod_test_identity(mod,mod_list[i])){
895 		mod_list[i] = NULL;
896 	      };
897 	    };
898 
899 	    /* Finally add the new modulator to to the list. */
900 	    mod_list[mod_list_count++] = mod;
901 	    mod = mod->next;
902 	  };
903 
904 	  /* Add instrument modulators (global / local) to the voice. */
905 	  for (i = 0; i < mod_list_count; i++){
906 
907 	    mod = mod_list[i];
908 
909 	    if (mod != NULL){ /* disabled modulators CANNOT be skipped. */
910 
911 	      /* Instrument modulators -supersede- existing (default)
912 	       * modulators.  SF 2.01 page 69, 'bullet' 6 */
913 	      fluid_voice_add_mod(voice, mod, FLUID_VOICE_OVERWRITE);
914 	    };
915 	  };
916 
917 	  /* Preset level, generators */
918 
919 	  for (i = 0; i < GEN_LAST; i++) {
920 
921 	    /* SF 2.01 section 8.5 page 58: If some generators are
922 	     * encountered at preset level, they should be ignored */
923 	    if ((i != GEN_STARTADDROFS)
924 		&& (i != GEN_ENDADDROFS)
925 		&& (i != GEN_STARTLOOPADDROFS)
926 		&& (i != GEN_ENDLOOPADDROFS)
927 		&& (i != GEN_STARTADDRCOARSEOFS)
928 		&& (i != GEN_ENDADDRCOARSEOFS)
929 		&& (i != GEN_STARTLOOPADDRCOARSEOFS)
930 		&& (i != GEN_KEYNUM)
931 		&& (i != GEN_VELOCITY)
932 		&& (i != GEN_ENDLOOPADDRCOARSEOFS)
933 		&& (i != GEN_SAMPLEMODE)
934 		&& (i != GEN_EXCLUSIVECLASS)
935 		&& (i != GEN_OVERRIDEROOTKEY)) {
936 
937 	      /* SF 2.01 section 9.4 'bullet' 9: A generator in a
938 	       * local preset zone supersedes a global preset zone
939 	       * generator.  The effect is -added- to the destination
940 	       * summing node -> voice_gen_incr */
941 
942 	      if (preset_zone->gen[i].flags){
943 		fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val);
944 	      } else {
945 		/* The generator has not been defined in this preset
946 		 * Do nothing, leave it unchanged.
947 		 */
948 	      };
949 	    }; /* if available at preset level */
950 	  }; /* for all generators */
951 
952 
953 	  /* Global preset zone, modulators: put them all into a
954 	   * list. */
955 	  mod_list_count = 0;
956 
957 	  /* Process the modulators of the local preset zone.  Kick
958 	   * out all identical modulators from the global preset zone
959 	   * (SF 2.01 page 69, second-last bullet) */
960 
961 	  mod = preset_zone->mod;
962 	  while (mod){
963 	    for (i = 0; i < mod_list_count; i++){
964 	      if (fluid_mod_test_identity(mod,mod_list[i])){
965 		mod_list[i] = NULL;
966 	      };
967 	    };
968 
969 	    /* Finally add the new modulator to the list. */
970 	    mod_list[mod_list_count++] = mod;
971 	    mod = mod->next;
972 	  };
973 
974 	  /* Add preset modulators (global / local) to the voice. */
975 	  for (i = 0; i < mod_list_count; i++){
976 	    mod = mod_list[i];
977 	    if ((mod != NULL) && (mod->amount != 0)) { /* disabled modulators can be skipped. */
978 
979 	      /* Preset modulators -add- to existing instrument /
980 	       * default modulators.  SF2.01 page 70 first bullet on
981 	       * page */
982 	      fluid_voice_add_mod(voice, mod, FLUID_VOICE_ADD);
983 	    };
984 	  };
985 
986 	  /* add the synthesis process to the synthesis loop. */
987 	  fluid_synth_start_voice(synth, voice);
988 
989 	  /* Store the ID of the first voice that was created by this noteon event.
990 	   * Exclusive class may only terminate older voices.
991 	   * That avoids killing voices, which have just been created.
992 	   * (a noteon event can create several voice processes with the same exclusive
993 	   * class - for example when using stereo samples)
994 	   */
995 	}
996 
997 	inst_zone = fluid_inst_zone_next(inst_zone);
998       }
999     }
1000     preset_zone = fluid_preset_zone_next(preset_zone);
1001   }
1002 
1003   return FLUID_OK;
1004 }
1005 
1006 
1007 
1008 /***************************************************************
1009  *
1010  *                           SAMPLE
1011  */
1012 
1013 
1014 
1015 /*
1016  * fluid_sample_set_name
1017  */
1018 int
fluid_sample_set_name(fluid_sample_t * sample,char * name)1019 fluid_sample_set_name(fluid_sample_t* sample, char * name)
1020 {
1021   FLUID_MEMCPY(sample->name, name, 20);
1022   return FLUID_OK;
1023 }
1024 
1025 /*
1026  * fluid_sample_set_sound_data
1027  */
1028 int
fluid_sample_set_sound_data(fluid_sample_t * sample,short * data,unsigned int nbframes,short copy_data,int rootkey)1029 fluid_sample_set_sound_data(fluid_sample_t* sample, short *data, unsigned int nbframes, short copy_data, int rootkey)
1030 {
1031 	/* 16 bit mono 44.1KHz data in */
1032 	/* in all cases, the sample has ownership of the data : it will release it in the end */
1033 	unsigned int storedNbFrames;
1034 
1035 	/* in case we already have some data */
1036   if (sample->data != NULL) {
1037   	FLUID_FREE(sample->data);
1038   }
1039 
1040 	if (copy_data) {
1041 
1042 		/* nbframes should be >= 48 (SoundFont specs) */
1043 		storedNbFrames = nbframes;
1044 		if (storedNbFrames < 48) storedNbFrames = 48;
1045 
1046 	  sample->data = FLUID_MALLOC(storedNbFrames*2 + 4*SAMPLE_LOOP_MARGIN);
1047 	  if (sample->data == NULL) {
1048 	    FLUID_LOG(FLUID_ERR, "Out of memory");
1049 	    return FLUID_FAILED;
1050 	  }
1051 	  FLUID_MEMSET(sample->data, 0, storedNbFrames*2 + 4*SAMPLE_LOOP_MARGIN);
1052 	  FLUID_MEMCPY((char*)(sample->data) + 2*SAMPLE_LOOP_MARGIN, data, nbframes*2);
1053 
1054 #if 0
1055 	  /* this would do the fill of the margins */
1056 	  FLUID_MEMCPY((char*)(sample->data) + 2*SAMPLE_LOOP_MARGIN + storedNbFrames*2, (char*)data, 2*SAMPLE_LOOP_MARGIN);
1057 	  FLUID_MEMCPY((char*)(sample->data), (char*)data + nbframes*2 - 2*SAMPLE_LOOP_MARGIN, 2*SAMPLE_LOOP_MARGIN);
1058 #endif
1059 
1060 	  /* pointers */
1061 	  /* all from the start of data */
1062 	  sample->start = SAMPLE_LOOP_MARGIN;
1063 	  sample->end = SAMPLE_LOOP_MARGIN + storedNbFrames;
1064   } else {
1065   	/* we cannot assure the SAMPLE_LOOP_MARGIN */
1066   	sample->data = data;
1067 	  sample->start = 0;
1068 	  sample->end = nbframes;
1069   }
1070 
1071   /* only used as markers for the LOOP generators : set them on the first real frame */
1072   sample->loopstart = sample->start;
1073   sample->loopend = sample->end;
1074 
1075   sample->samplerate = 44100;
1076   sample->origpitch = rootkey;
1077   sample->pitchadj = 0;
1078   sample->sampletype = FLUID_SAMPLETYPE_MONO;
1079   sample->valid = 1;
1080 
1081   return FLUID_OK;
1082 }
1083 
1084 /*
1085  * new_fluid_ramsample
1086  */
1087 fluid_sample_t*
new_fluid_ramsample()1088 new_fluid_ramsample()
1089 {
1090 	/* same as new_fluid_sample. Only here so that it is exported */
1091   fluid_sample_t* sample = NULL;
1092 
1093   sample = FLUID_NEW(fluid_sample_t);
1094   if (sample == NULL) {
1095     FLUID_LOG(FLUID_ERR, "Out of memory");
1096     return NULL;
1097   }
1098 
1099   memset(sample, 0, sizeof(fluid_sample_t));
1100 
1101   return sample;
1102 }
1103 
1104 /*
1105  * delete_fluid_ramsample
1106  */
1107 int
delete_fluid_ramsample(fluid_sample_t * sample)1108 delete_fluid_ramsample(fluid_sample_t* sample)
1109 {
1110 	/* same as delete_fluid_sample, plus frees the data */
1111   if (sample->data != NULL) {
1112   	FLUID_FREE(sample->data);
1113   }
1114   sample->data = NULL;
1115   FLUID_FREE(sample);
1116   return FLUID_OK;
1117 }
1118