# src/fluid_ramsfont.c

    00001 /* FluidSynth - A Software Synthesizer
    00002  *
    00003  * Copyright (C) 2003  Peter Hanappe and others.
    00004  *
    00005  * This library is free software; you can redistribute it and/or
    00006  * modify it under the terms of the GNU Library General Public License
    00007  * as published by the Free Software Foundation; either version 2 of
    00008  * the License, or (at your option) any later version.
    00009  *
    00010  * This library is distributed in the hope that it will be useful, but
    00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013  * Library General Public License for more details.
    00014  *
    00015  * You should have received a copy of the GNU Library General Public
    00016  * License along with this library; if not, write to the Free
    00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    00018  * 02111-1307, USA
    00019  */
    00020
    00021 #include "fluid_ramsfont.h"
    00022 #include "fluid_sys.h"
    00023 #include "fluid_synth.h"
    00024
    00025 /* thenumber of samples before the start and after the end */
    00026 #define SAMPLE_LOOP_MARGIN 8
    00027
    00028 /* Prototypes */
    00029 int fluid_rampreset_add_sample(fluid_rampreset_t* preset, fluid_sample_t* sample, int lokey, int hikey);
    00030 int fluid_rampreset_izone_set_gen(fluid_rampreset_t* preset, fluid_sample_t* sample, int gen_type, float value);
    00031 int fluid_rampreset_izone_set_loop(fluid_rampreset_t* preset, fluid_sample_t* sample, int on, float loopstart, float loopend);
    00032 int fluid_rampreset_remove_izone(fluid_rampreset_t* preset, fluid_sample_t* sample);
    00033 void fluid_rampreset_updatevoices(fluid_rampreset_t* preset, int gen_type, float val);
    00034
    00035 /*
    00036  * fluid_ramsfont_create_sfont
    00037  */
    00038 fluid_sfont_t*
    00039 fluid_ramsfont_create_sfont()
    00040 {
    00041         fluid_sfont_t* sfont;
    00042         fluid_ramsfont_t* ramsfont;
    00043
    00044         ramsfont = new_fluid_ramsfont();
    00045         if (ramsfont == NULL) {
    00046     return NULL;
    00047   }
    00048
    00049   sfont = FLUID_NEW(fluid_sfont_t);
    00050   if (sfont == NULL) {
    00051     FLUID_LOG(FLUID_ERR, "Out of memory");
    00052     return NULL;
    00053   }
    00054
    00055   sfont->data = ramsfont;
    00056   sfont->free = fluid_ramsfont_sfont_delete;
    00057   sfont->get_name = fluid_ramsfont_sfont_get_name;
    00058   sfont->get_preset = fluid_ramsfont_sfont_get_preset;
    00059   sfont->iteration_start = fluid_ramsfont_sfont_iteration_start;
    00060   sfont->iteration_next = fluid_ramsfont_sfont_iteration_next;
    00061
    00062   return sfont;
    00063
    00064 }
    00065
    00066 /***************************************************************
    00067  *
    00068  *                           PUBLIC INTERFACE
    00069  */
    00070
    00071 int fluid_ramsfont_sfont_delete(fluid_sfont_t* sfont)
    00072 {
    00073         if (delete_fluid_ramsfont(sfont->data) != 0)
    00074                 return -1;
    00075         FLUID_FREE(sfont);
    00076         return 0;
    00077 }
    00078
    00079 char* fluid_ramsfont_sfont_get_name(fluid_sfont_t* sfont)
    00080 {
    00081   return fluid_ramsfont_get_name((fluid_ramsfont_t*) sfont->data);
    00082 }
    00083
    00084 fluid_preset_t* fluid_ramsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum)
    00085 {
    00086   fluid_preset_t* preset;
    00087   fluid_rampreset_t* rampreset;
    00088
    00089   rampreset = fluid_ramsfont_get_preset((fluid_ramsfont_t*) sfont->data, bank, prenum);
    00090
    00091   if (rampreset == NULL) {
    00092     return NULL;
    00093   }
    00094
    00095   preset = FLUID_NEW(fluid_preset_t);
    00096   if (preset == NULL) {
    00097     FLUID_LOG(FLUID_ERR, "Out of memory");
    00098     return NULL;
    00099   }
    00100
    00101   preset->sfont = sfont;
    00102   preset->data = rampreset;
    00103   preset->free = fluid_rampreset_preset_delete;
    00104   preset->get_name = fluid_rampreset_preset_get_name;
    00105   preset->get_banknum = fluid_rampreset_preset_get_banknum;
    00106   preset->get_num = fluid_rampreset_preset_get_num;
    00107   preset->noteon = fluid_rampreset_preset_noteon;
    00108   preset->notify = NULL;
    00109
    00110   return preset;
    00111 }
    00112
    00113 void fluid_ramsfont_sfont_iteration_start(fluid_sfont_t* sfont)
    00114 {
    00115   fluid_ramsfont_iteration_start((fluid_ramsfont_t*) sfont->data);
    00116 }
    00117
    00118 int fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset)
    00119 {
    00120   preset->free = fluid_rampreset_preset_delete;
    00121   preset->get_name = fluid_rampreset_preset_get_name;
    00122   preset->get_banknum = fluid_rampreset_preset_get_banknum;
    00123   preset->get_num = fluid_rampreset_preset_get_num;
    00124   preset->noteon = fluid_rampreset_preset_noteon;
    00125   preset->notify = NULL;
    00126
    00127   return fluid_ramsfont_iteration_next((fluid_ramsfont_t*) sfont->data, preset);
    00128 }
    00129
    00130 int fluid_rampreset_preset_delete(fluid_preset_t* preset)
    00131 {
    00132   FLUID_FREE(preset);
    00133
    00134 /* TODO: free modulators */
    00135
    00136   return 0;
    00137 }
    00138
    00139 char* fluid_rampreset_preset_get_name(fluid_preset_t* preset)
    00140 {
    00141   return fluid_rampreset_get_name((fluid_rampreset_t*) preset->data);
    00142 }
    00143
    00144 int fluid_rampreset_preset_get_banknum(fluid_preset_t* preset)
    00145 {
    00146   return fluid_rampreset_get_banknum((fluid_rampreset_t*) preset->data);
    00147 }
    00148
    00149 int fluid_rampreset_preset_get_num(fluid_preset_t* preset)
    00150 {
    00151   return fluid_rampreset_get_num((fluid_rampreset_t*) preset->data);
    00152 }
    00153
    00154 int fluid_rampreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel)
    00155 {
    00156   return fluid_rampreset_noteon((fluid_rampreset_t*) preset->data, synth, chan, key, vel);
    00157 }
    00158
    00159
    00160
    00161
    00162 /***************************************************************
    00163  *
    00164  *                           SFONT
    00165  */
    00166
    00167 /*
    00168  * new_fluid_ramsfont
    00169  */
    00170 fluid_ramsfont_t* new_fluid_ramsfont()
    00171 {
    00172   fluid_ramsfont_t* sfont;
    00173
    00174   sfont = FLUID_NEW(fluid_ramsfont_t);
    00175   if (sfont == NULL) {
    00176     FLUID_LOG(FLUID_ERR, "Out of memory");
    00177     return NULL;
    00178   }
    00179
    00180   sfont->name[0] = 0;
    00181   sfont->sample = NULL;
    00182   sfont->preset = NULL;
    00183
    00184   return sfont;
    00185 }
    00186
    00187 /*
    00188  * delete_fluid_ramsfont
    00189  */
    00190 int delete_fluid_ramsfont(fluid_ramsfont_t* sfont)
    00191 {
    00192   fluid_list_t *list;
    00193   fluid_rampreset_t* preset;
    00194
    00195   /* Check that no samples are currently used */
    00196   for (list = sfont->sample; list; list = fluid_list_next(list)) {
    00197     fluid_sample_t* sam = (fluid_sample_t*) fluid_list_get(list);
    00198     if (fluid_sample_refcount(sam) != 0) {
    00199       return -1;
    00200     }
    00201   }
    00202
    00203   for (list = sfont->sample; list; list = fluid_list_next(list)) {
    00204         /* in ram soundfonts, the samples hold their data : so we should free it ourselves */
    00205         fluid_sample_t* sam = (fluid_sample_t*)fluid_list_get(list);
    00206     delete_fluid_ramsample(sam);
    00207   }
    00208
    00209   if (sfont->sample) {
    00210     delete_fluid_list(sfont->sample);
    00211   }
    00212
    00213   preset = sfont->preset;
    00214   while (preset != NULL) {
    00215     sfont->preset = preset->next;
    00216     delete_fluid_rampreset(preset);
    00217     preset = sfont->preset;
    00218   }
    00219
    00220   FLUID_FREE(sfont);
    00221   return FLUID_OK;
    00222 }
    00223
    00224 /*
    00225  * fluid_ramsfont_get_name
    00226  */
    00227 char* fluid_ramsfont_get_name(fluid_ramsfont_t* sfont)
    00228 {
    00229   return sfont->name;
    00230 }
    00231
    00232 /*
    00233  * fluid_ramsfont_set_name
    00234  */
    00235 int
    00236 fluid_ramsfont_set_name(fluid_ramsfont_t* sfont, char * name)
    00237 {
    00238   FLUID_MEMCPY(sfont->name, name, 20);
    00239   return FLUID_OK;
    00240 }
    00241
    00242
    00243 /* fluid_ramsfont_add_preset
    00244  *
    00245  * Add a preset to the SoundFont
    00246  */
    00247 int fluid_ramsfont_add_preset(fluid_ramsfont_t* sfont, fluid_rampreset_t* preset)
    00248 {
    00249   fluid_rampreset_t *cur, *prev;
    00250   if (sfont->preset == NULL) {
    00251     preset->next = NULL;
    00252     sfont->preset = preset;
    00253   } else {
    00254     /* sort them as we go along. very basic sorting trick. */
    00255     cur = sfont->preset;
    00256     prev = NULL;
    00257     while (cur != NULL) {
    00258       if ((preset->bank < cur->bank)
    00259           || ((preset->bank == cur->bank) && (preset->num < cur->num))) {
    00260         if (prev == NULL) {
    00261           preset->next = cur;
    00262           sfont->preset = preset;
    00263         } else {
    00264           preset->next = cur;
    00265           prev->next = preset;
    00266         }
    00267         return FLUID_OK;
    00268       }
    00269       prev = cur;
    00270       cur = cur->next;
    00271     }
    00272     preset->next = NULL;
    00273     prev->next = preset;
    00274   }
    00275   return FLUID_OK;
    00276 }
    00277
    00278 /*
    00279  * fluid_ramsfont_add_ramsample
    00280  */
    00281 int fluid_ramsfont_add_izone(fluid_ramsfont_t* sfont,
    00282                                 unsigned int bank, unsigned int num, fluid_sample_t* sample,
    00283                                 int lokey, int hikey)
    00284 {
    00285         /*- find or create a preset
    00286                 - add it the sample using the fluid_rampreset_add_sample fucntion
    00287                 - add the sample to the list of samples
    00288         */
    00289         int err;
    00290
    00291         fluid_rampreset_t* preset = fluid_ramsfont_get_preset(sfont, bank, num);
    00292         if (preset == NULL) {
    00293                 // Create it
    00294                 preset = new_fluid_rampreset(sfont);
    00295                 if (preset == NULL) {
    00296                         return FLUID_FAILED;
    00297                 }
    00298
    00299                 preset->bank = bank;
    00300                 preset->num = num;
    00301
    00302                 err = fluid_rampreset_add_sample(preset, sample, lokey, hikey);
    00303                 if (err != FLUID_OK) {
    00304                         return FLUID_FAILED;
    00305                 }
    00306
    00307                 // sort the preset
    00308                 fluid_ramsfont_add_preset(sfont, preset);
    00309
    00310         } else {
    00311
    00312                 // just add it
    00313                 err = fluid_rampreset_add_sample(preset, sample, lokey, hikey);
    00314                 if (err != FLUID_OK) {
    00315                         return FLUID_FAILED;
    00316                 }
    00317         }
    00318
    00319   sfont->sample = fluid_list_append(sfont->sample, sample);
    00320   return FLUID_OK;
    00321 }
    00322
    00323 int fluid_ramsfont_remove_izone(fluid_ramsfont_t* sfont,
    00324          unsigned int bank, unsigned int num, fluid_sample_t* sample) {
    00325         int err;
    00326         fluid_rampreset_t* preset = fluid_ramsfont_get_preset(sfont, bank, num);
    00327         if (preset == NULL) {
    00328                 return FLUID_FAILED;
    00329         }
    00330
    00331         // Fixed a crash bug : remove the sample from the sfont list after
    00332         // removing the izone (aschmitt august 2005)
    00333         err = fluid_rampreset_remove_izone(preset, sample);
    00334         if (err != FLUID_OK)
    00335                 return err;
    00336
    00337         // now we must remove the sample from sfont->sample
    00338         sfont->sample = fluid_list_remove(sfont->sample, sample);
    00339
    00340         return FLUID_OK;
    00341 }
    00342
    00343
    00344 /* Note for version 2.0 : missing API fluid_ramsfont_izone_get_gen - Antoine Schmitt May 2003 */
    00345 int fluid_ramsfont_izone_set_gen(fluid_ramsfont_t* sfont,
    00346                                 unsigned int bank, unsigned int num, fluid_sample_t* sample,
    00347                                 int gen_type, float value) {
    00348
    00349         fluid_rampreset_t* preset = fluid_ramsfont_get_preset(sfont, bank, num);
    00350         if (preset == NULL) {
    00351                         return FLUID_FAILED;
    00352         }
    00353
    00354         return fluid_rampreset_izone_set_gen(preset, sample, gen_type, value);
    00355 }
    00356
    00357 /* Note for version 2.0 : missing API fluid_ramsfont_izone_get_loop - Antoine Schmitt May 2003 */
    00358 int fluid_ramsfont_izone_set_loop(fluid_ramsfont_t* sfont,
    00359                                 unsigned int bank, unsigned int num, fluid_sample_t* sample,
    00360                                 int on, float loopstart, float loopend) {
    00361         fluid_rampreset_t* preset = fluid_ramsfont_get_preset(sfont, bank, num);
    00362         if (preset == NULL) {
    00363                         return FLUID_FAILED;
    00364         }
    00365
    00366         return fluid_rampreset_izone_set_loop(preset, sample, on, loopstart, loopend);
    00367 }
    00368
    00369 /*
    00370  * fluid_ramsfont_get_preset
    00371  */
    00372 fluid_rampreset_t* fluid_ramsfont_get_preset(fluid_ramsfont_t* sfont, unsigned int bank, unsigned int num)
    00373 {
    00374   fluid_rampreset_t* preset = sfont->preset;
    00375   while (preset != NULL) {
    00376     if ((preset->bank == bank) && ((preset->num == num))) {
    00377       return preset;
    00378     }
    00379     preset = preset->next;
    00380   }
    00381   return NULL;
    00382 }
    00383
    00384 /*
    00385  * fluid_ramsfont_iteration_start
    00386  */
    00387 void fluid_ramsfont_iteration_start(fluid_ramsfont_t* sfont)
    00388 {
    00389   sfont->iter_cur = sfont->preset;
    00390 }
    00391
    00392 /*
    00393  * fluid_ramsfont_iteration_next
    00394  */
    00395 int fluid_ramsfont_iteration_next(fluid_ramsfont_t* sfont, fluid_preset_t* preset)
    00396 {
    00397   if (sfont->iter_cur == NULL) {
    00398     return 0;
    00399   }
    00400
    00401   preset->data = (void*) sfont->iter_cur;
    00402   sfont->iter_cur = fluid_rampreset_next(sfont->iter_cur);
    00403   return 1;
    00404 }
    00405
    00406 /***************************************************************
    00407  *
    00408  *                           PRESET
    00409  */
    00410
    00411 typedef struct _fluid_rampreset_voice_t fluid_rampreset_voice_t;
    00412 struct _fluid_rampreset_voice_t {
    00413         fluid_voice_t *voice;
    00414         unsigned int voiceID;
    00415 };
    00416
    00417 /*
    00418  * new_fluid_rampreset
    00419  */
    00420 fluid_rampreset_t*
    00421 new_fluid_rampreset(fluid_ramsfont_t* sfont)
    00422 {
    00423   fluid_rampreset_t* preset = FLUID_NEW(fluid_rampreset_t);
    00424   if (preset == NULL) {
    00425     FLUID_LOG(FLUID_ERR, "Out of memory");
    00426     return NULL;
    00427   }
    00428   preset->next = NULL;
    00429   preset->sfont = sfont;
    00430   preset->name[0] = 0;
    00431   preset->bank = 0;
    00432   preset->num = 0;
    00433   preset->global_zone = NULL;
    00434   preset->zone = NULL;
    00435   preset->presetvoices = NULL;
    00436   return preset;
    00437 }
    00438
    00439 /*
    00440  * delete_fluid_rampreset
    00441  */
    00442 int
    00443 delete_fluid_rampreset(fluid_rampreset_t* preset)
    00444 {
    00445   int err = FLUID_OK;
    00446   fluid_preset_zone_t* zone;
    00447   fluid_rampreset_voice_t *data;
    00448
    00449   if (preset->global_zone != NULL) {
    00450     if (delete_fluid_preset_zone(preset->global_zone) != FLUID_OK) {
    00451       err = FLUID_FAILED;
    00452     }
    00453     preset->global_zone = NULL;
    00454   }
    00455   zone = preset->zone;
    00456   while (zone != NULL) {
    00457     preset->zone = zone->next;
    00458     if (delete_fluid_preset_zone(zone) != FLUID_OK) {
    00459       err = FLUID_FAILED;
    00460     }
    00461     zone = preset->zone;
    00462   }
    00463
    00464   if (preset->presetvoices != NULL) {
    00465         fluid_list_t *tmp = preset->presetvoices, *next;
    00466         while (tmp) {
    00467                 data = (fluid_rampreset_voice_t *)(tmp->data);
    00468                 FLUID_FREE(data);
    00469
    00470                 next = tmp->next;
    00471                 FLUID_FREE(tmp);
    00472                 tmp = next;
    00473         }
    00474   }
    00475   preset->presetvoices = NULL;
    00476
    00477   FLUID_FREE(preset);
    00478   return err;
    00479 }
    00480
    00481 int
    00482 fluid_rampreset_get_banknum(fluid_rampreset_t* preset)
    00483 {
    00484   return preset->bank;
    00485 }
    00486
    00487 int
    00488 fluid_rampreset_get_num(fluid_rampreset_t* preset)
    00489 {
    00490   return preset->num;
    00491 }
    00492
    00493 char*
    00494 fluid_rampreset_get_name(fluid_rampreset_t* preset)
    00495 {
    00496   return preset->name;
    00497 }
    00498
    00499 /*
    00500  * fluid_rampreset_next
    00501  */
    00502 fluid_rampreset_t*
    00503 fluid_rampreset_next(fluid_rampreset_t* preset)
    00504 {
    00505   return preset->next;
    00506 }
    00507
    00508
    00509 /*
    00510  * fluid_rampreset_add_zone
    00511  */
    00512 int
    00513 fluid_rampreset_add_zone(fluid_rampreset_t* preset, fluid_preset_zone_t* zone)
    00514 {
    00515   if (preset->zone == NULL) {
    00516     zone->next = NULL;
    00517     preset->zone = zone;
    00518   } else {
    00519     zone->next = preset->zone;
    00520     preset->zone = zone;
    00521   }
    00522   return FLUID_OK;
    00523 }
    00524
    00525
    00526 /*
    00527  * fluid_rampreset_add_sample
    00528  */
    00529 int fluid_rampreset_add_sample(fluid_rampreset_t* preset, fluid_sample_t* sample, int lokey, int hikey)
    00530 {
    00531         /* create a new instrument zone, with the given sample */
    00532
    00533         /* one preset zone */
    00534         if (preset->zone == NULL) {
    00535                 fluid_preset_zone_t* zone;
    00536                 zone = new_fluid_preset_zone("");
    00537                 if (zone == NULL) {
    00538                         return FLUID_FAILED;
    00539                 }
    00540
    00541                 /* its instrument */
    00542                 zone->inst = (fluid_inst_t*) new_fluid_inst();
    00543     if (zone->inst == NULL) {
    00544       delete_fluid_preset_zone(zone);
    00545       return FLUID_FAILED;
    00546     }
    00547
    00548                 fluid_rampreset_add_zone(preset, zone);
    00549         }
    00550
    00551         /* add an instrument zone for each sample */
    00552         {
    00553                 fluid_inst_t* inst = fluid_preset_zone_get_inst(preset->zone);
    00554                 fluid_inst_zone_t* izone = new_fluid_inst_zone("");
    00555                 if (izone == NULL) {
    00556                         return FLUID_FAILED;
    00557                 }
    00558
    00559                 if (fluid_inst_add_zone(inst, izone) != FLUID_OK) {
    00560                         delete_fluid_inst_zone(izone);
    00561                         return FLUID_FAILED;
    00562                 }
    00563
    00564                 izone->sample = sample;
    00565                 izone->keylo = lokey;
    00566                 izone->keyhi = hikey;
    00567
    00568                 // give the preset the name of the sample
    00569                 FLUID_MEMCPY(preset->name, sample->name, 20);
    00570         }
    00571
    00572         return FLUID_OK;
    00573 }
    00574
    00575 fluid_inst_zone_t* fluid_rampreset_izoneforsample(fluid_rampreset_t* preset, fluid_sample_t* sample)
    00576 {
    00577         fluid_inst_t* inst;
    00578         fluid_inst_zone_t* izone;
    00579
    00580         if (preset->zone == NULL) return NULL;
    00581
    00582         inst = fluid_preset_zone_get_inst(preset->zone);
    00583         izone = inst->zone;
    00584         while (izone) {
    00585                 if (izone->sample == sample)
    00586                         return izone;
    00587                 izone = izone->next;
    00588         }
    00589         return NULL;
    00590 }
    00591
    00592 int fluid_rampreset_izone_set_loop(fluid_rampreset_t* preset, fluid_sample_t* sample,
    00593        int on, float loopstart, float loopend) {
    00594         fluid_inst_zone_t* izone = fluid_rampreset_izoneforsample(preset, sample);
    00595         short coarse, fine;
    00596
    00597         if (izone == NULL)
    00598                         return FLUID_FAILED;
    00599
    00600         if (!on) {
    00601                 izone->gen[GEN_SAMPLEMODE].flags = GEN_SET;
    00602                 izone->gen[GEN_SAMPLEMODE].val = FLUID_UNLOOPED;
    00603                 fluid_rampreset_updatevoices(preset, GEN_SAMPLEMODE, FLUID_UNLOOPED);
    00604                 return FLUID_OK;
    00605 }
    00606
    00607         /* NOTE : We should check that (sample->startloop + loopStart <= sample->endloop - loopend - 32) */
    00608
    00609         /* loopstart */
    00610         if (loopstart > 32767. || loopstart < -32767.) {
    00611                 coarse = (short)(loopstart/32768.);
    00612                 fine = (short)(loopstart - (float)(coarse)*32768.);
    00613         } else {
    00614                 coarse = 0;
    00615                 fine = (short)loopstart;
    00616         }
    00617         izone->gen[GEN_STARTLOOPADDROFS].flags = GEN_SET;
    00618         izone->gen[GEN_STARTLOOPADDROFS].val = fine;
    00619         fluid_rampreset_updatevoices(preset, GEN_STARTLOOPADDROFS, fine);
    00620         if (coarse) {
    00621                 izone->gen[GEN_STARTLOOPADDRCOARSEOFS].flags = GEN_SET;
    00622                 izone->gen[GEN_STARTLOOPADDRCOARSEOFS].val = coarse;
    00623         } else {
    00624                 izone->gen[GEN_STARTLOOPADDRCOARSEOFS].flags = GEN_UNUSED;
    00625         }
    00626         fluid_rampreset_updatevoices(preset, GEN_STARTLOOPADDRCOARSEOFS, coarse);
    00627
    00628         /* loopend */
    00629         if (loopend > 32767. || loopend < -32767.) {
    00630                 coarse = (short)(loopend/32768.);
    00631                 fine = (short)(loopend - (float)(coarse)*32768.);
    00632         } else {
    00633                 coarse = 0;
    00634                 fine = (short)loopend;
    00635         }
    00636         izone->gen[GEN_ENDLOOPADDROFS].flags = GEN_SET;
    00637         izone->gen[GEN_ENDLOOPADDROFS].val = fine;
    00638         fluid_rampreset_updatevoices(preset, GEN_ENDLOOPADDROFS, fine);
    00639         if (coarse) {
    00640                 izone->gen[GEN_ENDLOOPADDRCOARSEOFS].flags = GEN_SET;
    00641                 izone->gen[GEN_ENDLOOPADDRCOARSEOFS].val = coarse;
    00642         } else {
    00643                 izone->gen[GEN_ENDLOOPADDRCOARSEOFS].flags = GEN_UNUSED;
    00644         }
    00645         fluid_rampreset_updatevoices(preset, GEN_ENDLOOPADDRCOARSEOFS, coarse);
    00646
    00647         izone->gen[GEN_SAMPLEMODE].flags = GEN_SET;
    00648         izone->gen[GEN_SAMPLEMODE].val = FLUID_LOOP_DURING_RELEASE;
    00649         fluid_rampreset_updatevoices(preset, GEN_SAMPLEMODE, FLUID_LOOP_DURING_RELEASE);
    00650
    00651         /* If the loop points are the whole samples, we are supposed to
    00652            copy the frames around in the margins (the start to the end margin and
    00653            the end to the start margin), but it works fine without this. Maybe some time
    00654            it will be needed (see SAMPLE_LOOP_MARGIN) -- Antoie Schmitt May 2003 */
    00655
    00656         return FLUID_OK;
    00657 }
    00658
    00659 int fluid_rampreset_izone_set_gen(fluid_rampreset_t* preset, fluid_sample_t* sample,
    00660        int gen_type, float value) {
    00661         fluid_inst_zone_t* izone = fluid_rampreset_izoneforsample(preset, sample);
    00662         if (izone == NULL)
    00663                         return FLUID_FAILED;
    00664
    00665         izone->gen[gen_type].flags = GEN_SET;
    00666         izone->gen[gen_type].val = value;
    00667
    00668         fluid_rampreset_updatevoices(preset, gen_type, value);
    00669
    00670         return FLUID_OK;
    00671 }
    00672
    00673 int fluid_rampreset_remove_izone(fluid_rampreset_t* preset, fluid_sample_t* sample) {
    00674         fluid_inst_t* inst;
    00675         fluid_inst_zone_t* izone, * prev;
    00676         int found = 0;
    00677
    00678         if (preset->zone == NULL) return FLUID_FAILED;
    00679         inst = fluid_preset_zone_get_inst(preset->zone);
    00680         izone = inst->zone;
    00681         prev = NULL;
    00682         while (izone && !found) {
    00683                 if (izone->sample == sample) {
    00684                         if (prev == NULL) {
    00685                                 inst->zone = izone->next;
    00686                         } else {
    00687                                 prev->next = izone->next;
    00688                         }
    00689                         izone->next = NULL;
    00690                         delete_fluid_inst_zone(izone);
    00691                         found = 1;
    00692                 } else {
    00693                         prev = izone;
    00694                         izone = izone->next;
    00695                 }
    00696         }
    00697         if (!found)
    00698                 return FLUID_FAILED;
    00699
    00700         // stop all the voices that use this sample, so that
    00701         // the sample can be cleared up
    00702         {
    00703                 fluid_list_t *tmp = preset->presetvoices;
    00704                 while (tmp) {
    00705                         fluid_rampreset_voice_t *presetvoice = (fluid_rampreset_voice_t *)(tmp->data);
    00706                         fluid_voice_t *voice = presetvoice->voice;
    00707                         if (fluid_voice_is_playing(voice) && (fluid_voice_get_id(voice) == presetvoice->voiceID)) {
    00708                                 // still belongs to the preset
    00709                                 if (voice->sample == sample) {
    00710                                         // uses this sample : turn it off.
    00711                                         // our presetvoices struct will be cleaneup at the next update
    00712                                         fluid_voice_off(voice);
    00713                                 }
    00714                         }
    00715                         tmp = tmp->next;
    00716                 }
    00717         }
    00718         return FLUID_OK;
    00719 }
    00720
    00721 /*
    00722  * fluid_rampreset_remembervoice
    00723  */
    00724 int
    00725 fluid_rampreset_remembervoice(fluid_rampreset_t* preset, fluid_voice_t* voice) {
    00726         /* stores the voice and the its ID in the preset for later update on gen_set */
    00727         fluid_rampreset_voice_t *presetvoice = FLUID_NEW(fluid_rampreset_voice_t);
    00728         if (presetvoice == NULL) {
    00729     FLUID_LOG(FLUID_ERR, "Out of memory");
    00730     return FLUID_FAILED;
    00731   }
    00732
    00733   presetvoice->voice = voice;
    00734   presetvoice->voiceID = fluid_voice_get_id(voice);
    00735
    00736   preset->presetvoices = fluid_list_append(preset->presetvoices, (void *)presetvoice);
    00737   if (preset->presetvoices == NULL) {
    00738         FLUID_FREE(presetvoice);
    00739     FLUID_LOG(FLUID_ERR, "Out of memory");
    00740     return FLUID_FAILED;
    00741   }
    00742   return FLUID_OK;
    00743 }
    00744
    00745 /*
    00746  * fluid_rampreset_updatevoice
    00747  */
    00748 void
    00749 fluid_rampreset_updatevoices(fluid_rampreset_t* preset, int gen_type, float val) {
    00750         fluid_list_t *tmp = preset->presetvoices, *prev = NULL, *next;
    00751
    00752         /* walk the presetvoice to update them if they are still active and ours.
    00753            If their ID has changed or their state is not playing, they are not ours, so we forget them
    00754         */
    00755         while (tmp) {
    00756                 fluid_rampreset_voice_t *presetvoice = (fluid_rampreset_voice_t *)(tmp->data);
    00757                 fluid_voice_t *voice = presetvoice->voice;
    00758                 if (!fluid_voice_is_playing(voice) || (fluid_voice_get_id(voice) != presetvoice->voiceID)) {
    00759                         /* forget it */
    00760                 FLUID_FREE(presetvoice);
    00761
    00762                         /* unlink it */
    00763                         next = tmp->next;
    00764                 FLUID_FREE(tmp);
    00765                         if (prev) {
    00766                                 prev->next = next;
    00767                         } else {
    00768                                 preset->presetvoices = next;
    00769                         }
    00770                 tmp = next;
    00771
    00772                 } else {
    00773
    00774                         /* update */
    00775                         fluid_voice_gen_set(voice, gen_type, val);
    00776                         fluid_voice_update_param(voice, gen_type);
    00777
    00778                         /* next */
    00779                         prev = tmp;
    00780                         tmp = tmp->next;
    00781                 }
    00782         }
    00783 }
    00784
    00785
    00786 /*
    00787  * fluid_rampreset_noteon
    00788  */
    00789 int
    00790 fluid_rampreset_noteon(fluid_rampreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel)
    00791 {
    00792   fluid_preset_zone_t *preset_zone;
    00793   fluid_inst_t* inst;
    00794   fluid_inst_zone_t *inst_zone, *global_inst_zone, *z;
    00795   fluid_sample_t* sample;
    00796   fluid_voice_t* voice;
    00797   fluid_mod_t * mod;
    00798   fluid_mod_t * mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */
    00799   int mod_list_count;
    00800   int i;
    00801
    00802   /* run thru all the zones of this preset */
    00803   preset_zone = preset->zone;
    00804   while (preset_zone != NULL) {
    00805
    00806     /* check if the note falls into the key and velocity range of this
    00807        preset */
    00808     if (fluid_preset_zone_inside_range(preset_zone, key, vel)) {
    00809
    00810       inst = fluid_preset_zone_get_inst(preset_zone);
    00811       global_inst_zone = fluid_inst_get_global_zone(inst);
    00812
    00813       /* run thru all the zones of this instrument */
    00814       inst_zone = fluid_inst_get_zone(inst);
    00815       while (inst_zone != NULL) {
    00816
    00817         /* make sure this instrument zone has a valid sample */
    00818         sample = fluid_inst_zone_get_sample(inst_zone);
    00819         if (fluid_sample_in_rom(sample) || (sample == NULL)) {
    00820           inst_zone = fluid_inst_zone_next(inst_zone);
    00821           continue;
    00822         }
    00823
    00824         /* check if the note falls into the key and velocity range of this
    00825            instrument */
    00826
    00827         if (fluid_inst_zone_inside_range(inst_zone, key, vel) && (sample != NULL)) {
    00828
    00829           /* this is a good zone. allocate a new synthesis process and
    00830              initialize it */
    00831
    00832           voice = fluid_synth_alloc_voice(synth, sample, chan, key, vel);
    00833           if (voice == NULL) {
    00834             return FLUID_FAILED;
    00835           }
    00836
    00837           if (fluid_rampreset_remembervoice(preset, voice) != FLUID_OK) {
    00838             return FLUID_FAILED;
    00839           }
    00840
    00841           z = inst_zone;
    00842
    00843           /* Instrument level, generators */
    00844
    00845           for (i = 0; i < GEN_LAST; i++) {
    00846
    00847             /* SF 2.01 section 9.4 'bullet' 4:
    00848              *
    00849              * A generator in a local instrument zone supersedes a
    00850              * global instrument zone generator.  Both cases supersede
    00851              * the default generator -> voice_gen_set */
    00852
    00853             if (inst_zone->gen[i].flags){
    00854               fluid_voice_gen_set(voice, i, inst_zone->gen[i].val);
    00855
    00856             } else if (global_inst_zone != NULL && global_inst_zone->gen[i].flags){
    00857               fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val);
    00858
    00859             } else {
    00860               /* The generator has not been defined in this instrument.
    00861                * Do nothing, leave it at the default.
    00862                */
    00863             };
    00864
    00865           }; /* for all generators */
    00866
    00867           /* global instrument zone, modulators: Put them all into a
    00868            * list. */
    00869
    00870           mod_list_count = 0;
    00871
    00872           if (global_inst_zone){
    00873             mod = global_inst_zone->mod;
    00874             while (mod){
    00875               mod_list[mod_list_count++] = mod;
    00876               mod = mod->next;
    00877             };
    00878           };
    00879
    00880           /* local instrument zone, modulators.
    00881            * Replace modulators with the same definition in the list:
    00882            * SF 2.01 page 69, 'bullet' 8
    00883            */
    00884           mod = inst_zone->mod;
    00885
    00886           while (mod){
    00887
    00888             /* 'Identical' modulators will be deleted by setting their
    00889              *  list entry to NULL.  The list length is known, NULL
    00890              *  entries will be ignored later.  SF2.01 section 9.5.1
    00891              *  page 69, 'bullet' 3 defines 'identical'.  */
    00892
    00893             for (i = 0; i < mod_list_count; i++){
    00894               if (fluid_mod_test_identity(mod,mod_list[i])){
    00895                 mod_list[i] = NULL;
    00896               };
    00897             };
    00898
    00899             /* Finally add the new modulator to to the list. */
    00900             mod_list[mod_list_count++] = mod;
    00901             mod = mod->next;
    00902           };
    00903
    00904           /* Add instrument modulators (global / local) to the voice. */
    00905           for (i = 0; i < mod_list_count; i++){
    00906
    00907             mod = mod_list[i];
    00908
    00909             if (mod != NULL){ /* disabled modulators CANNOT be skipped. */
    00910
    00911               /* Instrument modulators -supersede- existing (default)
    00912                * modulators.  SF 2.01 page 69, 'bullet' 6 */
    00913               fluid_voice_add_mod(voice, mod, FLUID_VOICE_OVERWRITE);
    00914             };
    00915           };
    00916
    00917           /* Preset level, generators */
    00918
    00919           for (i = 0; i < GEN_LAST; i++) {
    00920
    00921             /* SF 2.01 section 8.5 page 58: If some generators are
    00922              * encountered at preset level, they should be ignored */
    00923             if ((i != GEN_STARTADDROFS)
    00924                 && (i != GEN_ENDADDROFS)
    00925                 && (i != GEN_STARTLOOPADDROFS)
    00926                 && (i != GEN_ENDLOOPADDROFS)
    00927                 && (i != GEN_STARTADDRCOARSEOFS)
    00928                 && (i != GEN_ENDADDRCOARSEOFS)
    00929                 && (i != GEN_STARTLOOPADDRCOARSEOFS)
    00930                 && (i != GEN_KEYNUM)
    00931                 && (i != GEN_VELOCITY)
    00932                 && (i != GEN_ENDLOOPADDRCOARSEOFS)
    00933                 && (i != GEN_SAMPLEMODE)
    00934                 && (i != GEN_EXCLUSIVECLASS)
    00935                 && (i != GEN_OVERRIDEROOTKEY)) {
    00936
    00937               /* SF 2.01 section 9.4 'bullet' 9: A generator in a
    00938                * local preset zone supersedes a global preset zone
    00939                * generator.  The effect is -added- to the destination
    00940                * summing node -> voice_gen_incr */
    00941
    00942               if (preset_zone->gen[i].flags){
    00943                 fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val);
    00944               } else {
    00945                 /* The generator has not been defined in this preset
    00946                  * Do nothing, leave it unchanged.
    00947                  */
    00948               };
    00949             }; /* if available at preset level */
    00950           }; /* for all generators */
    00951
    00952
    00953           /* Global preset zone, modulators: put them all into a
    00954            * list. */
    00955           mod_list_count = 0;
    00956
    00957           /* Process the modulators of the local preset zone.  Kick
    00958            * out all identical modulators from the global preset zone
    00959            * (SF 2.01 page 69, second-last bullet) */
    00960
    00961           mod = preset_zone->mod;
    00962           while (mod){
    00963             for (i = 0; i < mod_list_count; i++){
    00964               if (fluid_mod_test_identity(mod,mod_list[i])){
    00965                 mod_list[i] = NULL;
    00966               };
    00967             };
    00968
    00969             /* Finally add the new modulator to the list. */
    00970             mod_list[mod_list_count++] = mod;
    00971             mod = mod->next;
    00972           };
    00973
    00974           /* Add preset modulators (global / local) to the voice. */
    00975           for (i = 0; i < mod_list_count; i++){
    00976             mod = mod_list[i];
    00977             if ((mod != NULL) && (mod->amount != 0)) { /* disabled modulators can be skipped. */
    00978
    00979               /* Preset modulators -add- to existing instrument /
    00980                * default modulators.  SF2.01 page 70 first bullet on
    00981                * page */
    00982               fluid_voice_add_mod(voice, mod, FLUID_VOICE_ADD);
    00983             };
    00984           };
    00985
    00986           /* add the synthesis process to the synthesis loop. */
    00987           fluid_synth_start_voice(synth, voice);
    00988
    00989           /* Store the ID of the first voice that was created by this noteon event.
    00990            * Exclusive class may only terminate older voices.
    00991            * That avoids killing voices, which have just been created.
    00992            * (a noteon event can create several voice processes with the same exclusive
    00993            * class - for example when using stereo samples)
    00994            */
    00995         }
    00996
    00997         inst_zone = fluid_inst_zone_next(inst_zone);
    00998       }
    00999     }
    01000     preset_zone = fluid_preset_zone_next(preset_zone);
    01001   }
    01002
    01003   return FLUID_OK;
    01004 }
    01005
    01006
    01007
    01008 /***************************************************************
    01009  *
    01010  *                           SAMPLE
    01011  */
    01012
    01013
    01014
    01015 /*
    01016  * fluid_sample_set_name
    01017  */
    01018 int
    01019 fluid_sample_set_name(fluid_sample_t* sample, char * name)
    01020 {
    01021   FLUID_MEMCPY(sample->name, name, 20);
    01022   return FLUID_OK;
    01023 }
    01024
    01025 /*
    01026  * fluid_sample_set_sound_data
    01027  */
    01028 int
    01029 fluid_sample_set_sound_data(fluid_sample_t* sample, short *data, unsigned int nbframes, short copy_data, int rootkey)
    01030 {
    01031         /* 16 bit mono 44.1KHz data in */
    01032         /* in all cases, the sample has ownership of the data : it will release it in the end */
    01033         unsigned int storedNbFrames;
    01034
    01035         /* in case we already have some data */
    01036   if (sample->data != NULL) {
    01037         FLUID_FREE(sample->data);
    01038   }
    01039
    01040         if (copy_data) {
    01041
    01042                 /* nbframes should be >= 48 (SoundFont specs) */
    01043                 storedNbFrames = nbframes;
    01044                 if (storedNbFrames < 48) storedNbFrames = 48;
    01045
    01046           sample->data = FLUID_MALLOC(storedNbFrames*2 + 4*SAMPLE_LOOP_MARGIN);
    01047           if (sample->data == NULL) {
    01048             FLUID_LOG(FLUID_ERR, "Out of memory");
    01049             return FLUID_FAILED;
    01050           }
    01051           FLUID_MEMSET(sample->data, 0, storedNbFrames*2 + 4*SAMPLE_LOOP_MARGIN);
    01052           FLUID_MEMCPY((char*)(sample->data) + 2*SAMPLE_LOOP_MARGIN, data, nbframes*2);
    01053
    01054 #if 0
    01055           /* this would do the fill of the margins */
    01056           FLUID_MEMCPY((char*)(sample->data) + 2*SAMPLE_LOOP_MARGIN + storedNbFrames*2, (char*)data, 2*SAMPLE_LOOP_MARGIN);
    01057           FLUID_MEMCPY((char*)(sample->data), (char*)data + nbframes*2 - 2*SAMPLE_LOOP_MARGIN, 2*SAMPLE_LOOP_MARGIN);
    01058 #endif
    01059
    01060           /* pointers */
    01061           /* all from the start of data */
    01062           sample->start = SAMPLE_LOOP_MARGIN;
    01063           sample->end = SAMPLE_LOOP_MARGIN + storedNbFrames;
    01064   } else {
    01065         /* we cannot assure the SAMPLE_LOOP_MARGIN */
    01066         sample->data = data;
    01067           sample->start = 0;
    01068           sample->end = nbframes;
    01069   }
    01070
    01071   /* only used as markers for the LOOP generators : set them on the first real frame */
    01072   sample->loopstart = sample->start;
    01073   sample->loopend = sample->end;
    01074
    01075   sample->samplerate = 44100;
    01076   sample->origpitch = rootkey;
    01077   sample->pitchadj = 0;
    01078   sample->sampletype = FLUID_SAMPLETYPE_MONO;
    01079   sample->valid = 1;
    01080
    01081   return FLUID_OK;
    01082 }
    01083
    01084 /*
    01085  * new_fluid_ramsample
    01086  */
    01087 fluid_sample_t*
    01088 new_fluid_ramsample()
    01089 {
    01090         /* same as new_fluid_sample. Only here so that it is exported */
    01091   fluid_sample_t* sample = NULL;
    01092
    01093   sample = FLUID_NEW(fluid_sample_t);
    01094   if (sample == NULL) {
    01095     FLUID_LOG(FLUID_ERR, "Out of memory");
    01096     return NULL;
    01097   }
    01098
    01099   memset(sample, 0, sizeof(fluid_sample_t));
    01100
    01101   return sample;
    01102 }
    01103
    01104 /*
    01105  * delete_fluid_ramsample
    01106  */
    01107 int
    01108 delete_fluid_ramsample(fluid_sample_t* sample)
    01109 {
    01110         /* same as delete_fluid_sample, plus frees the data */
    01111   if (sample->data != NULL) {
    01112         FLUID_FREE(sample->data);
    01113   }
    01114   sample->data = NULL;
    01115   FLUID_FREE(sample);
    01116   return FLUID_OK;
    01117 }