diff options
Diffstat (limited to 'libs/fluidsynth/src/fluid_defsfont.c')
-rw-r--r-- | libs/fluidsynth/src/fluid_defsfont.c | 4647 |
1 files changed, 1703 insertions, 2944 deletions
diff --git a/libs/fluidsynth/src/fluid_defsfont.c b/libs/fluidsynth/src/fluid_defsfont.c index c395218411..6e19eb71af 100644 --- a/libs/fluidsynth/src/fluid_defsfont.c +++ b/libs/fluidsynth/src/fluid_defsfont.c @@ -6,16 +6,16 @@ * Copyright (C) 1999-2001 Josh Green * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License - * as published by the Free Software Foundation; either version 2 of + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public + * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA @@ -23,69 +23,92 @@ #include "fluid_defsfont.h" -/* Todo: Get rid of that 'include' */ +#include "fluid_sfont.h" #include "fluid_sys.h" +#include "fluid_synth.h" +#include "fluid_samplecache.h" + +/* EMU8k/10k hardware applies this factor to initial attenuation generator values set at preset and + * instrument level in a soundfont. We apply this factor when loading the generator values to stay + * compatible as most existing soundfonts expect exactly this (strange, non-standard) behaviour. */ +#define EMU_ATTENUATION_FACTOR (0.4f) + +/* Dynamic sample loading functions */ +static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset); +static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset); +static void unload_sample(fluid_sample_t *sample); +static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int chan); +static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason); +static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone); +static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx); + /*************************************************************** * * SFONT LOADER */ -fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings) +/** + * Creates a default soundfont2 loader that can be used with fluid_synth_add_sfloader(). + * By default every synth instance has an initial default soundfont loader instance. + * Calling this function is usually only necessary to load a soundfont from memory, by providing custom callback functions via fluid_sfloader_set_callbacks(). + * + * @param settings A settings instance obtained by new_fluid_settings() + * @return A default soundfont2 loader struct + */ +fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings) { - fluid_sfloader_t* loader; + fluid_sfloader_t *loader; + fluid_return_val_if_fail(settings != NULL, NULL); - loader = FLUID_NEW(fluid_sfloader_t); - if (loader == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } + loader = new_fluid_sfloader(fluid_defsfloader_load, delete_fluid_sfloader); - loader->data = settings; - loader->free = delete_fluid_defsfloader; - loader->load = fluid_defsfloader_load; + if(loader == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } - return loader; -} + fluid_sfloader_set_data(loader, settings); -int delete_fluid_defsfloader(fluid_sfloader_t* loader) -{ - if (loader) { - FLUID_FREE(loader); - } - return FLUID_OK; + return loader; } -fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename) +fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *filename) { - fluid_defsfont_t* defsfont; - fluid_sfont_t* sfont; + fluid_defsfont_t *defsfont; + fluid_sfont_t *sfont; - defsfont = new_fluid_defsfont(loader->data); + defsfont = new_fluid_defsfont(fluid_sfloader_get_data(loader)); - if (defsfont == NULL) { - return NULL; - } + if(defsfont == NULL) + { + return NULL; + } - if (fluid_defsfont_load(defsfont, filename) == FLUID_FAILED) { - delete_fluid_defsfont(defsfont); - return NULL; - } + sfont = new_fluid_sfont(fluid_defsfont_sfont_get_name, + fluid_defsfont_sfont_get_preset, + fluid_defsfont_sfont_iteration_start, + fluid_defsfont_sfont_iteration_next, + fluid_defsfont_sfont_delete); - sfont = FLUID_NEW(fluid_sfont_t); - if (sfont == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } + if(sfont == NULL) + { + delete_fluid_defsfont(defsfont); + return NULL; + } - sfont->data = defsfont; - sfont->free = fluid_defsfont_sfont_delete; - sfont->get_name = fluid_defsfont_sfont_get_name; - sfont->get_preset = fluid_defsfont_sfont_get_preset; - sfont->iteration_start = fluid_defsfont_sfont_iteration_start; - sfont->iteration_next = fluid_defsfont_sfont_iteration_next; + fluid_sfont_set_data(sfont, defsfont); - return sfont; + defsfont->sfont = sfont; + + if(fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED) + { + fluid_sfont_delete_internal(sfont); + return NULL; + } + + return sfont; } @@ -95,621 +118,487 @@ fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* file * PUBLIC INTERFACE */ -int fluid_defsfont_sfont_delete(fluid_sfont_t* sfont) +int fluid_defsfont_sfont_delete(fluid_sfont_t *sfont) { - if (delete_fluid_defsfont(sfont->data) != 0) { - return -1; - } - FLUID_FREE(sfont); - return 0; -} + if(delete_fluid_defsfont(fluid_sfont_get_data(sfont)) != FLUID_OK) + { + return -1; + } -char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont) -{ - return fluid_defsfont_get_name((fluid_defsfont_t*) sfont->data); + delete_fluid_sfont(sfont); + return 0; } -#if 0 -fluid_sample_t* fluid_defsfont_get_sample(fluid_defsfont_t* sfont, char *s) +const char *fluid_defsfont_sfont_get_name(fluid_sfont_t *sfont) { - /* This function is here just to avoid an ABI/SONAME bump, see ticket #98. Should never be used. */ - return NULL; + return fluid_defsfont_get_name(fluid_sfont_get_data(sfont)); } -#endif -fluid_preset_t* -fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum) +fluid_preset_t * +fluid_defsfont_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum) { - fluid_preset_t* preset = NULL; - fluid_defpreset_t* defpreset; - fluid_defsfont_t* defsfont = sfont->data; - - defpreset = fluid_defsfont_get_preset(defsfont, bank, prenum); - - if (defpreset == NULL) { - return NULL; - } - - if (defsfont->preset_stack_size > 0) { - defsfont->preset_stack_size--; - preset = defsfont->preset_stack[defsfont->preset_stack_size]; - } - if (!preset) - preset = FLUID_NEW(fluid_preset_t); - if (!preset) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } - - preset->sfont = sfont; - preset->data = defpreset; - preset->free = fluid_defpreset_preset_delete; - preset->get_name = fluid_defpreset_preset_get_name; - preset->get_banknum = fluid_defpreset_preset_get_banknum; - preset->get_num = fluid_defpreset_preset_get_num; - preset->noteon = fluid_defpreset_preset_noteon; - preset->notify = NULL; - - return preset; + return fluid_defsfont_get_preset(fluid_sfont_get_data(sfont), bank, prenum); } -void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont) +void fluid_defsfont_sfont_iteration_start(fluid_sfont_t *sfont) { - fluid_defsfont_iteration_start((fluid_defsfont_t*) sfont->data); + fluid_defsfont_iteration_start(fluid_sfont_get_data(sfont)); } -int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset) +fluid_preset_t *fluid_defsfont_sfont_iteration_next(fluid_sfont_t *sfont) { - preset->free = fluid_defpreset_preset_delete; - preset->get_name = fluid_defpreset_preset_get_name; - preset->get_banknum = fluid_defpreset_preset_get_banknum; - preset->get_num = fluid_defpreset_preset_get_num; - preset->noteon = fluid_defpreset_preset_noteon; - preset->notify = NULL; - - return fluid_defsfont_iteration_next((fluid_defsfont_t*) sfont->data, preset); + return fluid_defsfont_iteration_next(fluid_sfont_get_data(sfont)); } -int fluid_defpreset_preset_delete(fluid_preset_t* preset) +void fluid_defpreset_preset_delete(fluid_preset_t *preset) { - fluid_defpreset_t* defpreset = preset ? preset->data : NULL; - fluid_defsfont_t* sfont = defpreset ? defpreset->sfont : NULL; + fluid_defsfont_t *defsfont; + fluid_defpreset_t *defpreset; + + defsfont = fluid_sfont_get_data(preset->sfont); + defpreset = fluid_preset_get_data(preset); - if (sfont && sfont->preset_stack_size < sfont->preset_stack_capacity) { - sfont->preset_stack[sfont->preset_stack_size] = preset; - sfont->preset_stack_size++; - } - else - FLUID_FREE(preset); + if(defsfont) + { + defsfont->preset = fluid_list_remove(defsfont->preset, defpreset); + } - return 0; + delete_fluid_defpreset(defpreset); + delete_fluid_preset(preset); } -char* fluid_defpreset_preset_get_name(fluid_preset_t* preset) +const char *fluid_defpreset_preset_get_name(fluid_preset_t *preset) { - return fluid_defpreset_get_name((fluid_defpreset_t*) preset->data); + return fluid_defpreset_get_name(fluid_preset_get_data(preset)); } -int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset) +int fluid_defpreset_preset_get_banknum(fluid_preset_t *preset) { - return fluid_defpreset_get_banknum((fluid_defpreset_t*) preset->data); + return fluid_defpreset_get_banknum(fluid_preset_get_data(preset)); } -int fluid_defpreset_preset_get_num(fluid_preset_t* preset) +int fluid_defpreset_preset_get_num(fluid_preset_t *preset) { - return fluid_defpreset_get_num((fluid_defpreset_t*) preset->data); + return fluid_defpreset_get_num(fluid_preset_get_data(preset)); } -int fluid_defpreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, - int chan, int key, int vel) +int fluid_defpreset_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth, + int chan, int key, int vel) { - return fluid_defpreset_noteon((fluid_defpreset_t*) preset->data, synth, chan, key, vel); + return fluid_defpreset_noteon(fluid_preset_get_data(preset), synth, chan, key, vel); } - - /*************************************************************** * - * CACHED SAMPLEDATA LOADER + * SFONT */ -typedef struct _fluid_cached_sampledata_t { - struct _fluid_cached_sampledata_t *next; - - char* filename; - time_t modification_time; - int num_references; - int mlock; - - const short* sampledata; - unsigned int samplesize; -} fluid_cached_sampledata_t; +/* + * new_fluid_defsfont + */ +fluid_defsfont_t *new_fluid_defsfont(fluid_settings_t *settings) +{ + fluid_defsfont_t *defsfont; -static fluid_cached_sampledata_t* all_cached_sampledata = NULL; -static fluid_mutex_t cached_sampledata_mutex = FLUID_MUTEX_INIT; + defsfont = FLUID_NEW(fluid_defsfont_t); -static int fluid_get_file_modification_time(char *filename, time_t *modification_time) -{ -#if defined(WIN32) || defined(__OS2__) - *modification_time = 0; - return FLUID_OK; -#else - struct stat buf; + if(defsfont == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } - if (stat(filename, &buf) == -1) { - return FLUID_FAILED; - } + FLUID_MEMSET(defsfont, 0, sizeof(*defsfont)); - *modification_time = buf.st_mtime; - return FLUID_OK; -#endif -} + fluid_settings_getint(settings, "synth.lock-memory", &defsfont->mlock); + fluid_settings_getint(settings, "synth.dynamic-sample-loading", &defsfont->dynamic_samples); -static int fluid_cached_sampledata_load(char *filename, unsigned int samplepos, - unsigned int samplesize, short **sampledata, int try_mlock) -{ - fluid_file fd = NULL; - short *loaded_sampledata = NULL; - fluid_cached_sampledata_t* cached_sampledata = NULL; - time_t modification_time; - - fluid_mutex_lock(cached_sampledata_mutex); - - if (fluid_get_file_modification_time(filename, &modification_time) == FLUID_FAILED) { - FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file."); - modification_time = 0; - } - - for (cached_sampledata = all_cached_sampledata; cached_sampledata; cached_sampledata = cached_sampledata->next) { - if (strcmp(filename, cached_sampledata->filename)) - continue; - if (cached_sampledata->modification_time != modification_time) - continue; - if (cached_sampledata->samplesize != samplesize) { - FLUID_LOG(FLUID_ERR, "Cached size of soundfont doesn't match actual size of soundfont (cached: %u. actual: %u)", - cached_sampledata->samplesize, samplesize); - continue; - } - - if (try_mlock && !cached_sampledata->mlock) { - if (fluid_mlock(cached_sampledata->sampledata, samplesize) != 0) - FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible."); - else - cached_sampledata->mlock = try_mlock; - } - - cached_sampledata->num_references++; - loaded_sampledata = (short*) cached_sampledata->sampledata; - goto success_exit; - } - - fd = FLUID_FOPEN(filename, "rb"); - if (fd == NULL) { - FLUID_LOG(FLUID_ERR, "Can't open soundfont file"); - goto error_exit; - } - if (FLUID_FSEEK(fd, samplepos, SEEK_SET) == -1) { - perror("error"); - FLUID_LOG(FLUID_ERR, "Failed to seek position in data file"); - goto error_exit; - } - - - loaded_sampledata = (short*) FLUID_MALLOC(samplesize); - if (loaded_sampledata == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - goto error_exit; - } - if (FLUID_FREAD(loaded_sampledata, 1, samplesize, fd) < samplesize) { - FLUID_LOG(FLUID_ERR, "Failed to read sample data"); - goto error_exit; - } - - FLUID_FCLOSE(fd); - fd = NULL; - - - cached_sampledata = (fluid_cached_sampledata_t*) FLUID_MALLOC(sizeof(fluid_cached_sampledata_t)); - if (cached_sampledata == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory."); - goto error_exit; - } - - /* Lock the memory to disable paging. It's okay if this fails. It - probably means that the user doesn't have to required permission. */ - cached_sampledata->mlock = 0; - if (try_mlock) { - if (fluid_mlock(loaded_sampledata, samplesize) != 0) - FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible."); - else - cached_sampledata->mlock = try_mlock; - } - - /* If this machine is big endian, the sample have to byte swapped */ - if (FLUID_IS_BIG_ENDIAN) { - unsigned char* cbuf; - unsigned char hi, lo; - unsigned int i, j; - short s; - cbuf = (unsigned char*)loaded_sampledata; - for (i = 0, j = 0; j < samplesize; i++) { - lo = cbuf[j++]; - hi = cbuf[j++]; - s = (hi << 8) | lo; - loaded_sampledata[i] = s; - } - } - - cached_sampledata->filename = (char*) FLUID_MALLOC(strlen(filename) + 1); - if (cached_sampledata->filename == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory."); - goto error_exit; - } - - sprintf(cached_sampledata->filename, "%s", filename); - cached_sampledata->modification_time = modification_time; - cached_sampledata->num_references = 1; - cached_sampledata->sampledata = loaded_sampledata; - cached_sampledata->samplesize = samplesize; - - cached_sampledata->next = all_cached_sampledata; - all_cached_sampledata = cached_sampledata; - - - success_exit: - fluid_mutex_unlock(cached_sampledata_mutex); - *sampledata = loaded_sampledata; - return FLUID_OK; - - error_exit: - if (fd != NULL) { - FLUID_FCLOSE(fd); - } - if (loaded_sampledata != NULL) { - FLUID_FREE(loaded_sampledata); - } - - if (cached_sampledata != NULL) { - if (cached_sampledata->filename != NULL) { - FLUID_FREE(cached_sampledata->filename); - } - FLUID_FREE(cached_sampledata); - } - - fluid_mutex_unlock(cached_sampledata_mutex); - *sampledata = NULL; - return FLUID_FAILED; + return defsfont; } -static int fluid_cached_sampledata_unload(const short *sampledata) +/* + * delete_fluid_defsfont + */ +int delete_fluid_defsfont(fluid_defsfont_t *defsfont) { - fluid_cached_sampledata_t* prev = NULL; - fluid_cached_sampledata_t* cached_sampledata; - - fluid_mutex_lock(cached_sampledata_mutex); - cached_sampledata = all_cached_sampledata; + fluid_list_t *list; + fluid_preset_t *preset; + fluid_sample_t *sample; - while (cached_sampledata != NULL) { - if (sampledata == cached_sampledata->sampledata) { + fluid_return_val_if_fail(defsfont != NULL, FLUID_OK); - cached_sampledata->num_references--; - - if (cached_sampledata->num_references == 0) { - if (cached_sampledata->mlock) - fluid_munlock(cached_sampledata->sampledata, cached_sampledata->samplesize); - FLUID_FREE((short*) cached_sampledata->sampledata); - FLUID_FREE(cached_sampledata->filename); + /* Check that no samples are currently used */ + for(list = defsfont->sample; list; list = fluid_list_next(list)) + { + sample = (fluid_sample_t *) fluid_list_get(list); - if (prev != NULL) { - prev->next = cached_sampledata->next; - } else { - all_cached_sampledata = cached_sampledata->next; + if(sample->refcount != 0) + { + return FLUID_FAILED; } + } - FLUID_FREE(cached_sampledata); - } + if(defsfont->filename != NULL) + { + FLUID_FREE(defsfont->filename); + } - goto success_exit; + for(list = defsfont->sample; list; list = fluid_list_next(list)) + { + delete_fluid_sample((fluid_sample_t *) fluid_list_get(list)); } - prev = cached_sampledata; - cached_sampledata = cached_sampledata->next; - } + if(defsfont->sample) + { + delete_fluid_list(defsfont->sample); + } - FLUID_LOG(FLUID_ERR, "Trying to free sampledata not found in cache."); - goto error_exit; - - success_exit: - fluid_mutex_unlock(cached_sampledata_mutex); - return FLUID_OK; + if(defsfont->sampledata != NULL) + { + fluid_samplecache_unload(defsfont->sampledata); + } - error_exit: - fluid_mutex_unlock(cached_sampledata_mutex); - return FLUID_FAILED; -} + for(list = defsfont->preset; list; list = fluid_list_next(list)) + { + preset = (fluid_preset_t *)fluid_list_get(list); + fluid_defpreset_preset_delete(preset); + } + delete_fluid_list(defsfont->preset); + for(list = defsfont->inst; list; list = fluid_list_next(list)) + { + delete_fluid_inst(fluid_list_get(list)); + } + delete_fluid_list(defsfont->inst); -/*************************************************************** - * - * SFONT - */ + FLUID_FREE(defsfont); + return FLUID_OK; +} /* - * new_fluid_defsfont + * fluid_defsfont_get_name */ -fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings) +const char *fluid_defsfont_get_name(fluid_defsfont_t *defsfont) { - fluid_defsfont_t* sfont; - int i; + return defsfont->filename; +} - sfont = FLUID_NEW(fluid_defsfont_t); - if (sfont == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } - - sfont->filename = NULL; - sfont->samplepos = 0; - sfont->samplesize = 0; - sfont->sample = NULL; - sfont->sampledata = NULL; - sfont->preset = NULL; - fluid_settings_getint(settings, "synth.lock-memory", &sfont->mlock); - - /* Initialise preset cache, so we don't have to call malloc on program changes. - Usually, we have at most one preset per channel plus one temporarily used, - so optimise for that case. */ - fluid_settings_getint(settings, "synth.midi-channels", &sfont->preset_stack_capacity); - sfont->preset_stack_capacity++; - sfont->preset_stack_size = 0; - sfont->preset_stack = FLUID_ARRAY(fluid_preset_t*, sfont->preset_stack_capacity); - if (!sfont->preset_stack) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - FLUID_FREE(sfont); - return NULL; - } +/* Load sample data for a single sample from the Soundfont file. + * Returns FLUID_OK on error, otherwise FLUID_FAILED + */ +int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, fluid_sample_t *sample) +{ + int num_samples; + unsigned int source_end = sample->source_end; + + /* For uncompressed samples we want to include the 46 zero sample word area following each sample + * in the Soundfont. Otherwise samples with loopend > end, which we have decided not to correct, would + * be corrected after all in fluid_sample_sanitize_loop */ + if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)) + { + source_end += 46; /* Length of zero sample word after each sample, according to SF specs */ - for (i = 0; i < sfont->preset_stack_capacity; i++) { - sfont->preset_stack[i] = FLUID_NEW(fluid_preset_t); - if (!sfont->preset_stack[i]) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - delete_fluid_defsfont(sfont); - return NULL; + /* Safeguard against Soundfonts that are not quite valid and don't include 46 sample words after the + * last sample */ + if(source_end >= (defsfont->samplesize / sizeof(short))) + { + source_end = defsfont->samplesize / sizeof(short); + } } - sfont->preset_stack_size++; - } - return sfont; -} + num_samples = fluid_samplecache_load( + sfdata, sample->source_start, source_end, sample->sampletype, + defsfont->mlock, &sample->data, &sample->data24); -/* - * delete_fluid_defsfont - */ -int delete_fluid_defsfont(fluid_defsfont_t* sfont) -{ - fluid_list_t *list; - fluid_defpreset_t* preset; - fluid_sample_t* sample; - - /* Check that no samples are currently used */ - for (list = sfont->sample; list; list = fluid_list_next(list)) { - sample = (fluid_sample_t*) fluid_list_get(list); - if (fluid_sample_refcount(sample) != 0) { - return -1; - } - } - - if (sfont->filename != NULL) { - FLUID_FREE(sfont->filename); - } - - for (list = sfont->sample; list; list = fluid_list_next(list)) { - delete_fluid_sample((fluid_sample_t*) fluid_list_get(list)); - } - - if (sfont->sample) { - delete_fluid_list(sfont->sample); - } - - if (sfont->sampledata != NULL) { - fluid_cached_sampledata_unload(sfont->sampledata); - } - - while (sfont->preset_stack_size > 0) - FLUID_FREE(sfont->preset_stack[--sfont->preset_stack_size]); - FLUID_FREE(sfont->preset_stack); - - preset = sfont->preset; - while (preset != NULL) { - sfont->preset = preset->next; - delete_fluid_defpreset(preset); - preset = sfont->preset; - } - - FLUID_FREE(sfont); - return FLUID_OK; + if(num_samples < 0) + { + return FLUID_FAILED; + } + + if(num_samples == 0) + { + sample->start = sample->end = 0; + sample->loopstart = sample->loopend = 0; + return FLUID_OK; + } + + /* Ogg Vorbis samples already have loop pointers relative to the invididual decompressed sample, + * but SF2 samples are relative to sample chunk start, so they need to be adjusted */ + if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)) + { + sample->loopstart = sample->source_loopstart - sample->source_start; + sample->loopend = sample->source_loopend - sample->source_start; + } + + /* As we've just loaded an individual sample into it's own buffer, we need to adjust the start + * and end pointers */ + sample->start = 0; + sample->end = num_samples - 1; + + return FLUID_OK; } -/* - * fluid_defsfont_get_name +/* Loads the sample data for all samples from the Soundfont file. For SF2 files, it loads the data in + * one large block. For SF3 files, each compressed sample gets loaded individually. + * Returns FLUID_OK on success, otherwise FLUID_FAILED */ -char* fluid_defsfont_get_name(fluid_defsfont_t* sfont) +int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata) { - return sfont->filename; -} + fluid_list_t *list; + fluid_sample_t *sample; + int sf3_file = (sfdata->version.major == 3); + + /* For SF2 files, we load the sample data in one large block */ + if(!sf3_file) + { + int read_samples; + int num_samples = sfdata->samplesize / sizeof(short); + + read_samples = fluid_samplecache_load(sfdata, 0, num_samples - 1, 0, defsfont->mlock, + &defsfont->sampledata, &defsfont->sample24data); + + if(read_samples != num_samples) + { + FLUID_LOG(FLUID_ERR, "Attempted to read %d words of sample data, but got %d instead", + num_samples, read_samples); + return FLUID_FAILED; + } + } + + for(list = defsfont->sample; list; list = fluid_list_next(list)) + { + sample = fluid_list_get(list); + + if(sf3_file) + { + /* SF3 samples get loaded individually, as most (or all) of them are in Ogg Vorbis format + * anyway */ + if(fluid_defsfont_load_sampledata(defsfont, sfdata, sample) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Failed to load sample '%s'", sample->name); + return FLUID_FAILED; + } + + fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short)); + } + else + { + /* Data pointers of SF2 samples point to large sample data block loaded above */ + sample->data = defsfont->sampledata; + sample->data24 = defsfont->sample24data; + fluid_sample_sanitize_loop(sample, defsfont->samplesize); + } + fluid_voice_optimize_sample(sample); + } + + return FLUID_OK; +} /* * fluid_defsfont_load */ -int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file) +int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t *fcbs, const char *file) { - SFData* sfdata; - fluid_list_t *p; - SFPreset* sfpreset; - SFSample* sfsample; - fluid_sample_t* sample; - fluid_defpreset_t* preset = NULL; - - sfont->filename = FLUID_MALLOC(1 + FLUID_STRLEN(file)); - if (sfont->filename == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return FLUID_FAILED; - } - FLUID_STRCPY(sfont->filename, file); + SFData *sfdata; + fluid_list_t *p; + SFPreset *sfpreset; + SFSample *sfsample; + fluid_sample_t *sample; + fluid_defpreset_t *defpreset = NULL; - /* The actual loading is done in the sfont and sffile files */ - sfdata = sfload_file(file); - if (sfdata == NULL) { - FLUID_LOG(FLUID_ERR, "Couldn't load soundfont file"); - return FLUID_FAILED; - } + defsfont->filename = FLUID_STRDUP(file); + + if(defsfont->filename == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + defsfont->fcbs = fcbs; + + /* The actual loading is done in the sfont and sffile files */ + sfdata = fluid_sffile_open(file, fcbs); + + if(sfdata == NULL) + { + FLUID_LOG(FLUID_ERR, "Couldn't load soundfont file"); + return FLUID_FAILED; + } + + if(fluid_sffile_parse_presets(sfdata) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Couldn't parse presets from soundfont file"); + goto err_exit; + } - /* Keep track of the position and size of the sample data because - it's loaded separately (and might be unoaded/reloaded in future) */ - sfont->samplepos = sfdata->samplepos; - sfont->samplesize = sfdata->samplesize; + /* Keep track of the position and size of the sample data because + it's loaded separately (and might be unoaded/reloaded in future) */ + defsfont->samplepos = sfdata->samplepos; + defsfont->samplesize = sfdata->samplesize; + defsfont->sample24pos = sfdata->sample24pos; + defsfont->sample24size = sfdata->sample24size; - /* load sample data in one block */ - if (fluid_defsfont_load_sampledata(sfont) != FLUID_OK) - goto err_exit; + /* Create all samples from sample headers */ + p = sfdata->sample; - /* Create all the sample headers */ - p = sfdata->sample; - while (p != NULL) { - sfsample = (SFSample *) p->data; + while(p != NULL) + { + sfsample = (SFSample *)fluid_list_get(p); + + sample = new_fluid_sample(); + + if(sample == NULL) + { + goto err_exit; + } + + if(fluid_sample_import_sfont(sample, sfsample, defsfont) == FLUID_OK) + { + fluid_defsfont_add_sample(defsfont, sample); + } + else + { + delete_fluid_sample(sample); + sample = NULL; + } + + /* Store reference to FluidSynth sample in SFSample for later IZone fixups */ + sfsample->fluid_sample = sample; + + p = fluid_list_next(p); + } - sample = new_fluid_sample(); - if (sample == NULL) goto err_exit; + /* If dynamic sample loading is disabled, load all samples in the Soundfont */ + if(!defsfont->dynamic_samples) + { + if(fluid_defsfont_load_all_sampledata(defsfont, sfdata) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Unable to load all sample data"); + goto err_exit; + } + } - if (fluid_sample_import_sfont(sample, sfsample, sfont) != FLUID_OK) - goto err_exit; + /* Load all the presets */ + p = sfdata->preset; - /* Store reference to FluidSynth sample in SFSample for later IZone fixups */ - sfsample->fluid_sample = sample; + while(p != NULL) + { + sfpreset = (SFPreset *)fluid_list_get(p); + defpreset = new_fluid_defpreset(defsfont); - fluid_defsfont_add_sample(sfont, sample); - fluid_voice_optimize_sample(sample); - p = fluid_list_next(p); - } + if(defpreset == NULL) + { + goto err_exit; + } - /* Load all the presets */ - p = sfdata->preset; - while (p != NULL) { - sfpreset = (SFPreset *) p->data; - preset = new_fluid_defpreset(sfont); - if (preset == NULL) goto err_exit; + if(fluid_defpreset_import_sfont(defpreset, sfpreset, defsfont) != FLUID_OK) + { + goto err_exit; + } - if (fluid_defpreset_import_sfont(preset, sfpreset, sfont) != FLUID_OK) - goto err_exit; + if(fluid_defsfont_add_preset(defsfont, defpreset) == FLUID_FAILED) + { + goto err_exit; + } - fluid_defsfont_add_preset(sfont, preset); - p = fluid_list_next(p); - } - sfont_close (sfdata); + p = fluid_list_next(p); + } - return FLUID_OK; + fluid_sffile_close(sfdata); + + return FLUID_OK; err_exit: - sfont_close (sfdata); - if (preset != NULL) - delete_fluid_defpreset(preset); - return FLUID_FAILED; + fluid_sffile_close(sfdata); + delete_fluid_defpreset(defpreset); + return FLUID_FAILED; } /* fluid_defsfont_add_sample * * Add a sample to the SoundFont */ -int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample) +int fluid_defsfont_add_sample(fluid_defsfont_t *defsfont, fluid_sample_t *sample) { - sfont->sample = fluid_list_append(sfont->sample, sample); - return FLUID_OK; + defsfont->sample = fluid_list_append(defsfont->sample, sample); + return FLUID_OK; } /* fluid_defsfont_add_preset * * Add a preset to the SoundFont */ -int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset) +int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *defpreset) { - fluid_defpreset_t *cur, *prev; - if (sfont->preset == NULL) { - preset->next = NULL; - sfont->preset = preset; - } else { - /* sort them as we go along. very basic sorting trick. */ - cur = sfont->preset; - prev = NULL; - while (cur != NULL) { - if ((preset->bank < cur->bank) - || ((preset->bank == cur->bank) && (preset->num < cur->num))) { - if (prev == NULL) { - preset->next = cur; - sfont->preset = preset; - } else { - preset->next = cur; - prev->next = preset; - } - return FLUID_OK; - } - prev = cur; - cur = cur->next; - } - preset->next = NULL; - prev->next = preset; - } - return FLUID_OK; -} + fluid_preset_t *preset; -/* - * fluid_defsfont_load_sampledata - */ -int -fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont) -{ - return fluid_cached_sampledata_load(sfont->filename, sfont->samplepos, - sfont->samplesize, &sfont->sampledata, sfont->mlock); + preset = new_fluid_preset(defsfont->sfont, + fluid_defpreset_preset_get_name, + fluid_defpreset_preset_get_banknum, + fluid_defpreset_preset_get_num, + fluid_defpreset_preset_noteon, + fluid_defpreset_preset_delete); + + if(defsfont->dynamic_samples) + { + preset->notify = dynamic_samples_preset_notify; + } + + if(preset == NULL) + { + return FLUID_FAILED; + } + + fluid_preset_set_data(preset, defpreset); + + defsfont->preset = fluid_list_append(defsfont->preset, preset); + + return FLUID_OK; } /* * fluid_defsfont_get_preset */ -fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int num) +fluid_preset_t *fluid_defsfont_get_preset(fluid_defsfont_t *defsfont, int bank, int num) { - fluid_defpreset_t* preset = sfont->preset; - while (preset != NULL) { - if ((preset->bank == bank) && ((preset->num == num))) { - return preset; - } - preset = preset->next; - } - return NULL; + fluid_preset_t *preset; + fluid_list_t *list; + + for(list = defsfont->preset; list != NULL; list = fluid_list_next(list)) + { + preset = (fluid_preset_t *)fluid_list_get(list); + + if((fluid_preset_get_banknum(preset) == bank) && (fluid_preset_get_num(preset) == num)) + { + return preset; + } + } + + return NULL; } /* * fluid_defsfont_iteration_start */ -void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont) +void fluid_defsfont_iteration_start(fluid_defsfont_t *defsfont) { - sfont->iter_cur = sfont->preset; + defsfont->preset_iter_cur = defsfont->preset; } /* * fluid_defsfont_iteration_next */ -int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset) +fluid_preset_t *fluid_defsfont_iteration_next(fluid_defsfont_t *defsfont) { - if (sfont->iter_cur == NULL) { - return 0; - } + fluid_preset_t *preset = (fluid_preset_t *)fluid_list_get(defsfont->preset_iter_cur); + + defsfont->preset_iter_cur = fluid_list_next(defsfont->preset_iter_cur); - preset->data = (void*) sfont->iter_cur; - sfont->iter_cur = fluid_defpreset_next(sfont->iter_cur); - return 1; + return preset; } /*************************************************************** @@ -720,75 +609,77 @@ int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* prese /* * new_fluid_defpreset */ -fluid_defpreset_t* -new_fluid_defpreset(fluid_defsfont_t* sfont) +fluid_defpreset_t * +new_fluid_defpreset(fluid_defsfont_t *defsfont) { - fluid_defpreset_t* preset = FLUID_NEW(fluid_defpreset_t); - if (preset == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } - preset->next = NULL; - preset->sfont = sfont; - preset->name[0] = 0; - preset->bank = 0; - preset->num = 0; - preset->global_zone = NULL; - preset->zone = NULL; - return preset; + fluid_defpreset_t *defpreset = FLUID_NEW(fluid_defpreset_t); + + if(defpreset == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + defpreset->next = NULL; + defpreset->defsfont = defsfont; + defpreset->name[0] = 0; + defpreset->bank = 0; + defpreset->num = 0; + defpreset->global_zone = NULL; + defpreset->zone = NULL; + return defpreset; } /* * delete_fluid_defpreset */ -int -delete_fluid_defpreset(fluid_defpreset_t* preset) +void +delete_fluid_defpreset(fluid_defpreset_t *defpreset) { - int err = FLUID_OK; - fluid_preset_zone_t* zone; - if (preset->global_zone != NULL) { - if (delete_fluid_preset_zone(preset->global_zone) != FLUID_OK) { - err = FLUID_FAILED; - } - preset->global_zone = NULL; - } - zone = preset->zone; - while (zone != NULL) { - preset->zone = zone->next; - if (delete_fluid_preset_zone(zone) != FLUID_OK) { - err = FLUID_FAILED; - } - zone = preset->zone; - } - FLUID_FREE(preset); - return err; + fluid_preset_zone_t *zone; + + fluid_return_if_fail(defpreset != NULL); + + delete_fluid_preset_zone(defpreset->global_zone); + defpreset->global_zone = NULL; + + zone = defpreset->zone; + + while(zone != NULL) + { + defpreset->zone = zone->next; + delete_fluid_preset_zone(zone); + zone = defpreset->zone; + } + + FLUID_FREE(defpreset); } int -fluid_defpreset_get_banknum(fluid_defpreset_t* preset) +fluid_defpreset_get_banknum(fluid_defpreset_t *defpreset) { - return preset->bank; + return defpreset->bank; } int -fluid_defpreset_get_num(fluid_defpreset_t* preset) +fluid_defpreset_get_num(fluid_defpreset_t *defpreset) { - return preset->num; + return defpreset->num; } -char* -fluid_defpreset_get_name(fluid_defpreset_t* preset) +const char * +fluid_defpreset_get_name(fluid_defpreset_t *defpreset) { - return preset->name; + return defpreset->name; } /* * fluid_defpreset_next */ -fluid_defpreset_t* -fluid_defpreset_next(fluid_defpreset_t* preset) +fluid_defpreset_t * +fluid_defpreset_next(fluid_defpreset_t *defpreset) { - return preset->next; + return defpreset->next; } @@ -796,580 +687,759 @@ fluid_defpreset_next(fluid_defpreset_t* preset) * fluid_defpreset_noteon */ int -fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel) +fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int chan, int key, int vel) { - fluid_preset_zone_t *preset_zone, *global_preset_zone; - fluid_inst_t* inst; - fluid_inst_zone_t *inst_zone, *global_inst_zone; - fluid_sample_t* sample; - fluid_voice_t* voice; - fluid_mod_t * mod; - fluid_mod_t * mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */ - int mod_list_count; - int i; + fluid_preset_zone_t *preset_zone, *global_preset_zone; + fluid_inst_t *inst; + fluid_inst_zone_t *inst_zone, *global_inst_zone; + fluid_voice_zone_t *voice_zone; + fluid_list_t *list; + fluid_voice_t *voice; + fluid_mod_t *mod; + fluid_mod_t *mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */ + int mod_list_count; + int i; - global_preset_zone = fluid_defpreset_get_global_zone(preset); + global_preset_zone = fluid_defpreset_get_global_zone(defpreset); - /* run thru all the zones of this preset */ - preset_zone = fluid_defpreset_get_zone(preset); - while (preset_zone != NULL) { + /* run thru all the zones of this preset */ + preset_zone = fluid_defpreset_get_zone(defpreset); - /* check if the note falls into the key and velocity range of this - preset */ - if (fluid_preset_zone_inside_range(preset_zone, key, vel)) { + while(preset_zone != NULL) + { - inst = fluid_preset_zone_get_inst(preset_zone); - global_inst_zone = fluid_inst_get_global_zone(inst); + /* check if the note falls into the key and velocity range of this + preset */ + if(fluid_zone_inside_range(&preset_zone->range, key, vel)) + { + + inst = fluid_preset_zone_get_inst(preset_zone); + global_inst_zone = fluid_inst_get_global_zone(inst); + + /* run thru all the zones of this instrument that could start a voice */ + for(list = preset_zone->voice_zone; list != NULL; list = fluid_list_next(list)) + { + voice_zone = fluid_list_get(list); - /* run thru all the zones of this instrument */ - inst_zone = fluid_inst_get_zone(inst); - while (inst_zone != NULL) { + /* check if the instrument zone is ignored and the note falls into + the key and velocity range of this instrument zone. + An instrument zone must be ignored when its voice is already running + played by a legato passage (see fluid_synth_noteon_monopoly_legato()) */ + if(fluid_zone_inside_range(&voice_zone->range, key, vel)) + { + + inst_zone = voice_zone->inst_zone; - /* make sure this instrument zone has a valid sample */ - sample = fluid_inst_zone_get_sample(inst_zone); - if ((sample == NULL) || fluid_sample_in_rom(sample)) { - inst_zone = fluid_inst_zone_next(inst_zone); - continue; - } + /* this is a good zone. allocate a new synthesis process and initialize it */ + voice = fluid_synth_alloc_voice_LOCAL(synth, inst_zone->sample, chan, key, vel, &voice_zone->range); - /* check if the note falls into the key and velocity range of this - instrument */ - - if (fluid_inst_zone_inside_range(inst_zone, key, vel) && (sample != NULL)) { - - /* this is a good zone. allocate a new synthesis process and - initialize it */ - - voice = fluid_synth_alloc_voice(synth, sample, chan, key, vel); - if (voice == NULL) { - return FLUID_FAILED; - } - - - /* Instrument level, generators */ - - for (i = 0; i < GEN_LAST; i++) { - - /* SF 2.01 section 9.4 'bullet' 4: - * - * A generator in a local instrument zone supersedes a - * global instrument zone generator. Both cases supersede - * the default generator -> voice_gen_set */ - - if (inst_zone->gen[i].flags){ - fluid_voice_gen_set(voice, i, inst_zone->gen[i].val); - - } else if ((global_inst_zone != NULL) && (global_inst_zone->gen[i].flags)) { - fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val); - - } else { - /* The generator has not been defined in this instrument. - * Do nothing, leave it at the default. - */ - } - - } /* for all generators */ - - /* global instrument zone, modulators: Put them all into a - * list. */ - - mod_list_count = 0; - - if (global_inst_zone){ - mod = global_inst_zone->mod; - while (mod){ - mod_list[mod_list_count++] = mod; - mod = mod->next; - } - } - - /* local instrument zone, modulators. - * Replace modulators with the same definition in the list: - * SF 2.01 page 69, 'bullet' 8 - */ - mod = inst_zone->mod; - - while (mod){ - - /* 'Identical' modulators will be deleted by setting their - * list entry to NULL. The list length is known, NULL - * entries will be ignored later. SF2.01 section 9.5.1 - * page 69, 'bullet' 3 defines 'identical'. */ - - for (i = 0; i < mod_list_count; i++){ - if (mod_list[i] && fluid_mod_test_identity(mod,mod_list[i])){ - mod_list[i] = NULL; - } - } - - /* Finally add the new modulator to to the list. */ - mod_list[mod_list_count++] = mod; - mod = mod->next; - } - - /* Add instrument modulators (global / local) to the voice. */ - for (i = 0; i < mod_list_count; i++){ - - mod = mod_list[i]; - - if (mod != NULL){ /* disabled modulators CANNOT be skipped. */ - - /* Instrument modulators -supersede- existing (default) - * modulators. SF 2.01 page 69, 'bullet' 6 */ - fluid_voice_add_mod(voice, mod, FLUID_VOICE_OVERWRITE); - } - } - - /* Preset level, generators */ - - for (i = 0; i < GEN_LAST; i++) { - - /* SF 2.01 section 8.5 page 58: If some generators are - * encountered at preset level, they should be ignored */ - if ((i != GEN_STARTADDROFS) - && (i != GEN_ENDADDROFS) - && (i != GEN_STARTLOOPADDROFS) - && (i != GEN_ENDLOOPADDROFS) - && (i != GEN_STARTADDRCOARSEOFS) - && (i != GEN_ENDADDRCOARSEOFS) - && (i != GEN_STARTLOOPADDRCOARSEOFS) - && (i != GEN_KEYNUM) - && (i != GEN_VELOCITY) - && (i != GEN_ENDLOOPADDRCOARSEOFS) - && (i != GEN_SAMPLEMODE) - && (i != GEN_EXCLUSIVECLASS) - && (i != GEN_OVERRIDEROOTKEY)) { - - /* SF 2.01 section 9.4 'bullet' 9: A generator in a - * local preset zone supersedes a global preset zone - * generator. The effect is -added- to the destination - * summing node -> voice_gen_incr */ - - if (preset_zone->gen[i].flags) { - fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val); - } else if ((global_preset_zone != NULL) && global_preset_zone->gen[i].flags) { - fluid_voice_gen_incr(voice, i, global_preset_zone->gen[i].val); - } else { - /* The generator has not been defined in this preset - * Do nothing, leave it unchanged. - */ - } - } /* if available at preset level */ - } /* for all generators */ - - - /* Global preset zone, modulators: put them all into a - * list. */ - mod_list_count = 0; - if (global_preset_zone){ - mod = global_preset_zone->mod; - while (mod){ - mod_list[mod_list_count++] = mod; - mod = mod->next; - } - } - - /* Process the modulators of the local preset zone. Kick - * out all identical modulators from the global preset zone - * (SF 2.01 page 69, second-last bullet) */ - - mod = preset_zone->mod; - while (mod){ - for (i = 0; i < mod_list_count; i++){ - if (mod_list[i] && fluid_mod_test_identity(mod,mod_list[i])){ - mod_list[i] = NULL; - } - } - - /* Finally add the new modulator to the list. */ - mod_list[mod_list_count++] = mod; - mod = mod->next; - } - - /* Add preset modulators (global / local) to the voice. */ - for (i = 0; i < mod_list_count; i++){ - mod = mod_list[i]; - if ((mod != NULL) && (mod->amount != 0)) { /* disabled modulators can be skipped. */ - - /* Preset modulators -add- to existing instrument / - * default modulators. SF2.01 page 70 first bullet on - * page */ - fluid_voice_add_mod(voice, mod, FLUID_VOICE_ADD); - } - } - - /* add the synthesis process to the synthesis loop. */ - fluid_synth_start_voice(synth, voice); - - /* Store the ID of the first voice that was created by this noteon event. - * Exclusive class may only terminate older voices. - * That avoids killing voices, which have just been created. - * (a noteon event can create several voice processes with the same exclusive - * class - for example when using stereo samples) - */ - } - - inst_zone = fluid_inst_zone_next(inst_zone); - } - } - preset_zone = fluid_preset_zone_next(preset_zone); - } - - return FLUID_OK; + if(voice == NULL) + { + return FLUID_FAILED; + } + + + /* Instrument level, generators */ + + for(i = 0; i < GEN_LAST; i++) + { + + /* SF 2.01 section 9.4 'bullet' 4: + * + * A generator in a local instrument zone supersedes a + * global instrument zone generator. Both cases supersede + * the default generator -> voice_gen_set */ + + if(inst_zone->gen[i].flags) + { + fluid_voice_gen_set(voice, i, inst_zone->gen[i].val); + + } + else if((global_inst_zone != NULL) && (global_inst_zone->gen[i].flags)) + { + fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val); + + } + else + { + /* The generator has not been defined in this instrument. + * Do nothing, leave it at the default. + */ + } + + } /* for all generators */ + + /* global instrument zone, modulators: Put them all into a + * list. */ + + mod_list_count = 0; + + if(global_inst_zone) + { + mod = global_inst_zone->mod; + + while(mod) + { + mod_list[mod_list_count++] = mod; + mod = mod->next; + } + } + + /* local instrument zone, modulators. + * Replace modulators with the same definition in the list: + * SF 2.01 page 69, 'bullet' 8 + */ + mod = inst_zone->mod; + + while(mod) + { + + /* 'Identical' modulators will be deleted by setting their + * list entry to NULL. The list length is known, NULL + * entries will be ignored later. SF2.01 section 9.5.1 + * page 69, 'bullet' 3 defines 'identical'. */ + + for(i = 0; i < mod_list_count; i++) + { + if(mod_list[i] && fluid_mod_test_identity(mod, mod_list[i])) + { + mod_list[i] = NULL; + } + } + + /* Finally add the new modulator to to the list. */ + mod_list[mod_list_count++] = mod; + mod = mod->next; + } + + /* Add instrument modulators (global / local) to the voice. */ + for(i = 0; i < mod_list_count; i++) + { + + mod = mod_list[i]; + + if(mod != NULL) /* disabled modulators CANNOT be skipped. */ + { + + /* Instrument modulators -supersede- existing (default) + * modulators. SF 2.01 page 69, 'bullet' 6 */ + fluid_voice_add_mod(voice, mod, FLUID_VOICE_OVERWRITE); + } + } + + /* Preset level, generators */ + + for(i = 0; i < GEN_LAST; i++) + { + + /* SF 2.01 section 8.5 page 58: If some generators are + encountered at preset level, they should be ignored. + However this check is not necessary when the soundfont + loader has ignored invalid preset generators. + Actually load_pgen()has ignored these invalid preset + generators: + GEN_STARTADDROFS, GEN_ENDADDROFS, + GEN_STARTLOOPADDROFS, GEN_ENDLOOPADDROFS, + GEN_STARTADDRCOARSEOFS,GEN_ENDADDRCOARSEOFS, + GEN_STARTLOOPADDRCOARSEOFS, + GEN_KEYNUM, GEN_VELOCITY, + GEN_ENDLOOPADDRCOARSEOFS, + GEN_SAMPLEMODE, GEN_EXCLUSIVECLASS,GEN_OVERRIDEROOTKEY + */ + + /* SF 2.01 section 9.4 'bullet' 9: A generator in a + * local preset zone supersedes a global preset zone + * generator. The effect is -added- to the destination + * summing node -> voice_gen_incr */ + + if(preset_zone->gen[i].flags) + { + fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val); + } + else if((global_preset_zone != NULL) && global_preset_zone->gen[i].flags) + { + fluid_voice_gen_incr(voice, i, global_preset_zone->gen[i].val); + } + else + { + /* The generator has not been defined in this preset + * Do nothing, leave it unchanged. + */ + } + } /* for all generators */ + + + /* Global preset zone, modulators: put them all into a + * list. */ + mod_list_count = 0; + + if(global_preset_zone) + { + mod = global_preset_zone->mod; + + while(mod) + { + mod_list[mod_list_count++] = mod; + mod = mod->next; + } + } + + /* Process the modulators of the local preset zone. Kick + * out all identical modulators from the global preset zone + * (SF 2.01 page 69, second-last bullet) */ + + mod = preset_zone->mod; + + while(mod) + { + for(i = 0; i < mod_list_count; i++) + { + if(mod_list[i] && fluid_mod_test_identity(mod, mod_list[i])) + { + mod_list[i] = NULL; + } + } + + /* Finally add the new modulator to the list. */ + mod_list[mod_list_count++] = mod; + mod = mod->next; + } + + /* Add preset modulators (global / local) to the voice. */ + for(i = 0; i < mod_list_count; i++) + { + mod = mod_list[i]; + + if((mod != NULL) && (mod->amount != 0)) /* disabled modulators can be skipped. */ + { + + /* Preset modulators -add- to existing instrument / + * default modulators. SF2.01 page 70 first bullet on + * page */ + fluid_voice_add_mod(voice, mod, FLUID_VOICE_ADD); + } + } + + /* add the synthesis process to the synthesis loop. */ + fluid_synth_start_voice(synth, voice); + + /* Store the ID of the first voice that was created by this noteon event. + * Exclusive class may only terminate older voices. + * That avoids killing voices, which have just been created. + * (a noteon event can create several voice processes with the same exclusive + * class - for example when using stereo samples) + */ + } + + } + } + + preset_zone = fluid_preset_zone_next(preset_zone); + } + + return FLUID_OK; } /* * fluid_defpreset_set_global_zone */ int -fluid_defpreset_set_global_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone) +fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone) { - preset->global_zone = zone; - return FLUID_OK; + defpreset->global_zone = zone; + return FLUID_OK; } /* * fluid_defpreset_import_sfont */ int -fluid_defpreset_import_sfont(fluid_defpreset_t* preset, - SFPreset* sfpreset, - fluid_defsfont_t* sfont) +fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset, + SFPreset *sfpreset, + fluid_defsfont_t *defsfont) { - fluid_list_t *p; - SFZone* sfzone; - fluid_preset_zone_t* zone; - int count; - char zone_name[256]; - if ((sfpreset->name != NULL) && (FLUID_STRLEN(sfpreset->name) > 0)) { - FLUID_STRCPY(preset->name, sfpreset->name); - } else { - FLUID_SPRINTF(preset->name, "Bank%d,Preset%d", sfpreset->bank, sfpreset->prenum); - } - preset->bank = sfpreset->bank; - preset->num = sfpreset->prenum; - p = sfpreset->zone; - count = 0; - while (p != NULL) { - sfzone = (SFZone *) p->data; - FLUID_SPRINTF(zone_name, "%s/%d", preset->name, count); - zone = new_fluid_preset_zone(zone_name); - if (zone == NULL) { - return FLUID_FAILED; - } - if (fluid_preset_zone_import_sfont(zone, sfzone, sfont) != FLUID_OK) { - delete_fluid_preset_zone(zone); - return FLUID_FAILED; - } - if ((count == 0) && (fluid_preset_zone_get_inst(zone) == NULL)) { - fluid_defpreset_set_global_zone(preset, zone); - } else if (fluid_defpreset_add_zone(preset, zone) != FLUID_OK) { - return FLUID_FAILED; - } - p = fluid_list_next(p); - count++; - } - return FLUID_OK; + fluid_list_t *p; + SFZone *sfzone; + fluid_preset_zone_t *zone; + int count; + char zone_name[256]; + + if(FLUID_STRLEN(sfpreset->name) > 0) + { + FLUID_STRCPY(defpreset->name, sfpreset->name); + } + else + { + FLUID_SNPRINTF(defpreset->name, sizeof(defpreset->name), "Bank%d,Pre%d", sfpreset->bank, sfpreset->prenum); + } + + defpreset->bank = sfpreset->bank; + defpreset->num = sfpreset->prenum; + p = sfpreset->zone; + count = 0; + + while(p != NULL) + { + sfzone = (SFZone *)fluid_list_get(p); + FLUID_SNPRINTF(zone_name, sizeof(zone_name), "%s/%d", defpreset->name, count); + zone = new_fluid_preset_zone(zone_name); + + if(zone == NULL) + { + return FLUID_FAILED; + } + + if(fluid_preset_zone_import_sfont(zone, sfzone, defsfont) != FLUID_OK) + { + delete_fluid_preset_zone(zone); + return FLUID_FAILED; + } + + if((count == 0) && (fluid_preset_zone_get_inst(zone) == NULL)) + { + fluid_defpreset_set_global_zone(defpreset, zone); + } + else if(fluid_defpreset_add_zone(defpreset, zone) != FLUID_OK) + { + return FLUID_FAILED; + } + + p = fluid_list_next(p); + count++; + } + + return FLUID_OK; } /* * fluid_defpreset_add_zone */ int -fluid_defpreset_add_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone) +fluid_defpreset_add_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone) { - if (preset->zone == NULL) { - zone->next = NULL; - preset->zone = zone; - } else { - zone->next = preset->zone; - preset->zone = zone; - } - return FLUID_OK; + if(defpreset->zone == NULL) + { + zone->next = NULL; + defpreset->zone = zone; + } + else + { + zone->next = defpreset->zone; + defpreset->zone = zone; + } + + return FLUID_OK; } /* * fluid_defpreset_get_zone */ -fluid_preset_zone_t* -fluid_defpreset_get_zone(fluid_defpreset_t* preset) +fluid_preset_zone_t * +fluid_defpreset_get_zone(fluid_defpreset_t *defpreset) { - return preset->zone; + return defpreset->zone; } /* * fluid_defpreset_get_global_zone */ -fluid_preset_zone_t* -fluid_defpreset_get_global_zone(fluid_defpreset_t* preset) +fluid_preset_zone_t * +fluid_defpreset_get_global_zone(fluid_defpreset_t *defpreset) { - return preset->global_zone; + return defpreset->global_zone; } +/*************************************************************** + * + * PRESET_ZONE + */ + /* * fluid_preset_zone_next */ -fluid_preset_zone_t* -fluid_preset_zone_next(fluid_preset_zone_t* preset) +fluid_preset_zone_t * +fluid_preset_zone_next(fluid_preset_zone_t *zone) { - return preset->next; + return zone->next; } /* * new_fluid_preset_zone */ -fluid_preset_zone_t* +fluid_preset_zone_t * new_fluid_preset_zone(char *name) { - int size; - fluid_preset_zone_t* zone = NULL; - zone = FLUID_NEW(fluid_preset_zone_t); - if (zone == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } - zone->next = NULL; - size = 1 + FLUID_STRLEN(name); - zone->name = FLUID_MALLOC(size); - if (zone->name == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - FLUID_FREE(zone); - return NULL; - } - FLUID_STRCPY(zone->name, name); - zone->inst = NULL; - zone->keylo = 0; - zone->keyhi = 128; - zone->vello = 0; - zone->velhi = 128; - - /* Flag all generators as unused (default, they will be set when they are found - * in the sound font). - * This also sets the generator values to default, but that is of no concern here.*/ - fluid_gen_set_default_values(&zone->gen[0]); - zone->mod = NULL; /* list of modulators */ - return zone; -} + fluid_preset_zone_t *zone = NULL; + zone = FLUID_NEW(fluid_preset_zone_t); -/*************************************************************** - * - * PRESET_ZONE - */ + if(zone == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + zone->next = NULL; + zone->voice_zone = NULL; + zone->name = FLUID_STRDUP(name); + + if(zone->name == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_FREE(zone); + return NULL; + } + + zone->inst = NULL; + zone->range.keylo = 0; + zone->range.keyhi = 128; + zone->range.vello = 0; + zone->range.velhi = 128; + zone->range.ignore = FALSE; + + /* Flag all generators as unused (default, they will be set when they are found + * in the sound font). + * This also sets the generator values to default, but that is of no concern here.*/ + fluid_gen_set_default_values(&zone->gen[0]); + zone->mod = NULL; /* list of modulators */ + return zone; +} /* * delete_fluid_preset_zone */ -int -delete_fluid_preset_zone(fluid_preset_zone_t* zone) +void +delete_fluid_preset_zone(fluid_preset_zone_t *zone) +{ + fluid_mod_t *mod, *tmp; + fluid_list_t *list; + + fluid_return_if_fail(zone != NULL); + + mod = zone->mod; + + while(mod) /* delete the modulators */ + { + tmp = mod; + mod = mod->next; + delete_fluid_mod(tmp); + } + + for(list = zone->voice_zone; list != NULL; list = fluid_list_next(list)) + { + FLUID_FREE(fluid_list_get(list)); + } + + delete_fluid_list(zone->voice_zone); + + FLUID_FREE(zone->name); + FLUID_FREE(zone); +} + +static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone) { - fluid_mod_t *mod, *tmp; + fluid_inst_zone_t *inst_zone; + fluid_sample_t *sample; + fluid_voice_zone_t *voice_zone; + fluid_zone_range_t *irange; + fluid_zone_range_t *prange = &preset_zone->range; + + fluid_return_val_if_fail(preset_zone->inst != NULL, FLUID_FAILED); + + inst_zone = fluid_inst_get_zone(preset_zone->inst); - mod = zone->mod; - while (mod) /* delete the modulators */ + while(inst_zone != NULL) { - tmp = mod; - mod = mod->next; - fluid_mod_delete (tmp); + + /* We only create voice ranges for zones that could actually start a voice, + * i.e. that have a sample and don't point to ROM */ + sample = fluid_inst_zone_get_sample(inst_zone); + + if((sample == NULL) || fluid_sample_in_rom(sample)) + { + inst_zone = fluid_inst_zone_next(inst_zone); + continue; + } + + voice_zone = FLUID_NEW(fluid_voice_zone_t); + + if(voice_zone == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + voice_zone->inst_zone = inst_zone; + + irange = &inst_zone->range; + + voice_zone->range.keylo = (prange->keylo > irange->keylo) ? prange->keylo : irange->keylo; + voice_zone->range.keyhi = (prange->keyhi < irange->keyhi) ? prange->keyhi : irange->keyhi; + voice_zone->range.vello = (prange->vello > irange->vello) ? prange->vello : irange->vello; + voice_zone->range.velhi = (prange->velhi < irange->velhi) ? prange->velhi : irange->velhi; + voice_zone->range.ignore = FALSE; + + preset_zone->voice_zone = fluid_list_append(preset_zone->voice_zone, voice_zone); + + inst_zone = fluid_inst_zone_next(inst_zone); } - if (zone->name) FLUID_FREE (zone->name); - if (zone->inst) delete_fluid_inst (zone->inst); - FLUID_FREE(zone); - return FLUID_OK; + return FLUID_OK; } /* * fluid_preset_zone_import_sfont */ int -fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont) +fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defsfont) { - fluid_list_t *r; - SFGen* sfgen; - int count; - for (count = 0, r = sfzone->gen; r != NULL; count++) { - sfgen = (SFGen *) r->data; - switch (sfgen->id) { - case GEN_KEYRANGE: - zone->keylo = (int) sfgen->amount.range.lo; - zone->keyhi = (int) sfgen->amount.range.hi; - break; - case GEN_VELRANGE: - zone->vello = (int) sfgen->amount.range.lo; - zone->velhi = (int) sfgen->amount.range.hi; - break; - default: - /* FIXME: some generators have an unsigne word amount value but i don't know which ones */ - zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword; - zone->gen[sfgen->id].flags = GEN_SET; - break; - } - r = fluid_list_next(r); - } - if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) { - zone->inst = (fluid_inst_t*) new_fluid_inst(); - if (zone->inst == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return FLUID_FAILED; - } - if (fluid_inst_import_sfont(zone->inst, (SFInst *) sfzone->instsamp->data, sfont) != FLUID_OK) { - return FLUID_FAILED; - } - } - - /* Import the modulators (only SF2.1 and higher) */ - for (count = 0, r = sfzone->mod; r != NULL; count++) { - - SFMod* mod_src = (SFMod *)r->data; - fluid_mod_t * mod_dest = fluid_mod_new(); - int type; - - if (mod_dest == NULL){ - return FLUID_FAILED; - } - mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/ - - /* *** Amount *** */ - mod_dest->amount = mod_src->amount; - - /* *** Source *** */ - mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */ - mod_dest->flags1 = 0; - - /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ - if (mod_src->src & (1<<7)){ - mod_dest->flags1 |= FLUID_MOD_CC; - } else { - mod_dest->flags1 |= FLUID_MOD_GC; - } - - /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ - if (mod_src->src & (1<<8)){ - mod_dest->flags1 |= FLUID_MOD_NEGATIVE; - } else { - mod_dest->flags1 |= FLUID_MOD_POSITIVE; - } - - /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ - if (mod_src->src & (1<<9)){ - mod_dest->flags1 |= FLUID_MOD_BIPOLAR; - } else { - mod_dest->flags1 |= FLUID_MOD_UNIPOLAR; - } - - /* modulator source types: SF2.01 section 8.2.1 page 52 */ - type=(mod_src->src) >> 10; - type &= 63; /* type is a 6-bit value */ - if (type == 0){ - mod_dest->flags1 |= FLUID_MOD_LINEAR; - } else if (type == 1){ - mod_dest->flags1 |= FLUID_MOD_CONCAVE; - } else if (type == 2){ - mod_dest->flags1 |= FLUID_MOD_CONVEX; - } else if (type == 3){ - mod_dest->flags1 |= FLUID_MOD_SWITCH; - } else { - /* This shouldn't happen - unknown type! - * Deactivate the modulator by setting the amount to 0. */ - mod_dest->amount=0; - } - - /* *** Dest *** */ - mod_dest->dest = mod_src->dest; /* index of controlled generator */ - - /* *** Amount source *** */ - mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, p.50 */ - mod_dest->flags2 = 0; - - /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ - if (mod_src->amtsrc & (1<<7)){ - mod_dest->flags2 |= FLUID_MOD_CC; - } else { - mod_dest->flags2 |= FLUID_MOD_GC; - } - - /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ - if (mod_src->amtsrc & (1<<8)){ - mod_dest->flags2 |= FLUID_MOD_NEGATIVE; - } else { - mod_dest->flags2 |= FLUID_MOD_POSITIVE; - } - - /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ - if (mod_src->amtsrc & (1<<9)){ - mod_dest->flags2 |= FLUID_MOD_BIPOLAR; - } else { - mod_dest->flags2 |= FLUID_MOD_UNIPOLAR; - } - - /* modulator source types: SF2.01 section 8.2.1 page 52 */ - type = (mod_src->amtsrc) >> 10; - type &= 63; /* type is a 6-bit value */ - if (type == 0){ - mod_dest->flags2 |= FLUID_MOD_LINEAR; - } else if (type == 1){ - mod_dest->flags2 |= FLUID_MOD_CONCAVE; - } else if (type == 2){ - mod_dest->flags2 |= FLUID_MOD_CONVEX; - } else if (type == 3){ - mod_dest->flags2 |= FLUID_MOD_SWITCH; - } else { - /* This shouldn't happen - unknown type! - * Deactivate the modulator by setting the amount to 0. */ - mod_dest->amount=0; - } - - /* *** Transform *** */ - /* SF2.01 only uses the 'linear' transform (0). - * Deactivate the modulator by setting the amount to 0 in any other case. - */ - if (mod_src->trans !=0){ - mod_dest->amount = 0; - } - - /* Store the new modulator in the zone The order of modulators - * will make a difference, at least in an instrument context: The - * second modulator overwrites the first one, if they only differ - * in amount. */ - if (count == 0){ - zone->mod = mod_dest; - } else { - fluid_mod_t * last_mod = zone->mod; - - /* Find the end of the list */ - while (last_mod->next != NULL){ - last_mod=last_mod->next; - } - - last_mod->next = mod_dest; - } - - r = fluid_list_next(r); - } /* foreach modulator */ - - return FLUID_OK; + fluid_list_t *r; + SFGen *sfgen; + SFInst *sfinst; + int count; + + for(count = 0, r = sfzone->gen; r != NULL; count++) + { + sfgen = (SFGen *)fluid_list_get(r); + + switch(sfgen->id) + { + case GEN_KEYRANGE: + zone->range.keylo = sfgen->amount.range.lo; + zone->range.keyhi = sfgen->amount.range.hi; + break; + + case GEN_VELRANGE: + zone->range.vello = sfgen->amount.range.lo; + zone->range.velhi = sfgen->amount.range.hi; + break; + + case GEN_ATTENUATION: + /* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at + * preset and instrument level */ + zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR; + zone->gen[sfgen->id].flags = GEN_SET; + break; + + default: + /* FIXME: some generators have an unsigne word amount value but i don't know which ones */ + zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword; + zone->gen[sfgen->id].flags = GEN_SET; + break; + } + + r = fluid_list_next(r); + } + + if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) + { + sfinst = sfzone->instsamp->data; + + zone->inst = find_inst_by_idx(defsfont, sfinst->idx); + + if(zone->inst == NULL) + { + zone->inst = fluid_inst_import_sfont(zone, sfinst, defsfont); + } + + if(zone->inst == NULL) + { + return FLUID_FAILED; + } + + if(fluid_preset_zone_create_voice_zones(zone) == FLUID_FAILED) + { + return FLUID_FAILED; + } + } + + /* Import the modulators (only SF2.1 and higher) */ + for(count = 0, r = sfzone->mod; r != NULL; count++) + { + + SFMod *mod_src = (SFMod *)fluid_list_get(r); + fluid_mod_t *mod_dest = new_fluid_mod(); + int type; + + if(mod_dest == NULL) + { + return FLUID_FAILED; + } + + mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/ + + /* *** Amount *** */ + mod_dest->amount = mod_src->amount; + + /* *** Source *** */ + mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */ + mod_dest->flags1 = 0; + + /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ + if(mod_src->src & (1 << 7)) + { + mod_dest->flags1 |= FLUID_MOD_CC; + } + else + { + mod_dest->flags1 |= FLUID_MOD_GC; + } + + /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ + if(mod_src->src & (1 << 8)) + { + mod_dest->flags1 |= FLUID_MOD_NEGATIVE; + } + else + { + mod_dest->flags1 |= FLUID_MOD_POSITIVE; + } + + /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ + if(mod_src->src & (1 << 9)) + { + mod_dest->flags1 |= FLUID_MOD_BIPOLAR; + } + else + { + mod_dest->flags1 |= FLUID_MOD_UNIPOLAR; + } + + /* modulator source types: SF2.01 section 8.2.1 page 52 */ + type = (mod_src->src) >> 10; + type &= 63; /* type is a 6-bit value */ + + if(type == 0) + { + mod_dest->flags1 |= FLUID_MOD_LINEAR; + } + else if(type == 1) + { + mod_dest->flags1 |= FLUID_MOD_CONCAVE; + } + else if(type == 2) + { + mod_dest->flags1 |= FLUID_MOD_CONVEX; + } + else if(type == 3) + { + mod_dest->flags1 |= FLUID_MOD_SWITCH; + } + else + { + /* This shouldn't happen - unknown type! + * Deactivate the modulator by setting the amount to 0. */ + mod_dest->amount = 0; + } + + /* *** Dest *** */ + mod_dest->dest = mod_src->dest; /* index of controlled generator */ + + /* *** Amount source *** */ + mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, p.50 */ + mod_dest->flags2 = 0; + + /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ + if(mod_src->amtsrc & (1 << 7)) + { + mod_dest->flags2 |= FLUID_MOD_CC; + } + else + { + mod_dest->flags2 |= FLUID_MOD_GC; + } + + /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ + if(mod_src->amtsrc & (1 << 8)) + { + mod_dest->flags2 |= FLUID_MOD_NEGATIVE; + } + else + { + mod_dest->flags2 |= FLUID_MOD_POSITIVE; + } + + /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ + if(mod_src->amtsrc & (1 << 9)) + { + mod_dest->flags2 |= FLUID_MOD_BIPOLAR; + } + else + { + mod_dest->flags2 |= FLUID_MOD_UNIPOLAR; + } + + /* modulator source types: SF2.01 section 8.2.1 page 52 */ + type = (mod_src->amtsrc) >> 10; + type &= 63; /* type is a 6-bit value */ + + if(type == 0) + { + mod_dest->flags2 |= FLUID_MOD_LINEAR; + } + else if(type == 1) + { + mod_dest->flags2 |= FLUID_MOD_CONCAVE; + } + else if(type == 2) + { + mod_dest->flags2 |= FLUID_MOD_CONVEX; + } + else if(type == 3) + { + mod_dest->flags2 |= FLUID_MOD_SWITCH; + } + else + { + /* This shouldn't happen - unknown type! + * Deactivate the modulator by setting the amount to 0. */ + mod_dest->amount = 0; + } + + /* *** Transform *** */ + /* SF2.01 only uses the 'linear' transform (0). + * Deactivate the modulator by setting the amount to 0 in any other case. + */ + if(mod_src->trans != 0) + { + mod_dest->amount = 0; + } + + /* Store the new modulator in the zone The order of modulators + * will make a difference, at least in an instrument context: The + * second modulator overwrites the first one, if they only differ + * in amount. */ + if(count == 0) + { + zone->mod = mod_dest; + } + else + { + fluid_mod_t *last_mod = zone->mod; + + /* Find the end of the list */ + while(last_mod->next != NULL) + { + last_mod = last_mod->next; + } + + last_mod->next = mod_dest; + } + + r = fluid_list_next(r); + } /* foreach modulator */ + + return FLUID_OK; } /* * fluid_preset_zone_get_inst */ -fluid_inst_t* -fluid_preset_zone_get_inst(fluid_preset_zone_t* zone) +fluid_inst_t * +fluid_preset_zone_get_inst(fluid_preset_zone_t *zone) { - return zone->inst; + return zone->inst; } -/* - * fluid_preset_zone_inside_range - */ -int -fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel) -{ - return ((zone->keylo <= key) && - (zone->keyhi >= key) && - (zone->vello <= vel) && - (zone->velhi >= vel)); -} /*************************************************************** * @@ -1379,136 +1449,167 @@ fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel) /* * new_fluid_inst */ -fluid_inst_t* +fluid_inst_t * new_fluid_inst() { - fluid_inst_t* inst = FLUID_NEW(fluid_inst_t); - if (inst == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } - inst->name[0] = 0; - inst->global_zone = NULL; - inst->zone = NULL; - return inst; + fluid_inst_t *inst = FLUID_NEW(fluid_inst_t); + + if(inst == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + inst->name[0] = 0; + inst->global_zone = NULL; + inst->zone = NULL; + return inst; } /* * delete_fluid_inst */ -int -delete_fluid_inst(fluid_inst_t* inst) +void +delete_fluid_inst(fluid_inst_t *inst) { - fluid_inst_zone_t* zone; - int err = FLUID_OK; - if (inst->global_zone != NULL) { - if (delete_fluid_inst_zone(inst->global_zone) != FLUID_OK) { - err = FLUID_FAILED; - } + fluid_inst_zone_t *zone; + + fluid_return_if_fail(inst != NULL); + + delete_fluid_inst_zone(inst->global_zone); inst->global_zone = NULL; - } - zone = inst->zone; - while (zone != NULL) { - inst->zone = zone->next; - if (delete_fluid_inst_zone(zone) != FLUID_OK) { - err = FLUID_FAILED; - } + zone = inst->zone; - } - FLUID_FREE(inst); - return err; + + while(zone != NULL) + { + inst->zone = zone->next; + delete_fluid_inst_zone(zone); + zone = inst->zone; + } + + FLUID_FREE(inst); } /* * fluid_inst_set_global_zone */ int -fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone) +fluid_inst_set_global_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone) { - inst->global_zone = zone; - return FLUID_OK; + inst->global_zone = zone; + return FLUID_OK; } /* * fluid_inst_import_sfont */ -int -fluid_inst_import_sfont(fluid_inst_t* inst, SFInst *sfinst, fluid_defsfont_t* sfont) +fluid_inst_t * +fluid_inst_import_sfont(fluid_preset_zone_t *preset_zone, SFInst *sfinst, fluid_defsfont_t *defsfont) { - fluid_list_t *p; - SFZone* sfzone; - fluid_inst_zone_t* zone; - char zone_name[256]; - int count; + fluid_list_t *p; + fluid_inst_t *inst; + SFZone *sfzone; + fluid_inst_zone_t *inst_zone; + char zone_name[256]; + int count; - p = sfinst->zone; - if ((sfinst->name != NULL) && (FLUID_STRLEN(sfinst->name) > 0)) { - FLUID_STRCPY(inst->name, sfinst->name); - } else { - FLUID_STRCPY(inst->name, "<untitled>"); - } + inst = (fluid_inst_t *) new_fluid_inst(); - count = 0; - while (p != NULL) { + if(inst == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } - sfzone = (SFZone *) p->data; - FLUID_SPRINTF(zone_name, "%s/%d", inst->name, count); + inst->source_idx = sfinst->idx; - zone = new_fluid_inst_zone(zone_name); - if (zone == NULL) { - return FLUID_FAILED; - } + p = sfinst->zone; - if (fluid_inst_zone_import_sfont(zone, sfzone, sfont) != FLUID_OK) { - delete_fluid_inst_zone(zone); - return FLUID_FAILED; + if(FLUID_STRLEN(sfinst->name) > 0) + { + FLUID_STRCPY(inst->name, sfinst->name); + } + else + { + FLUID_STRCPY(inst->name, "<untitled>"); } - if ((count == 0) && (fluid_inst_zone_get_sample(zone) == NULL)) { - fluid_inst_set_global_zone(inst, zone); + count = 0; + + while(p != NULL) + { + + sfzone = (SFZone *)fluid_list_get(p); + FLUID_SNPRINTF(zone_name, sizeof(zone_name), "%s/%d", inst->name, count); + + inst_zone = new_fluid_inst_zone(zone_name); + + if(inst_zone == NULL) + { + return NULL; + } + + if(fluid_inst_zone_import_sfont(inst_zone, sfzone, defsfont) != FLUID_OK) + { + delete_fluid_inst_zone(inst_zone); + return NULL; + } + + if((count == 0) && (fluid_inst_zone_get_sample(inst_zone) == NULL)) + { + fluid_inst_set_global_zone(inst, inst_zone); + + } + else if(fluid_inst_add_zone(inst, inst_zone) != FLUID_OK) + { + return NULL; + } - } else if (fluid_inst_add_zone(inst, zone) != FLUID_OK) { - return FLUID_FAILED; + p = fluid_list_next(p); + count++; } - p = fluid_list_next(p); - count++; - } - return FLUID_OK; + defsfont->inst = fluid_list_append(defsfont->inst, inst); + return inst; } /* * fluid_inst_add_zone */ int -fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone) +fluid_inst_add_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone) { - if (inst->zone == NULL) { - zone->next = NULL; - inst->zone = zone; - } else { - zone->next = inst->zone; - inst->zone = zone; - } - return FLUID_OK; + if(inst->zone == NULL) + { + zone->next = NULL; + inst->zone = zone; + } + else + { + zone->next = inst->zone; + inst->zone = zone; + } + + return FLUID_OK; } /* * fluid_inst_get_zone */ -fluid_inst_zone_t* -fluid_inst_get_zone(fluid_inst_t* inst) +fluid_inst_zone_t * +fluid_inst_get_zone(fluid_inst_t *inst) { - return inst->zone; + return inst->zone; } /* * fluid_inst_get_global_zone */ -fluid_inst_zone_t* -fluid_inst_get_global_zone(fluid_inst_t* inst) +fluid_inst_zone_t * +fluid_inst_get_global_zone(fluid_inst_t *inst) { - return inst->global_zone; + return inst->global_zone; } /*************************************************************** @@ -1519,1914 +1620,572 @@ fluid_inst_get_global_zone(fluid_inst_t* inst) /* * new_fluid_inst_zone */ -fluid_inst_zone_t* -new_fluid_inst_zone(char* name) -{ - int size; - fluid_inst_zone_t* zone = NULL; - zone = FLUID_NEW(fluid_inst_zone_t); - if (zone == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } - zone->next = NULL; - size = 1 + FLUID_STRLEN(name); - zone->name = FLUID_MALLOC(size); - if (zone->name == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - FLUID_FREE(zone); - return NULL; - } - FLUID_STRCPY(zone->name, name); - zone->sample = NULL; - zone->keylo = 0; - zone->keyhi = 128; - zone->vello = 0; - zone->velhi = 128; - - /* Flag the generators as unused. - * This also sets the generator values to default, but they will be overwritten anyway, if used.*/ - fluid_gen_set_default_values(&zone->gen[0]); - zone->mod=NULL; /* list of modulators */ - return zone; -} - -/* - * delete_fluid_inst_zone - */ -int -delete_fluid_inst_zone(fluid_inst_zone_t* zone) +fluid_inst_zone_t * +new_fluid_inst_zone(char *name) { - fluid_mod_t *mod, *tmp; + fluid_inst_zone_t *zone = NULL; + zone = FLUID_NEW(fluid_inst_zone_t); - mod = zone->mod; - while (mod) /* delete the modulators */ + if(zone == NULL) { - tmp = mod; - mod = mod->next; - fluid_mod_delete (tmp); + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; } - if (zone->name) FLUID_FREE (zone->name); - FLUID_FREE(zone); - return FLUID_OK; -} - -/* - * fluid_inst_zone_next - */ -fluid_inst_zone_t* -fluid_inst_zone_next(fluid_inst_zone_t* zone) -{ - return zone->next; -} - -/* - * fluid_inst_zone_import_sfont - */ -int -fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont) -{ - fluid_list_t *r; - SFGen* sfgen; - int count; - - for (count = 0, r = sfzone->gen; r != NULL; count++) { - sfgen = (SFGen *) r->data; - switch (sfgen->id) { - case GEN_KEYRANGE: - zone->keylo = (int) sfgen->amount.range.lo; - zone->keyhi = (int) sfgen->amount.range.hi; - break; - case GEN_VELRANGE: - zone->vello = (int) sfgen->amount.range.lo; - zone->velhi = (int) sfgen->amount.range.hi; - break; - default: - /* FIXME: some generators have an unsigned word amount value but - i don't know which ones */ - zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword; - zone->gen[sfgen->id].flags = GEN_SET; - break; - } - r = fluid_list_next(r); - } - - /* FIXME */ -/* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */ -/* FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */ -/* } */ - - /* fixup sample pointer */ - if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) - zone->sample = ((SFSample *)(sfzone->instsamp->data))->fluid_sample; - - /* Import the modulators (only SF2.1 and higher) */ - for (count = 0, r = sfzone->mod; r != NULL; count++) { - SFMod* mod_src = (SFMod *) r->data; - int type; - fluid_mod_t* mod_dest; - - mod_dest = fluid_mod_new(); - if (mod_dest == NULL){ - return FLUID_FAILED; - } - - mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/ - - /* *** Amount *** */ - mod_dest->amount = mod_src->amount; - - /* *** Source *** */ - mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */ - mod_dest->flags1 = 0; - - /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ - if (mod_src->src & (1<<7)){ - mod_dest->flags1 |= FLUID_MOD_CC; - } else { - mod_dest->flags1 |= FLUID_MOD_GC; - } - - /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ - if (mod_src->src & (1<<8)){ - mod_dest->flags1 |= FLUID_MOD_NEGATIVE; - } else { - mod_dest->flags1 |= FLUID_MOD_POSITIVE; - } - - /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ - if (mod_src->src & (1<<9)){ - mod_dest->flags1 |= FLUID_MOD_BIPOLAR; - } else { - mod_dest->flags1 |= FLUID_MOD_UNIPOLAR; - } - - /* modulator source types: SF2.01 section 8.2.1 page 52 */ - type = (mod_src->src) >> 10; - type &= 63; /* type is a 6-bit value */ - if (type == 0){ - mod_dest->flags1 |= FLUID_MOD_LINEAR; - } else if (type == 1){ - mod_dest->flags1 |= FLUID_MOD_CONCAVE; - } else if (type == 2){ - mod_dest->flags1 |= FLUID_MOD_CONVEX; - } else if (type == 3){ - mod_dest->flags1 |= FLUID_MOD_SWITCH; - } else { - /* This shouldn't happen - unknown type! - * Deactivate the modulator by setting the amount to 0. */ - mod_dest->amount = 0; - } - - /* *** Dest *** */ - mod_dest->dest=mod_src->dest; /* index of controlled generator */ - - /* *** Amount source *** */ - mod_dest->src2=mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, page 50 */ - mod_dest->flags2 = 0; - - /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ - if (mod_src->amtsrc & (1<<7)){ - mod_dest->flags2 |= FLUID_MOD_CC; - } else { - mod_dest->flags2 |= FLUID_MOD_GC; - } - - /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ - if (mod_src->amtsrc & (1<<8)){ - mod_dest->flags2 |= FLUID_MOD_NEGATIVE; - } else { - mod_dest->flags2 |= FLUID_MOD_POSITIVE; - } - - /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ - if (mod_src->amtsrc & (1<<9)){ - mod_dest->flags2 |= FLUID_MOD_BIPOLAR; - } else { - mod_dest->flags2 |= FLUID_MOD_UNIPOLAR; - } - - /* modulator source types: SF2.01 section 8.2.1 page 52 */ - type=(mod_src->amtsrc) >> 10; - type &= 63; /* type is a 6-bit value */ - if (type == 0){ - mod_dest->flags2 |= FLUID_MOD_LINEAR; - } else if (type == 1){ - mod_dest->flags2 |= FLUID_MOD_CONCAVE; - } else if (type == 2){ - mod_dest->flags2 |= FLUID_MOD_CONVEX; - } else if (type == 3){ - mod_dest->flags2 |= FLUID_MOD_SWITCH; - } else { - /* This shouldn't happen - unknown type! - * Deactivate the modulator by setting the amount to 0. */ - mod_dest->amount = 0; - } - - /* *** Transform *** */ - /* SF2.01 only uses the 'linear' transform (0). - * Deactivate the modulator by setting the amount to 0 in any other case. - */ - if (mod_src->trans !=0){ - mod_dest->amount = 0; - } - - /* Store the new modulator in the zone - * The order of modulators will make a difference, at least in an instrument context: - * The second modulator overwrites the first one, if they only differ in amount. */ - if (count == 0){ - zone->mod=mod_dest; - } else { - fluid_mod_t * last_mod=zone->mod; - /* Find the end of the list */ - while (last_mod->next != NULL){ - last_mod=last_mod->next; - } - last_mod->next=mod_dest; - } - - r = fluid_list_next(r); - } /* foreach modulator */ - return FLUID_OK; -} + zone->next = NULL; + zone->name = FLUID_STRDUP(name); -/* - * fluid_inst_zone_get_sample - */ -fluid_sample_t* -fluid_inst_zone_get_sample(fluid_inst_zone_t* zone) -{ - return zone->sample; -} + if(zone->name == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_FREE(zone); + return NULL; + } -/* - * fluid_inst_zone_inside_range - */ -int -fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel) -{ - return ((zone->keylo <= key) && - (zone->keyhi >= key) && - (zone->vello <= vel) && - (zone->velhi >= vel)); + zone->sample = NULL; + zone->range.keylo = 0; + zone->range.keyhi = 128; + zone->range.vello = 0; + zone->range.velhi = 128; + zone->range.ignore = FALSE; + /* Flag the generators as unused. + * This also sets the generator values to default, but they will be overwritten anyway, if used.*/ + fluid_gen_set_default_values(&zone->gen[0]); + zone->mod = NULL; /* list of modulators */ + return zone; } -/*************************************************************** - * - * SAMPLE - */ - /* - * new_fluid_sample + * delete_fluid_inst_zone */ -fluid_sample_t* -new_fluid_sample() +void +delete_fluid_inst_zone(fluid_inst_zone_t *zone) { - fluid_sample_t* sample = NULL; + fluid_mod_t *mod, *tmp; - sample = FLUID_NEW(fluid_sample_t); - if (sample == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return NULL; - } + fluid_return_if_fail(zone != NULL); - memset(sample, 0, sizeof(fluid_sample_t)); - sample->valid = 1; + mod = zone->mod; - return sample; -} + while(mod) /* delete the modulators */ + { + tmp = mod; + mod = mod->next; + delete_fluid_mod(tmp); + } -/* - * delete_fluid_sample - */ -int -delete_fluid_sample(fluid_sample_t* sample) -{ - FLUID_FREE(sample); - return FLUID_OK; + FLUID_FREE(zone->name); + FLUID_FREE(zone); } /* - * fluid_sample_in_rom + * fluid_inst_zone_next */ -int -fluid_sample_in_rom(fluid_sample_t* sample) +fluid_inst_zone_t * +fluid_inst_zone_next(fluid_inst_zone_t *zone) { - return (sample->sampletype & FLUID_SAMPLETYPE_ROM); + return zone->next; } /* - * fluid_sample_import_sfont + * fluid_inst_zone_import_sfont */ int -fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont) +fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont) { - FLUID_STRCPY(sample->name, sfsample->name); - sample->data = sfont->sampledata; - sample->start = sfsample->start; - sample->end = sfsample->start + sfsample->end; - sample->loopstart = sfsample->start + sfsample->loopstart; - sample->loopend = sfsample->start + sfsample->loopend; - sample->samplerate = sfsample->samplerate; - sample->origpitch = sfsample->origpitch; - sample->pitchadj = sfsample->pitchadj; - sample->sampletype = sfsample->sampletype; - - if (sample->sampletype & FLUID_SAMPLETYPE_ROM) { - sample->valid = 0; - FLUID_LOG(FLUID_WARN, "Ignoring sample %s: can't use ROM samples", sample->name); - } - if (sample->end - sample->start < 8) { - sample->valid = 0; - FLUID_LOG(FLUID_WARN, "Ignoring sample %s: too few sample data points", sample->name); - } else { -/* if (sample->loopstart < sample->start + 8) { */ -/* FLUID_LOG(FLUID_WARN, "Fixing sample %s: at least 8 data points required before loop start", sample->name); */ -/* sample->loopstart = sample->start + 8; */ -/* } */ -/* if (sample->loopend > sample->end - 8) { */ -/* FLUID_LOG(FLUID_WARN, "Fixing sample %s: at least 8 data points required after loop end", sample->name); */ -/* sample->loopend = sample->end - 8; */ -/* } */ - } - return FLUID_OK; -} - + fluid_list_t *r; + SFGen *sfgen; + int count; + for(count = 0, r = sfzone->gen; r != NULL; count++) + { + sfgen = (SFGen *)fluid_list_get(r); + + switch(sfgen->id) + { + case GEN_KEYRANGE: + inst_zone->range.keylo = sfgen->amount.range.lo; + inst_zone->range.keyhi = sfgen->amount.range.hi; + break; + + case GEN_VELRANGE: + inst_zone->range.vello = sfgen->amount.range.lo; + inst_zone->range.velhi = sfgen->amount.range.hi; + break; + + case GEN_ATTENUATION: + /* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at + * preset and instrument level */ + inst_zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR; + inst_zone->gen[sfgen->id].flags = GEN_SET; + break; + + default: + /* FIXME: some generators have an unsigned word amount value but + i don't know which ones */ + inst_zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword; + inst_zone->gen[sfgen->id].flags = GEN_SET; + break; + } -/********************************************************************************/ -/********************************************************************************/ -/********************************************************************************/ -/********************************************************************************/ -/********************************************************************************/ + r = fluid_list_next(r); + } + /* FIXME */ + /* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */ + /* FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */ + /* } */ + /* fixup sample pointer */ + if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) + { + inst_zone->sample = ((SFSample *)(sfzone->instsamp->data))->fluid_sample; + } -/*=================================sfload.c======================== - Borrowed from Smurf SoundFont Editor by Josh Green - =================================================================*/ + /* Import the modulators (only SF2.1 and higher) */ + for(count = 0, r = sfzone->mod; r != NULL; count++) + { + SFMod *mod_src = (SFMod *)fluid_list_get(r); + int type; + fluid_mod_t *mod_dest; -/* - functions for loading data from sfont files, with appropriate byte swapping - on big endian machines. Sfont IDs are not swapped because the ID read is - equivalent to the matching ID list in memory regardless of LE/BE machine -*/ - -#if FLUID_IS_BIG_ENDIAN - -#define READCHUNK(var,fd) G_STMT_START { \ - if (!safe_fread(var, 8, fd)) \ - return(FAIL); \ - ((SFChunk *)(var))->size = GUINT32_FROM_LE(((SFChunk *)(var))->size); \ -} G_STMT_END - -#define READD(var,fd) G_STMT_START { \ - unsigned int _temp; \ - if (!safe_fread(&_temp, 4, fd)) \ - return(FAIL); \ - var = GINT32_FROM_LE(_temp); \ -} G_STMT_END - -#define READW(var,fd) G_STMT_START { \ - unsigned short _temp; \ - if (!safe_fread(&_temp, 2, fd)) \ - return(FAIL); \ - var = GINT16_FROM_LE(_temp); \ -} G_STMT_END - -#else - -#define READCHUNK(var,fd) G_STMT_START { \ - if (!safe_fread(var, 8, fd)) \ - return(FAIL); \ - ((SFChunk *)(var))->size = GUINT32_FROM_LE(((SFChunk *)(var))->size); \ -} G_STMT_END - -#define READD(var,fd) G_STMT_START { \ - unsigned int _temp; \ - if (!safe_fread(&_temp, 4, fd)) \ - return(FAIL); \ - var = GINT32_FROM_LE(_temp); \ -} G_STMT_END - -#define READW(var,fd) G_STMT_START { \ - unsigned short _temp; \ - if (!safe_fread(&_temp, 2, fd)) \ - return(FAIL); \ - var = GINT16_FROM_LE(_temp); \ -} G_STMT_END - -#endif - - -#define READID(var,fd) G_STMT_START { \ - if (!safe_fread(var, 4, fd)) \ - return(FAIL); \ -} G_STMT_END - -#define READSTR(var,fd) G_STMT_START { \ - if (!safe_fread(var, 20, fd)) \ - return(FAIL); \ - (*var)[20] = '\0'; \ -} G_STMT_END - -#define READB(var,fd) G_STMT_START { \ - if (!safe_fread(&var, 1, fd)) \ - return(FAIL); \ -} G_STMT_END - -#define FSKIP(size,fd) G_STMT_START { \ - if (!safe_fseek(fd, size, SEEK_CUR)) \ - return(FAIL); \ -} G_STMT_END - -#define FSKIPW(fd) G_STMT_START { \ - if (!safe_fseek(fd, 2, SEEK_CUR)) \ - return(FAIL); \ -} G_STMT_END - -/* removes and advances a fluid_list_t pointer */ -#define SLADVREM(list, item) G_STMT_START { \ - fluid_list_t *_temp = item; \ - item = fluid_list_next(item); \ - list = fluid_list_remove_link(list, _temp); \ - delete1_fluid_list(_temp); \ -} G_STMT_END - -static int chunkid (unsigned int id); -static int load_body (unsigned int size, SFData * sf, FILE * fd); -static int read_listchunk (SFChunk * chunk, FILE * fd); -static int process_info (int size, SFData * sf, FILE * fd); -static int process_sdta (unsigned int size, SFData * sf, FILE * fd); -static int pdtahelper (unsigned int expid, unsigned int reclen, SFChunk * chunk, - int * size, FILE * fd); -static int process_pdta (int size, SFData * sf, FILE * fd); -static int load_phdr (int size, SFData * sf, FILE * fd); -static int load_pbag (int size, SFData * sf, FILE * fd); -static int load_pmod (int size, SFData * sf, FILE * fd); -static int load_pgen (int size, SFData * sf, FILE * fd); -static int load_ihdr (int size, SFData * sf, FILE * fd); -static int load_ibag (int size, SFData * sf, FILE * fd); -static int load_imod (int size, SFData * sf, FILE * fd); -static int load_igen (int size, SFData * sf, FILE * fd); -static int load_shdr (unsigned int size, SFData * sf, FILE * fd); -static int fixup_pgen (SFData * sf); -static int fixup_igen (SFData * sf); -static int fixup_sample (SFData * sf); - -char idlist[] = { - "RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD" - "ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdr" -}; - -static unsigned int sdtachunk_size; - -/* sound font file load functions */ -static int -chunkid (unsigned int id) -{ - unsigned int i; - unsigned int *p; + mod_dest = new_fluid_mod(); - p = (unsigned int *) & idlist; - for (i = 0; i < sizeof (idlist) / sizeof (int); i++, p += 1) - if (*p == id) - return (i + 1); + if(mod_dest == NULL) + { + return FLUID_FAILED; + } - return (UNKN_ID); -} + mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/ -SFData * -sfload_file (const char * fname) -{ - SFData *sf = NULL; - FILE *fd; - int fsize = 0; - int err = FALSE; + /* *** Amount *** */ + mod_dest->amount = mod_src->amount; - if (!(fd = fopen (fname, "rb"))) - { - FLUID_LOG (FLUID_ERR, _("Unable to open file \"%s\""), fname); - return (NULL); - } + /* *** Source *** */ + mod_dest->src1 = mod_src->src & 127; /* index of source 1, seven-bit value, SF2.01 section 8.2, page 50 */ + mod_dest->flags1 = 0; - if (!(sf = FLUID_NEW (SFData))) - { - FLUID_LOG(FLUID_ERR, "Out of memory"); - fclose(fd); - err = TRUE; - } + /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ + if(mod_src->src & (1 << 7)) + { + mod_dest->flags1 |= FLUID_MOD_CC; + } + else + { + mod_dest->flags1 |= FLUID_MOD_GC; + } - if (!err) - { - memset (sf, 0, sizeof (SFData)); /* zero sfdata */ - sf->fname = FLUID_STRDUP (fname); /* copy file name */ - sf->sffd = fd; - } + /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ + if(mod_src->src & (1 << 8)) + { + mod_dest->flags1 |= FLUID_MOD_NEGATIVE; + } + else + { + mod_dest->flags1 |= FLUID_MOD_POSITIVE; + } - /* get size of file */ - if (!err && fseek (fd, 0L, SEEK_END) == -1) - { /* seek to end of file */ - err = TRUE; - FLUID_LOG (FLUID_ERR, _("Seek to end of file failed")); - } - if (!err && (fsize = ftell (fd)) == -1) - { /* position = size */ - err = TRUE; - FLUID_LOG (FLUID_ERR, _("Get end of file position failed")); - } - if (!err) - rewind (fd); + /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ + if(mod_src->src & (1 << 9)) + { + mod_dest->flags1 |= FLUID_MOD_BIPOLAR; + } + else + { + mod_dest->flags1 |= FLUID_MOD_UNIPOLAR; + } - if (!err && !load_body (fsize, sf, fd)) - err = TRUE; /* load the sfont */ + /* modulator source types: SF2.01 section 8.2.1 page 52 */ + type = (mod_src->src) >> 10; + type &= 63; /* type is a 6-bit value */ - if (err) - { - if (sf) - sfont_close (sf); - return (NULL); - } + if(type == 0) + { + mod_dest->flags1 |= FLUID_MOD_LINEAR; + } + else if(type == 1) + { + mod_dest->flags1 |= FLUID_MOD_CONCAVE; + } + else if(type == 2) + { + mod_dest->flags1 |= FLUID_MOD_CONVEX; + } + else if(type == 3) + { + mod_dest->flags1 |= FLUID_MOD_SWITCH; + } + else + { + /* This shouldn't happen - unknown type! + * Deactivate the modulator by setting the amount to 0. */ + mod_dest->amount = 0; + } - return (sf); -} + /* *** Dest *** */ + mod_dest->dest = mod_src->dest; /* index of controlled generator */ -static int -load_body (unsigned int size, SFData * sf, FILE * fd) -{ - SFChunk chunk; - - READCHUNK (&chunk, fd); /* load RIFF chunk */ - if (chunkid (chunk.id) != RIFF_ID) { /* error if not RIFF */ - FLUID_LOG (FLUID_ERR, _("Not a RIFF file")); - return (FAIL); - } - - READID (&chunk.id, fd); /* load file ID */ - if (chunkid (chunk.id) != SFBK_ID) { /* error if not SFBK_ID */ - FLUID_LOG (FLUID_ERR, _("Not a SoundFont file")); - return (FAIL); - } - - if (chunk.size != size - 8) { - gerr (ErrCorr, _("SoundFont file size mismatch")); - return (FAIL); - } - - /* Process INFO block */ - if (!read_listchunk (&chunk, fd)) - return (FAIL); - if (chunkid (chunk.id) != INFO_ID) - return (gerr (ErrCorr, _("Invalid ID found when expecting INFO chunk"))); - if (!process_info (chunk.size, sf, fd)) - return (FAIL); - - /* Process sample chunk */ - if (!read_listchunk (&chunk, fd)) - return (FAIL); - if (chunkid (chunk.id) != SDTA_ID) - return (gerr (ErrCorr, - _("Invalid ID found when expecting SAMPLE chunk"))); - if (!process_sdta (chunk.size, sf, fd)) - return (FAIL); - - /* process HYDRA chunk */ - if (!read_listchunk (&chunk, fd)) - return (FAIL); - if (chunkid (chunk.id) != PDTA_ID) - return (gerr (ErrCorr, _("Invalid ID found when expecting HYDRA chunk"))); - if (!process_pdta (chunk.size, sf, fd)) - return (FAIL); - - if (!fixup_pgen (sf)) - return (FAIL); - if (!fixup_igen (sf)) - return (FAIL); - if (!fixup_sample (sf)) - return (FAIL); - - /* sort preset list by bank, preset # */ - sf->preset = fluid_list_sort (sf->preset, - (fluid_compare_func_t) sfont_preset_compare_func); - - return (OK); -} + /* *** Amount source *** */ + mod_dest->src2 = mod_src->amtsrc & 127; /* index of source 2, seven-bit value, SF2.01 section 8.2, page 50 */ + mod_dest->flags2 = 0; -static int -read_listchunk (SFChunk * chunk, FILE * fd) -{ - READCHUNK (chunk, fd); /* read list chunk */ - if (chunkid (chunk->id) != LIST_ID) /* error if ! list chunk */ - return (gerr (ErrCorr, _("Invalid chunk id in level 0 parse"))); - READID (&chunk->id, fd); /* read id string */ - chunk->size -= 4; - return (OK); -} + /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ + if(mod_src->amtsrc & (1 << 7)) + { + mod_dest->flags2 |= FLUID_MOD_CC; + } + else + { + mod_dest->flags2 |= FLUID_MOD_GC; + } -static int -process_info (int size, SFData * sf, FILE * fd) -{ - SFChunk chunk; - unsigned char id; - char *item; - unsigned short ver; - - while (size > 0) - { - READCHUNK (&chunk, fd); - size -= 8; - - id = chunkid (chunk.id); - - if (id == IFIL_ID) - { /* sound font version chunk? */ - if (chunk.size != 4) - return (gerr (ErrCorr, - _("Sound font version info chunk has invalid size"))); - - READW (ver, fd); - sf->version.major = ver; - READW (ver, fd); - sf->version.minor = ver; - - if (sf->version.major < 2) { - FLUID_LOG (FLUID_ERR, - _("Sound font version is %d.%d which is not" - " supported, convert to version 2.0x"), - sf->version.major, - sf->version.minor); - return (FAIL); - } - - if (sf->version.major > 2) { - FLUID_LOG (FLUID_WARN, - _("Sound font version is %d.%d which is newer than" - " what this version of FLUID Synth was designed for (v2.0x)"), - sf->version.major, - sf->version.minor); - return (FAIL); - } - } - else if (id == IVER_ID) - { /* ROM version chunk? */ - if (chunk.size != 4) - return (gerr (ErrCorr, - _("ROM version info chunk has invalid size"))); - - READW (ver, fd); - sf->romver.major = ver; - READW (ver, fd); - sf->romver.minor = ver; - } - else if (id != UNKN_ID) - { - if ((id != ICMT_ID && chunk.size > 256) || (chunk.size > 65536) - || (chunk.size % 2)) - return (gerr (ErrCorr, - _("INFO sub chunk %.4s has invalid chunk size" - " of %d bytes"), &chunk.id, chunk.size)); - - /* alloc for chunk id and da chunk */ - if (!(item = FLUID_MALLOC (chunk.size + 1))) - { - FLUID_LOG(FLUID_ERR, "Out of memory"); - return (FAIL); - } - - /* attach to INFO list, sfont_close will cleanup if FAIL occurs */ - sf->info = fluid_list_append (sf->info, item); - - *(unsigned char *) item = id; - if (!safe_fread (&item[1], chunk.size, fd)) - return (FAIL); - - /* force terminate info item (don't forget uint8 info ID) */ - *(item + chunk.size) = '\0'; - } - else - return (gerr (ErrCorr, _("Invalid chunk id in INFO chunk"))); - size -= chunk.size; - } - - if (size < 0) - return (gerr (ErrCorr, _("INFO chunk size mismatch"))); - - return (OK); -} + /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ + if(mod_src->amtsrc & (1 << 8)) + { + mod_dest->flags2 |= FLUID_MOD_NEGATIVE; + } + else + { + mod_dest->flags2 |= FLUID_MOD_POSITIVE; + } -static int -process_sdta (unsigned int size, SFData * sf, FILE * fd) -{ - SFChunk chunk; + /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ + if(mod_src->amtsrc & (1 << 9)) + { + mod_dest->flags2 |= FLUID_MOD_BIPOLAR; + } + else + { + mod_dest->flags2 |= FLUID_MOD_UNIPOLAR; + } - if (size == 0) - return (OK); /* no sample data? */ + /* modulator source types: SF2.01 section 8.2.1 page 52 */ + type = (mod_src->amtsrc) >> 10; + type &= 63; /* type is a 6-bit value */ - /* read sub chunk */ - READCHUNK (&chunk, fd); - size -= 8; + if(type == 0) + { + mod_dest->flags2 |= FLUID_MOD_LINEAR; + } + else if(type == 1) + { + mod_dest->flags2 |= FLUID_MOD_CONCAVE; + } + else if(type == 2) + { + mod_dest->flags2 |= FLUID_MOD_CONVEX; + } + else if(type == 3) + { + mod_dest->flags2 |= FLUID_MOD_SWITCH; + } + else + { + /* This shouldn't happen - unknown type! + * Deactivate the modulator by setting the amount to 0. */ + mod_dest->amount = 0; + } - if (chunkid (chunk.id) != SMPL_ID) - return (gerr (ErrCorr, - _("Expected SMPL chunk found invalid id instead"))); + /* *** Transform *** */ + /* SF2.01 only uses the 'linear' transform (0). + * Deactivate the modulator by setting the amount to 0 in any other case. + */ + if(mod_src->trans != 0) + { + mod_dest->amount = 0; + } - /* SDTA chunk may also contain sm24 chunk for 24 bit samples - * (not yet supported), only an error if SMPL chunk size is - * greater than SDTA. */ - if (chunk.size > size) - return (gerr (ErrCorr, _("SDTA chunk size mismatch"))); + /* Store the new modulator in the zone + * The order of modulators will make a difference, at least in an instrument context: + * The second modulator overwrites the first one, if they only differ in amount. */ + if(count == 0) + { + inst_zone->mod = mod_dest; + } + else + { + fluid_mod_t *last_mod = inst_zone->mod; - /* sample data follows */ - sf->samplepos = ftell (fd); + /* Find the end of the list */ + while(last_mod->next != NULL) + { + last_mod = last_mod->next; + } - /* used in fixup_sample() to check validity of sample headers */ - sdtachunk_size = chunk.size; - sf->samplesize = chunk.size; + last_mod->next = mod_dest; + } - FSKIP (size, fd); + r = fluid_list_next(r); + } /* foreach modulator */ - return (OK); + return FLUID_OK; } -static int -pdtahelper (unsigned int expid, unsigned int reclen, SFChunk * chunk, - int * size, FILE * fd) +/* + * fluid_inst_zone_get_sample + */ +fluid_sample_t * +fluid_inst_zone_get_sample(fluid_inst_zone_t *zone) { - unsigned int id; - char *expstr; - - expstr = CHNKIDSTR (expid); /* in case we need it */ - - READCHUNK (chunk, fd); - *size -= 8; - - if ((id = chunkid (chunk->id)) != expid) - return (gerr (ErrCorr, _("Expected" - " PDTA sub-chunk \"%.4s\" found invalid id instead"), expstr)); - - if (chunk->size % reclen) /* valid chunk size? */ - return (gerr (ErrCorr, - _("\"%.4s\" chunk size is not a multiple of %d bytes"), expstr, - reclen)); - if ((*size -= chunk->size) < 0) - return (gerr (ErrCorr, - _("\"%.4s\" chunk size exceeds remaining PDTA chunk size"), expstr)); - return (OK); + return zone->sample; } -static int -process_pdta (int size, SFData * sf, FILE * fd) -{ - SFChunk chunk; - - if (!pdtahelper (PHDR_ID, SFPHDRSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_phdr (chunk.size, sf, fd)) - return (FAIL); - - if (!pdtahelper (PBAG_ID, SFBAGSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_pbag (chunk.size, sf, fd)) - return (FAIL); - - if (!pdtahelper (PMOD_ID, SFMODSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_pmod (chunk.size, sf, fd)) - return (FAIL); - - if (!pdtahelper (PGEN_ID, SFGENSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_pgen (chunk.size, sf, fd)) - return (FAIL); - - if (!pdtahelper (IHDR_ID, SFIHDRSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_ihdr (chunk.size, sf, fd)) - return (FAIL); - - if (!pdtahelper (IBAG_ID, SFBAGSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_ibag (chunk.size, sf, fd)) - return (FAIL); - - if (!pdtahelper (IMOD_ID, SFMODSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_imod (chunk.size, sf, fd)) - return (FAIL); - - if (!pdtahelper (IGEN_ID, SFGENSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_igen (chunk.size, sf, fd)) - return (FAIL); - - if (!pdtahelper (SHDR_ID, SFSHDRSIZE, &chunk, &size, fd)) - return (FAIL); - if (!load_shdr (chunk.size, sf, fd)) - return (FAIL); - - return (OK); -} -/* preset header loader */ -static int -load_phdr (int size, SFData * sf, FILE * fd) +int +fluid_zone_inside_range(fluid_zone_range_t *range, int key, int vel) { - int i, i2; - SFPreset *p, *pr = NULL; /* ptr to current & previous preset */ - unsigned short zndx, pzndx = 0; - - if (size % SFPHDRSIZE || size == 0) - return (gerr (ErrCorr, _("Preset header chunk size is invalid"))); - - i = size / SFPHDRSIZE - 1; - if (i == 0) - { /* at least one preset + term record */ - FLUID_LOG (FLUID_WARN, _("File contains no presets")); - FSKIP (SFPHDRSIZE, fd); - return (OK); - } - - for (; i > 0; i--) - { /* load all preset headers */ - p = FLUID_NEW (SFPreset); - sf->preset = fluid_list_append (sf->preset, p); - p->zone = NULL; /* In case of failure, sfont_close can cleanup */ - READSTR (&p->name, fd); /* possible read failure ^ */ - READW (p->prenum, fd); - READW (p->bank, fd); - READW (zndx, fd); - READD (p->libr, fd); - READD (p->genre, fd); - READD (p->morph, fd); - - if (pr) - { /* not first preset? */ - if (zndx < pzndx) - return (gerr (ErrCorr, _("Preset header indices not monotonic"))); - i2 = zndx - pzndx; - while (i2--) - { - pr->zone = fluid_list_prepend (pr->zone, NULL); - } - } - else if (zndx > 0) /* 1st preset, warn if ofs >0 */ - FLUID_LOG (FLUID_WARN, _("%d preset zones not referenced, discarding"), zndx); - pr = p; /* update preset ptr */ - pzndx = zndx; - } - - FSKIP (24, fd); - READW (zndx, fd); /* Read terminal generator index */ - FSKIP (12, fd); - - if (zndx < pzndx) - return (gerr (ErrCorr, _("Preset header indices not monotonic"))); - i2 = zndx - pzndx; - while (i2--) - { - pr->zone = fluid_list_prepend (pr->zone, NULL); - } - - return (OK); -} + /* ignoreInstrumentZone is set in mono legato playing */ + int ignore_zone = range->ignore; -/* preset bag loader */ -static int -load_pbag (int size, SFData * sf, FILE * fd) -{ - fluid_list_t *p, *p2; - SFZone *z, *pz = NULL; - unsigned short genndx, modndx; - unsigned short pgenndx = 0, pmodndx = 0; - unsigned short i; - - if (size % SFBAGSIZE || size == 0) /* size is multiple of SFBAGSIZE? */ - return (gerr (ErrCorr, _("Preset bag chunk size is invalid"))); - - p = sf->preset; - while (p) - { /* traverse through presets */ - p2 = ((SFPreset *) (p->data))->zone; - while (p2) - { /* traverse preset's zones */ - if ((size -= SFBAGSIZE) < 0) - return (gerr (ErrCorr, _("Preset bag chunk size mismatch"))); - z = FLUID_NEW (SFZone); - p2->data = z; - z->gen = NULL; /* Init gen and mod before possible failure, */ - z->mod = NULL; /* to ensure proper cleanup (sfont_close) */ - READW (genndx, fd); /* possible read failure ^ */ - READW (modndx, fd); - z->instsamp = NULL; - - if (pz) - { /* if not first zone */ - if (genndx < pgenndx) - return (gerr (ErrCorr, - _("Preset bag generator indices not monotonic"))); - if (modndx < pmodndx) - return (gerr (ErrCorr, - _("Preset bag modulator indices not monotonic"))); - i = genndx - pgenndx; - while (i--) - pz->gen = fluid_list_prepend (pz->gen, NULL); - i = modndx - pmodndx; - while (i--) - pz->mod = fluid_list_prepend (pz->mod, NULL); - } - pz = z; /* update previous zone ptr */ - pgenndx = genndx; /* update previous zone gen index */ - pmodndx = modndx; /* update previous zone mod index */ - p2 = fluid_list_next (p2); - } - p = fluid_list_next (p); - } - - size -= SFBAGSIZE; - if (size != 0) - return (gerr (ErrCorr, _("Preset bag chunk size mismatch"))); - - READW (genndx, fd); - READW (modndx, fd); - - if (!pz) - { - if (genndx > 0) - FLUID_LOG (FLUID_WARN, _("No preset generators and terminal index not 0")); - if (modndx > 0) - FLUID_LOG (FLUID_WARN, _("No preset modulators and terminal index not 0")); - return (OK); - } - - if (genndx < pgenndx) - return (gerr (ErrCorr, _("Preset bag generator indices not monotonic"))); - if (modndx < pmodndx) - return (gerr (ErrCorr, _("Preset bag modulator indices not monotonic"))); - i = genndx - pgenndx; - while (i--) - pz->gen = fluid_list_prepend (pz->gen, NULL); - i = modndx - pmodndx; - while (i--) - pz->mod = fluid_list_prepend (pz->mod, NULL); - - return (OK); -} + /* Reset the 'ignore' request */ + range->ignore = FALSE; -/* preset modulator loader */ -static int -load_pmod (int size, SFData * sf, FILE * fd) -{ - fluid_list_t *p, *p2, *p3; - SFMod *m; - - p = sf->preset; - while (p) - { /* traverse through all presets */ - p2 = ((SFPreset *) (p->data))->zone; - while (p2) - { /* traverse this preset's zones */ - p3 = ((SFZone *) (p2->data))->mod; - while (p3) - { /* load zone's modulators */ - if ((size -= SFMODSIZE) < 0) - return (gerr (ErrCorr, - _("Preset modulator chunk size mismatch"))); - m = FLUID_NEW (SFMod); - p3->data = m; - READW (m->src, fd); - READW (m->dest, fd); - READW (m->amount, fd); - READW (m->amtsrc, fd); - READW (m->trans, fd); - p3 = fluid_list_next (p3); - } - p2 = fluid_list_next (p2); - } - p = fluid_list_next (p); - } - - /* - If there isn't even a terminal record - Hmmm, the specs say there should be one, but.. - */ - if (size == 0) - return (OK); - - size -= SFMODSIZE; - if (size != 0) - return (gerr (ErrCorr, _("Preset modulator chunk size mismatch"))); - FSKIP (SFMODSIZE, fd); /* terminal mod */ - - return (OK); + return !ignore_zone && ((range->keylo <= key) && + (range->keyhi >= key) && + (range->vello <= vel) && + (range->velhi >= vel)); } -/* ------------------------------------------------------------------- - * preset generator loader - * generator (per preset) loading rules: - * Zones with no generators or modulators shall be annihilated - * Global zone must be 1st zone, discard additional ones (instrumentless zones) +/*************************************************************** * - * generator (per zone) loading rules (in order of decreasing precedence): - * KeyRange is 1st in list (if exists), else discard - * if a VelRange exists only preceded by a KeyRange, else discard - * if a generator follows an instrument discard it - * if a duplicate generator exists replace previous one - * ------------------------------------------------------------------- */ -static int -load_pgen (int size, SFData * sf, FILE * fd) -{ - fluid_list_t *p, *p2, *p3, *dup, **hz = NULL; - SFZone *z; - SFGen *g; - SFGenAmount genval; - unsigned short genid; - int level, skip, drop, gzone, discarded; - - p = sf->preset; - while (p) - { /* traverse through all presets */ - gzone = FALSE; - discarded = FALSE; - p2 = ((SFPreset *) (p->data))->zone; - if (p2) - hz = &p2; - while (p2) - { /* traverse preset's zones */ - level = 0; - z = (SFZone *) (p2->data); - p3 = z->gen; - while (p3) - { /* load zone's generators */ - dup = NULL; - skip = FALSE; - drop = FALSE; - if ((size -= SFGENSIZE) < 0) - return (gerr (ErrCorr, - _("Preset generator chunk size mismatch"))); - - READW (genid, fd); - - if (genid == Gen_KeyRange) - { /* nothing precedes */ - if (level == 0) - { - level = 1; - READB (genval.range.lo, fd); - READB (genval.range.hi, fd); - } - else - skip = TRUE; - } - else if (genid == Gen_VelRange) - { /* only KeyRange precedes */ - if (level <= 1) - { - level = 2; - READB (genval.range.lo, fd); - READB (genval.range.hi, fd); - } - else - skip = TRUE; - } - else if (genid == Gen_Instrument) - { /* inst is last gen */ - level = 3; - READW (genval.uword, fd); - ((SFZone *) (p2->data))->instsamp = GINT_TO_POINTER (genval.uword + 1); - break; /* break out of generator loop */ - } - else - { - level = 2; - if (gen_validp (genid)) - { /* generator valid? */ - READW (genval.sword, fd); - dup = gen_inlist (genid, z->gen); - } - else - skip = TRUE; - } - - if (!skip) - { - if (!dup) - { /* if gen ! dup alloc new */ - g = FLUID_NEW (SFGen); - p3->data = g; - g->id = genid; - } - else - { - g = (SFGen *) (dup->data); /* ptr to orig gen */ - drop = TRUE; - } - g->amount = genval; - } - else - { /* Skip this generator */ - discarded = TRUE; - drop = TRUE; - FSKIPW (fd); - } - - if (!drop) - p3 = fluid_list_next (p3); /* next gen */ - else - SLADVREM (z->gen, p3); /* drop place holder */ - - } /* generator loop */ - - if (level == 3) - SLADVREM (z->gen, p3); /* zone has inst? */ - else - { /* congratulations its a global zone */ - if (!gzone) - { /* Prior global zones? */ - gzone = TRUE; - - /* if global zone is not 1st zone, relocate */ - if (*hz != p2) - { - void* save = p2->data; - FLUID_LOG (FLUID_WARN, - _("Preset \"%s\": Global zone is not first zone"), - ((SFPreset *) (p->data))->name); - SLADVREM (*hz, p2); - *hz = fluid_list_prepend (*hz, save); - continue; - } - } - else - { /* previous global zone exists, discard */ - FLUID_LOG (FLUID_WARN, - _("Preset \"%s\": Discarding invalid global zone"), - ((SFPreset *) (p->data))->name); - sfont_zone_delete (sf, hz, (SFZone *) (p2->data)); - } - } - - while (p3) - { /* Kill any zones following an instrument */ - discarded = TRUE; - if ((size -= SFGENSIZE) < 0) - return (gerr (ErrCorr, - _("Preset generator chunk size mismatch"))); - FSKIP (SFGENSIZE, fd); - SLADVREM (z->gen, p3); - } - - p2 = fluid_list_next (p2); /* next zone */ - } - if (discarded) - FLUID_LOG(FLUID_WARN, - _("Preset \"%s\": Some invalid generators were discarded"), - ((SFPreset *) (p->data))->name); - p = fluid_list_next (p); - } - - /* in case there isn't a terminal record */ - if (size == 0) - return (OK); - - size -= SFGENSIZE; - if (size != 0) - return (gerr (ErrCorr, _("Preset generator chunk size mismatch"))); - FSKIP (SFGENSIZE, fd); /* terminal gen */ - - return (OK); -} - -/* instrument header loader */ -static int -load_ihdr (int size, SFData * sf, FILE * fd) -{ - int i, i2; - SFInst *p, *pr = NULL; /* ptr to current & previous instrument */ - unsigned short zndx, pzndx = 0; - - if (size % SFIHDRSIZE || size == 0) /* chunk size is valid? */ - return (gerr (ErrCorr, _("Instrument header has invalid size"))); - - size = size / SFIHDRSIZE - 1; - if (size == 0) - { /* at least one preset + term record */ - FLUID_LOG (FLUID_WARN, _("File contains no instruments")); - FSKIP (SFIHDRSIZE, fd); - return (OK); - } - - for (i = 0; i < size; i++) - { /* load all instrument headers */ - p = FLUID_NEW (SFInst); - sf->inst = fluid_list_append (sf->inst, p); - p->zone = NULL; /* For proper cleanup if fail (sfont_close) */ - READSTR (&p->name, fd); /* Possible read failure ^ */ - READW (zndx, fd); - - if (pr) - { /* not first instrument? */ - if (zndx < pzndx) - return (gerr (ErrCorr, - _("Instrument header indices not monotonic"))); - i2 = zndx - pzndx; - while (i2--) - pr->zone = fluid_list_prepend (pr->zone, NULL); - } - else if (zndx > 0) /* 1st inst, warn if ofs >0 */ - FLUID_LOG (FLUID_WARN, _("%d instrument zones not referenced, discarding"), - zndx); - pzndx = zndx; - pr = p; /* update instrument ptr */ - } - - FSKIP (20, fd); - READW (zndx, fd); - - if (zndx < pzndx) - return (gerr (ErrCorr, _("Instrument header indices not monotonic"))); - i2 = zndx - pzndx; - while (i2--) - pr->zone = fluid_list_prepend (pr->zone, NULL); - - return (OK); -} + * SAMPLE + */ -/* instrument bag loader */ -static int -load_ibag (int size, SFData * sf, FILE * fd) +/* + * fluid_sample_in_rom + */ +int +fluid_sample_in_rom(fluid_sample_t *sample) { - fluid_list_t *p, *p2; - SFZone *z, *pz = NULL; - unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0; - int i; - - if (size % SFBAGSIZE || size == 0) /* size is multiple of SFBAGSIZE? */ - return (gerr (ErrCorr, _("Instrument bag chunk size is invalid"))); - - p = sf->inst; - while (p) - { /* traverse through inst */ - p2 = ((SFInst *) (p->data))->zone; - while (p2) - { /* load this inst's zones */ - if ((size -= SFBAGSIZE) < 0) - return (gerr (ErrCorr, _("Instrument bag chunk size mismatch"))); - z = FLUID_NEW (SFZone); - p2->data = z; - z->gen = NULL; /* In case of failure, */ - z->mod = NULL; /* sfont_close can clean up */ - READW (genndx, fd); /* READW = possible read failure */ - READW (modndx, fd); - z->instsamp = NULL; - - if (pz) - { /* if not first zone */ - if (genndx < pgenndx) - return (gerr (ErrCorr, - _("Instrument generator indices not monotonic"))); - if (modndx < pmodndx) - return (gerr (ErrCorr, - _("Instrument modulator indices not monotonic"))); - i = genndx - pgenndx; - while (i--) - pz->gen = fluid_list_prepend (pz->gen, NULL); - i = modndx - pmodndx; - while (i--) - pz->mod = fluid_list_prepend (pz->mod, NULL); - } - pz = z; /* update previous zone ptr */ - pgenndx = genndx; - pmodndx = modndx; - p2 = fluid_list_next (p2); - } - p = fluid_list_next (p); - } - - size -= SFBAGSIZE; - if (size != 0) - return (gerr (ErrCorr, _("Instrument chunk size mismatch"))); - - READW (genndx, fd); - READW (modndx, fd); - - if (!pz) - { /* in case that all are no zoners */ - if (genndx > 0) - FLUID_LOG (FLUID_WARN, - _("No instrument generators and terminal index not 0")); - if (modndx > 0) - FLUID_LOG (FLUID_WARN, - _("No instrument modulators and terminal index not 0")); - return (OK); - } - - if (genndx < pgenndx) - return (gerr (ErrCorr, _("Instrument generator indices not monotonic"))); - if (modndx < pmodndx) - return (gerr (ErrCorr, _("Instrument modulator indices not monotonic"))); - i = genndx - pgenndx; - while (i--) - pz->gen = fluid_list_prepend (pz->gen, NULL); - i = modndx - pmodndx; - while (i--) - pz->mod = fluid_list_prepend (pz->mod, NULL); - - return (OK); + return (sample->sampletype & FLUID_SAMPLETYPE_ROM); } -/* instrument modulator loader */ -static int -load_imod (int size, SFData * sf, FILE * fd) -{ - fluid_list_t *p, *p2, *p3; - SFMod *m; - - p = sf->inst; - while (p) - { /* traverse through all inst */ - p2 = ((SFInst *) (p->data))->zone; - while (p2) - { /* traverse this inst's zones */ - p3 = ((SFZone *) (p2->data))->mod; - while (p3) - { /* load zone's modulators */ - if ((size -= SFMODSIZE) < 0) - return (gerr (ErrCorr, - _("Instrument modulator chunk size mismatch"))); - m = FLUID_NEW (SFMod); - p3->data = m; - READW (m->src, fd); - READW (m->dest, fd); - READW (m->amount, fd); - READW (m->amtsrc, fd); - READW (m->trans, fd); - p3 = fluid_list_next (p3); - } - p2 = fluid_list_next (p2); - } - p = fluid_list_next (p); - } - - /* - If there isn't even a terminal record - Hmmm, the specs say there should be one, but.. - */ - if (size == 0) - return (OK); - - size -= SFMODSIZE; - if (size != 0) - return (gerr (ErrCorr, _("Instrument modulator chunk size mismatch"))); - FSKIP (SFMODSIZE, fd); /* terminal mod */ - - return (OK); -} -/* load instrument generators (see load_pgen for loading rules) */ -static int -load_igen (int size, SFData * sf, FILE * fd) +/* + * fluid_sample_import_sfont + */ +int +fluid_sample_import_sfont(fluid_sample_t *sample, SFSample *sfsample, fluid_defsfont_t *defsfont) { - fluid_list_t *p, *p2, *p3, *dup, **hz = NULL; - SFZone *z; - SFGen *g; - SFGenAmount genval; - unsigned short genid; - int level, skip, drop, gzone, discarded; - - p = sf->inst; - while (p) - { /* traverse through all instruments */ - gzone = FALSE; - discarded = FALSE; - p2 = ((SFInst *) (p->data))->zone; - if (p2) - hz = &p2; - while (p2) - { /* traverse this instrument's zones */ - level = 0; - z = (SFZone *) (p2->data); - p3 = z->gen; - while (p3) - { /* load zone's generators */ - dup = NULL; - skip = FALSE; - drop = FALSE; - if ((size -= SFGENSIZE) < 0) - return (gerr (ErrCorr, _("IGEN chunk size mismatch"))); - - READW (genid, fd); - - if (genid == Gen_KeyRange) - { /* nothing precedes */ - if (level == 0) - { - level = 1; - READB (genval.range.lo, fd); - READB (genval.range.hi, fd); - } - else - skip = TRUE; - } - else if (genid == Gen_VelRange) - { /* only KeyRange precedes */ - if (level <= 1) - { - level = 2; - READB (genval.range.lo, fd); - READB (genval.range.hi, fd); - } - else - skip = TRUE; - } - else if (genid == Gen_SampleId) - { /* sample is last gen */ - level = 3; - READW (genval.uword, fd); - ((SFZone *) (p2->data))->instsamp = GINT_TO_POINTER (genval.uword + 1); - break; /* break out of generator loop */ - } - else - { - level = 2; - if (gen_valid (genid)) - { /* gen valid? */ - READW (genval.sword, fd); - dup = gen_inlist (genid, z->gen); - } - else - skip = TRUE; - } - - if (!skip) - { - if (!dup) - { /* if gen ! dup alloc new */ - g = FLUID_NEW (SFGen); - p3->data = g; - g->id = genid; - } - else - { - g = (SFGen *) (dup->data); - drop = TRUE; - } - g->amount = genval; - } - else - { /* skip this generator */ - discarded = TRUE; - drop = TRUE; - FSKIPW (fd); - } - - if (!drop) - p3 = fluid_list_next (p3); /* next gen */ - else - SLADVREM (z->gen, p3); - - } /* generator loop */ - - if (level == 3) - SLADVREM (z->gen, p3); /* zone has sample? */ - else - { /* its a global zone */ - if (!gzone) - { - gzone = TRUE; - - /* if global zone is not 1st zone, relocate */ - if (*hz != p2) - { - void* save = p2->data; - FLUID_LOG (FLUID_WARN, - _("Instrument \"%s\": Global zone is not first zone"), - ((SFPreset *) (p->data))->name); - SLADVREM (*hz, p2); - *hz = fluid_list_prepend (*hz, save); - continue; - } - } - else - { /* previous global zone exists, discard */ - FLUID_LOG (FLUID_WARN, - _("Instrument \"%s\": Discarding invalid global zone"), - ((SFInst *) (p->data))->name); - sfont_zone_delete (sf, hz, (SFZone *) (p2->data)); - } - } - - while (p3) - { /* Kill any zones following a sample */ - discarded = TRUE; - if ((size -= SFGENSIZE) < 0) - return (gerr (ErrCorr, - _("Instrument generator chunk size mismatch"))); - FSKIP (SFGENSIZE, fd); - SLADVREM (z->gen, p3); - } - - p2 = fluid_list_next (p2); /* next zone */ - } - if (discarded) - FLUID_LOG(FLUID_WARN, - _("Instrument \"%s\": Some invalid generators were discarded"), - ((SFInst *) (p->data))->name); - p = fluid_list_next (p); - } - - /* for those non-terminal record cases, grr! */ - if (size == 0) - return (OK); - - size -= SFGENSIZE; - if (size != 0) - return (gerr (ErrCorr, _("IGEN chunk size mismatch"))); - FSKIP (SFGENSIZE, fd); /* terminal gen */ - - return (OK); -} + FLUID_STRCPY(sample->name, sfsample->name); -/* sample header loader */ -static int -load_shdr (unsigned int size, SFData * sf, FILE * fd) -{ - unsigned int i; - SFSample *p; + sample->source_start = sfsample->start; + sample->source_end = (sfsample->end > 0) ? sfsample->end - 1 : 0; /* marks last sample, contrary to SF spec. */ + sample->source_loopstart = sfsample->loopstart; + sample->source_loopend = sfsample->loopend; - if (size % SFSHDRSIZE || size == 0) /* size is multiple of SHDR size? */ - return (gerr (ErrCorr, _("Sample header has invalid size"))); + sample->start = sample->source_start; + sample->end = sample->source_end; + sample->loopstart = sample->source_loopstart; + sample->loopend = sample->source_loopend; + sample->samplerate = sfsample->samplerate; + sample->origpitch = sfsample->origpitch; + sample->pitchadj = sfsample->pitchadj; + sample->sampletype = sfsample->sampletype; - size = size / SFSHDRSIZE - 1; - if (size == 0) - { /* at least one sample + term record? */ - FLUID_LOG (FLUID_WARN, _("File contains no samples")); - FSKIP (SFSHDRSIZE, fd); - return (OK); + if(defsfont->dynamic_samples) + { + sample->notify = dynamic_samples_sample_notify; } - /* load all sample headers */ - for (i = 0; i < size; i++) + if(fluid_sample_validate(sample, defsfont->samplesize) == FLUID_FAILED) { - p = FLUID_NEW (SFSample); - sf->sample = fluid_list_append (sf->sample, p); - READSTR (&p->name, fd); - READD (p->start, fd); - READD (p->end, fd); /* - end, loopstart and loopend */ - READD (p->loopstart, fd); /* - will be checked and turned into */ - READD (p->loopend, fd); /* - offsets in fixup_sample() */ - READD (p->samplerate, fd); - READB (p->origpitch, fd); - READB (p->pitchadj, fd); - FSKIPW (fd); /* skip sample link */ - READW (p->sampletype, fd); - p->samfile = 0; + return FLUID_FAILED; } - FSKIP (SFSHDRSIZE, fd); /* skip terminal shdr */ - - return (OK); + return FLUID_OK; } -/* "fixup" (inst # -> inst ptr) instrument references in preset list */ -static int -fixup_pgen (SFData * sf) +/* Called if a sample is no longer used by a voice. Used by dynamic sample loading + * to unload a sample that is not used by any loaded presets anymore but couldn't + * be unloaded straight away because it was still in use by a voice. */ +static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason) { - fluid_list_t *p, *p2, *p3; - SFZone *z; - int i; - - p = sf->preset; - while (p) - { - p2 = ((SFPreset *) (p->data))->zone; - while (p2) - { /* traverse this preset's zones */ - z = (SFZone *) (p2->data); - if ((i = GPOINTER_TO_INT (z->instsamp))) - { /* load instrument # */ - p3 = fluid_list_nth (sf->inst, i - 1); - if (!p3) - return (gerr (ErrCorr, - _("Preset %03d %03d: Invalid instrument reference"), - ((SFPreset *) (p->data))->bank, - ((SFPreset *) (p->data))->prenum)); - z->instsamp = p3; - } - else - z->instsamp = NULL; - p2 = fluid_list_next (p2); - } - p = fluid_list_next (p); - } - - return (OK); -} + if(reason == FLUID_SAMPLE_DONE && sample->preset_count == 0) + { + unload_sample(sample); + } -/* "fixup" (sample # -> sample ptr) sample references in instrument list */ -static int -fixup_igen (SFData * sf) -{ - fluid_list_t *p, *p2, *p3; - SFZone *z; - int i; - - p = sf->inst; - while (p) - { - p2 = ((SFInst *) (p->data))->zone; - while (p2) - { /* traverse instrument's zones */ - z = (SFZone *) (p2->data); - if ((i = GPOINTER_TO_INT (z->instsamp))) - { /* load sample # */ - p3 = fluid_list_nth (sf->sample, i - 1); - if (!p3) - return (gerr (ErrCorr, - _("Instrument \"%s\": Invalid sample reference"), - ((SFInst *) (p->data))->name)); - z->instsamp = p3; - } - p2 = fluid_list_next (p2); - } - p = fluid_list_next (p); - } - - return (OK); + return FLUID_OK; } -/* convert sample end, loopstart and loopend to offsets and check if valid */ -static int -fixup_sample (SFData * sf) +/* Called if a preset has been selected for or unselected from a channel. Used by + * dynamic sample loading to load and unload samples on demand. */ +static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int chan) { - fluid_list_t *p; - SFSample *sam; - - p = sf->sample; - while (p) - { - sam = (SFSample *) (p->data); - - /* if sample is not a ROM sample and end is over the sample data chunk - or sam start is greater than 4 less than the end (at least 4 samples) */ - if ((!(sam->sampletype & FLUID_SAMPLETYPE_ROM) - && sam->end > sdtachunk_size) || sam->start > (sam->end - 4)) - { - FLUID_LOG (FLUID_WARN, _("Sample '%s' start/end file positions are invalid," - " disabling and will not be saved"), sam->name); - - /* disable sample by setting all sample markers to 0 */ - sam->start = sam->end = sam->loopstart = sam->loopend = 0; - - return (OK); - } - else if (sam->loopend > sam->end || sam->loopstart >= sam->loopend - || sam->loopstart <= sam->start) - { /* loop is fowled?? (cluck cluck :) */ - /* can pad loop by 8 samples and ensure at least 4 for loop (2*8+4) */ - if ((sam->end - sam->start) >= 20) - { - sam->loopstart = sam->start + 8; - sam->loopend = sam->end - 8; - } - else - { /* loop is fowled, sample is tiny (can't pad 8 samples) */ - sam->loopstart = sam->start + 1; - sam->loopend = sam->end - 1; - } - } - - /* convert sample end, loopstart, loopend to offsets from sam->start */ - sam->end -= sam->start + 1; /* marks last sample, contrary to SF spec. */ - sam->loopstart -= sam->start; - sam->loopend -= sam->start; - - p = fluid_list_next (p); - } - - return (OK); -} + fluid_defsfont_t *defsfont; -/*=================================sfont.c======================== - Smurf SoundFont Editor - ================================================================*/ - - -/* optimum chunk area sizes (could be more optimum) */ -#define PRESET_CHUNK_OPTIMUM_AREA 256 -#define INST_CHUNK_OPTIMUM_AREA 256 -#define SAMPLE_CHUNK_OPTIMUM_AREA 256 -#define ZONE_CHUNK_OPTIMUM_AREA 256 -#define MOD_CHUNK_OPTIMUM_AREA 256 -#define GEN_CHUNK_OPTIMUM_AREA 256 + if(reason == FLUID_PRESET_SELECTED) + { + FLUID_LOG(FLUID_DBG, "Selected preset '%s' on channel %d", fluid_preset_get_name(preset), chan); + defsfont = fluid_sfont_get_data(preset->sfont); + load_preset_samples(defsfont, preset); + } + else if(reason == FLUID_PRESET_UNSELECTED) + { + FLUID_LOG(FLUID_DBG, "Deselected preset '%s' from channel %d", fluid_preset_get_name(preset), chan); + defsfont = fluid_sfont_get_data(preset->sfont); + unload_preset_samples(defsfont, preset); + } -unsigned short badgen[] = { Gen_Unused1, Gen_Unused2, Gen_Unused3, Gen_Unused4, - Gen_Reserved1, Gen_Reserved2, Gen_Reserved3, 0 -}; + return FLUID_OK; +} -unsigned short badpgen[] = { Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs, - Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_EndAddrCoarseOfs, - Gen_StartLoopAddrCoarseOfs, Gen_Keynum, Gen_Velocity, - Gen_EndLoopAddrCoarseOfs, Gen_SampleModes, Gen_ExclusiveClass, - Gen_OverrideRootKey, 0 -}; -/* close SoundFont file and delete a SoundFont structure */ -void -sfont_close (SFData * sf) +/* Walk through all samples used by the passed in preset and make sure that the + * sample data is loaded for each sample. Used by dynamic sample loading. */ +static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset) { - fluid_list_t *p, *p2; - - if (sf->sffd) - fclose (sf->sffd); - - if (sf->fname) - free (sf->fname); - - p = sf->info; - while (p) - { - free (p->data); - p = fluid_list_next (p); - } - delete_fluid_list(sf->info); - sf->info = NULL; - - p = sf->preset; - while (p) - { /* loop over presets */ - p2 = ((SFPreset *) (p->data))->zone; - while (p2) - { /* loop over preset's zones */ - sfont_free_zone (p2->data); - p2 = fluid_list_next (p2); - } /* free preset's zone list */ - delete_fluid_list (((SFPreset *) (p->data))->zone); - FLUID_FREE (p->data); /* free preset chunk */ - p = fluid_list_next (p); - } - delete_fluid_list (sf->preset); - sf->preset = NULL; - - p = sf->inst; - while (p) - { /* loop over instruments */ - p2 = ((SFInst *) (p->data))->zone; - while (p2) - { /* loop over inst's zones */ - sfont_free_zone (p2->data); - p2 = fluid_list_next (p2); - } /* free inst's zone list */ - delete_fluid_list (((SFInst *) (p->data))->zone); - FLUID_FREE (p->data); - p = fluid_list_next (p); - } - delete_fluid_list (sf->inst); - sf->inst = NULL; - - p = sf->sample; - while (p) - { - FLUID_FREE (p->data); - p = fluid_list_next (p); - } - delete_fluid_list (sf->sample); - sf->sample = NULL; - - FLUID_FREE (sf); -} + fluid_defpreset_t *defpreset; + fluid_preset_zone_t *preset_zone; + fluid_inst_t *inst; + fluid_inst_zone_t *inst_zone; + fluid_sample_t *sample; + SFData *sffile = NULL; -/* free all elements of a zone (Preset or Instrument) */ -void -sfont_free_zone (SFZone * zone) -{ - fluid_list_t *p; + defpreset = fluid_preset_get_data(preset); + preset_zone = fluid_defpreset_get_zone(defpreset); - if (!zone) - return; + while(preset_zone != NULL) + { + inst = fluid_preset_zone_get_inst(preset_zone); + inst_zone = fluid_inst_get_zone(inst); + + while(inst_zone != NULL) + { + sample = fluid_inst_zone_get_sample(inst_zone); + + if((sample != NULL) && (sample->start != sample->end)) + { + sample->preset_count++; + + /* If this is the first time this sample has been selected, + * load the sampledata */ + if(sample->preset_count == 1) + { + /* Make sure we have an open Soundfont file. Do this here + * to avoid having to open the file if no loading is necessary + * for a preset */ + if(sffile == NULL) + { + sffile = fluid_sffile_open(defsfont->filename, defsfont->fcbs); + + if(sffile == NULL) + { + FLUID_LOG(FLUID_ERR, "Unable to open Soundfont file"); + return FLUID_FAILED; + } + } + + if(fluid_defsfont_load_sampledata(defsfont, sffile, sample) == FLUID_OK) + { + fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short)); + fluid_voice_optimize_sample(sample); + } + else + { + FLUID_LOG(FLUID_ERR, "Unable to load sample '%s', disabling", sample->name); + sample->start = sample->end = 0; + } + } + } + + inst_zone = fluid_inst_zone_next(inst_zone); + } - p = zone->gen; - while (p) - { /* Free gen chunks for this zone */ - if (p->data) - FLUID_FREE (p->data); - p = fluid_list_next (p); + preset_zone = fluid_preset_zone_next(preset_zone); } - delete_fluid_list (zone->gen); /* free genlist */ - p = zone->mod; - while (p) - { /* Free mod chunks for this zone */ - if (p->data) - FLUID_FREE (p->data); - p = fluid_list_next (p); + if(sffile != NULL) + { + fluid_sffile_close(sffile); } - delete_fluid_list (zone->mod); /* free modlist */ - FLUID_FREE (zone); /* free zone chunk */ + return FLUID_OK; } -/* preset sort function, first by bank, then by preset # */ -int -sfont_preset_compare_func (void* a, void* b) +/* Walk through all samples used by the passed in preset and unload the sample data + * of each sample that is not used by any selected preset anymore. Used by dynamic + * sample loading. */ +static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset) { - int aval, bval; + fluid_defpreset_t *defpreset; + fluid_preset_zone_t *preset_zone; + fluid_inst_t *inst; + fluid_inst_zone_t *inst_zone; + fluid_sample_t *sample; + + defpreset = fluid_preset_get_data(preset); + preset_zone = fluid_defpreset_get_zone(defpreset); + + while(preset_zone != NULL) + { + inst = fluid_preset_zone_get_inst(preset_zone); + inst_zone = fluid_inst_get_zone(inst); + + while(inst_zone != NULL) + { + sample = fluid_inst_zone_get_sample(inst_zone); + + if((sample != NULL) && (sample->preset_count > 0)) + { + sample->preset_count--; + + /* If the sample is not used by any preset or used by a + * sounding voice, unload it from the sample cache. If it's + * still in use by a voice, dynamic_samples_sample_notify will + * take care of unloading the sample as soon as the voice is + * finished with it (but only on the next API call). */ + if(sample->preset_count == 0 && sample->refcount == 0) + { + unload_sample(sample); + } + } + + inst_zone = fluid_inst_zone_next(inst_zone); + } - aval = (int) (((SFPreset *) a)->bank) << 16 | ((SFPreset *) a)->prenum; - bval = (int) (((SFPreset *) b)->bank) << 16 | ((SFPreset *) b)->prenum; + preset_zone = fluid_preset_zone_next(preset_zone); + } - return (aval - bval); + return FLUID_OK; } -/* delete zone from zone list */ -void -sfont_zone_delete (SFData * sf, fluid_list_t ** zlist, SFZone * zone) +/* Unload an unused sample from the samplecache */ +static void unload_sample(fluid_sample_t *sample) { - *zlist = fluid_list_remove (*zlist, (void*) zone); - sfont_free_zone (zone); -} + fluid_return_if_fail(sample != NULL); + fluid_return_if_fail(sample->data != NULL); + fluid_return_if_fail(sample->preset_count == 0); + fluid_return_if_fail(sample->refcount == 0); -/* Find generator in gen list */ -fluid_list_t * -gen_inlist (int gen, fluid_list_t * genlist) -{ /* is generator in gen list? */ - fluid_list_t *p; + FLUID_LOG(FLUID_DBG, "Unloading sample '%s'", sample->name); - p = genlist; - while (p) + if(fluid_samplecache_unload(sample->data) == FLUID_FAILED) { - if (p->data == NULL) - return (NULL); - if (gen == ((SFGen *) p->data)->id) - break; - p = fluid_list_next (p); + FLUID_LOG(FLUID_ERR, "Unable to unload sample '%s'", sample->name); + } + else + { + sample->data = NULL; + sample->data24 = NULL; } - return (p); -} - -/* check validity of instrument generator */ -int -gen_valid (int gen) -{ /* is generator id valid? */ - int i = 0; - - if (gen > Gen_MaxValid) - return (FALSE); - while (badgen[i] && badgen[i] != gen) - i++; - return (badgen[i] == 0); -} - -/* check validity of preset generator */ -int -gen_validp (int gen) -{ /* is preset generator valid? */ - int i = 0; - - if (!gen_valid (gen)) - return (FALSE); - while (badpgen[i] && badpgen[i] != (unsigned short) gen) - i++; - return (badpgen[i] == 0); } -/*================================util.c===========================*/ - -/* Logging function, returns FAIL to use as a return value in calling funcs */ -int -gerr (int ev, char * fmt, ...) +static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx) { - va_list args; - - va_start (args, fmt); - vprintf(fmt, args); - va_end (args); + fluid_list_t *list; + fluid_inst_t *inst; - printf("\n"); - - return (FAIL); -} + for(list = defsfont->inst; list != NULL; list = fluid_list_next(list)) + { + inst = fluid_list_get(list); -int -safe_fread (void *buf, int count, FILE * fd) -{ - if (fread (buf, count, 1, fd) != 1) - { /* size_t = count, nmemb = 1 */ - if (feof (fd)) - gerr (ErrEof, _("EOF while attemping to read %d bytes"), count); - else - FLUID_LOG (FLUID_ERR, _("File read failed")); - return (FAIL); - } - return (OK); -} + if(inst->source_idx == idx) + { + return inst; + } + } -int -safe_fseek (FILE * fd, long ofs, int whence) -{ - if (fseek (fd, ofs, whence) == -1) { - FLUID_LOG (FLUID_ERR, _("File seek failed with offset = %ld and whence = %d"), ofs, whence); - return (FAIL); - } - return (OK); + return NULL; } |