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 */
29int fluid_rampreset_add_sample(fluid_rampreset_t* preset, fluid_sample_t* sample, int lokey, int hikey);
30int fluid_rampreset_izone_set_gen(fluid_rampreset_t* preset, fluid_sample_t* sample, int gen_type, float value);
31int fluid_rampreset_izone_set_loop(fluid_rampreset_t* preset, fluid_sample_t* sample, int on, float loopstart, float loopend);
32int fluid_rampreset_remove_izone(fluid_rampreset_t* preset, fluid_sample_t* sample);
33void fluid_rampreset_updatevoices(fluid_rampreset_t* preset, int gen_type, float val);
34
35/*
36 * fluid_ramsfont_create_sfont
37 */
38fluid_sfont_t*
39fluid_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
71int 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
79char* fluid_ramsfont_sfont_get_name(fluid_sfont_t* sfont)
80{
81  return fluid_ramsfont_get_name((fluid_ramsfont_t*) sfont->data);
82}
83
84fluid_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
113void fluid_ramsfont_sfont_iteration_start(fluid_sfont_t* sfont)
114{
115  fluid_ramsfont_iteration_start((fluid_ramsfont_t*) sfont->data);
116}
117
118int 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
130int fluid_rampreset_preset_delete(fluid_preset_t* preset)
131{
132  FLUID_FREE(preset);
133
134/* TODO: free modulators */
135
136  return 0;
137}
138
139char* fluid_rampreset_preset_get_name(fluid_preset_t* preset)
140{
141  return fluid_rampreset_get_name((fluid_rampreset_t*) preset->data);
142}
143
144int fluid_rampreset_preset_get_banknum(fluid_preset_t* preset)
145{
146  return fluid_rampreset_get_banknum((fluid_rampreset_t*) preset->data);
147}
148
149int fluid_rampreset_preset_get_num(fluid_preset_t* preset)
150{
151  return fluid_rampreset_get_num((fluid_rampreset_t*) preset->data);
152}
153
154int 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 */
170fluid_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 */
190int 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 */
227char* fluid_ramsfont_get_name(fluid_ramsfont_t* sfont)
228{
229  return sfont->name;
230}
231
232/*
233 * fluid_ramsfont_set_name
234 */
235int
236fluid_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 */
247int 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 */
281int 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
323int 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 */
345int 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 */
358int 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 */
372fluid_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 */
387void fluid_ramsfont_iteration_start(fluid_ramsfont_t* sfont)
388{
389  sfont->iter_cur = sfont->preset;
390}
391
392/*
393 * fluid_ramsfont_iteration_next
394 */
395int 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
411typedef struct _fluid_rampreset_voice_t fluid_rampreset_voice_t;
412struct _fluid_rampreset_voice_t {
413	fluid_voice_t *voice;
414	unsigned int voiceID;
415};
416
417/*
418 * new_fluid_rampreset
419 */
420fluid_rampreset_t*
421new_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 */
442int
443delete_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
481int
482fluid_rampreset_get_banknum(fluid_rampreset_t* preset)
483{
484  return preset->bank;
485}
486
487int
488fluid_rampreset_get_num(fluid_rampreset_t* preset)
489{
490  return preset->num;
491}
492
493char*
494fluid_rampreset_get_name(fluid_rampreset_t* preset)
495{
496  return preset->name;
497}
498
499/*
500 * fluid_rampreset_next
501 */
502fluid_rampreset_t*
503fluid_rampreset_next(fluid_rampreset_t* preset)
504{
505  return preset->next;
506}
507
508
509/*
510 * fluid_rampreset_add_zone
511 */
512int
513fluid_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 */
529int 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
575fluid_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
592int 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
659int 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
673int 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 */
724int
725fluid_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 */
748void
749fluid_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 */
789int
790fluid_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 */
1018int
1019fluid_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 */
1028int
1029fluid_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 */
1087fluid_sample_t*
1088new_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 */
1107int
1108delete_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