summaryrefslogtreecommitdiff
path: root/libs/fluidsynth/src/fluid_defsfont.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/fluidsynth/src/fluid_defsfont.c')
-rw-r--r--libs/fluidsynth/src/fluid_defsfont.c4647
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;
}