Update Fluidsynth to v2.0.7
[ardour.git] / libs / fluidsynth / src / fluid_defsfont.c
index c3952184114e47e76d85fc8119f09255bc8570bb..4639574dd9e147c99a9fbd65e18aad06bbc663b7 100644 (file)
@@ -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
 
 
 #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;
+    }
+
+    fluid_sfont_set_data(sfont, defsfont);
 
-  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;
+    defsfont->sfont = sfont;
+
+    if(fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED)
+    {
+        fluid_defsfont_sfont_delete(sfont);
+        return NULL;
+    }
 
-  return sfont;
+    return sfont;
 }
 
 
@@ -95,621 +118,498 @@ fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* file
  *                           PUBLIC INTERFACE
  */
 
-int fluid_defsfont_sfont_delete(fluid_sfont_tsfont)
+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_tsfont)
+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_tpreset)
+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_tpreset)
+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
+ */
+
+/*
+ * new_fluid_defsfont
  */
+fluid_defsfont_t *new_fluid_defsfont(fluid_settings_t *settings)
+{
+    fluid_defsfont_t *defsfont;
 
-typedef struct _fluid_cached_sampledata_t {
-  struct _fluid_cached_sampledata_t *next;
+    defsfont = FLUID_NEW(fluid_defsfont_t);
 
-  char* filename;
-  time_t modification_time;
-  int num_references;
-  int mlock;
+    if(defsfont == NULL)
+    {
+        FLUID_LOG(FLUID_ERR, "Out of memory");
+        return NULL;
+    }
 
-  const short* sampledata;
-  unsigned int samplesize;
-} fluid_cached_sampledata_t;
+    FLUID_MEMSET(defsfont, 0, sizeof(*defsfont));
 
-static fluid_cached_sampledata_t* all_cached_sampledata = NULL;
-static fluid_mutex_t cached_sampledata_mutex = FLUID_MUTEX_INIT;
+    fluid_settings_getint(settings, "synth.lock-memory", &defsfont->mlock);
+    fluid_settings_getint(settings, "synth.dynamic-sample-loading", &defsfont->dynamic_samples);
+
+    return defsfont;
+}
 
-static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
+/*
+ * delete_fluid_defsfont
+ */
+int delete_fluid_defsfont(fluid_defsfont_t *defsfont)
 {
-#if defined(WIN32) || defined(__OS2__)
-  *modification_time = 0;
-  return FLUID_OK;
-#else
-  struct stat buf;
+    fluid_list_t *list;
+    fluid_preset_t *preset;
+    fluid_sample_t *sample;
 
-  if (stat(filename, &buf) == -1) {
-    return FLUID_FAILED;
-  }
-
-  *modification_time = buf.st_mtime;
-  return FLUID_OK;
-#endif
-}
-
-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;
-}
-
-static int fluid_cached_sampledata_unload(const short *sampledata)
-{
-  fluid_cached_sampledata_t* prev = NULL;
-  fluid_cached_sampledata_t* cached_sampledata;
-
-  fluid_mutex_lock(cached_sampledata_mutex);
-  cached_sampledata = all_cached_sampledata;
-
-  while (cached_sampledata != NULL) {
-    if (sampledata == cached_sampledata->sampledata) {
-
-      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);
-
-        if (prev != NULL) {
-          prev->next = cached_sampledata->next;
-        } else {
-          all_cached_sampledata = cached_sampledata->next;
+    fluid_return_val_if_fail(defsfont != NULL, FLUID_OK);
+
+    /* 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(sample->refcount != 0)
+        {
+            return FLUID_FAILED;
         }
+    }
+
+    if(defsfont->filename != NULL)
+    {
+        FLUID_FREE(defsfont->filename);
+    }
 
-        FLUID_FREE(cached_sampledata);
-      }
+    for(list = defsfont->sample; list; list = fluid_list_next(list))
+    {
+        sample = (fluid_sample_t *) fluid_list_get(list);
+
+        /* If the sample data pointer is different to the sampledata chunk of
+         * the soundfont, then the sample has been loaded individually (SF3)
+         * and needs to be unloaded explicitly. This is safe even if using
+         * dynamic sample loading, as the sample_unload mechanism sets
+         * sample->data to NULL after unload. */
+        if ((sample->data != NULL) && (sample->data != defsfont->sampledata))
+        {
+            fluid_samplecache_unload(sample->data);
+        }
+        delete_fluid_sample(sample);
+    }
 
-      goto success_exit;
+    if(defsfont->sample)
+    {
+        delete_fluid_list(defsfont->sample);
     }
 
-    prev = cached_sampledata;
-    cached_sampledata = cached_sampledata->next;
-  }
+    if(defsfont->sampledata != NULL)
+    {
+        fluid_samplecache_unload(defsfont->sampledata);
+    }
 
-  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;
+    for(list = defsfont->preset; list; list = fluid_list_next(list))
+    {
+        preset = (fluid_preset_t *)fluid_list_get(list);
+        fluid_defpreset_preset_delete(preset);
+    }
 
- error_exit:
-  fluid_mutex_unlock(cached_sampledata_mutex);
-  return FLUID_FAILED;
-}
+    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);
 
+    FLUID_FREE(defsfont);
+    return FLUID_OK;
+}
 
-/***************************************************************
- *
- *                           SFONT
+/*
+ * fluid_defsfont_get_name
  */
+const char *fluid_defsfont_get_name(fluid_defsfont_t *defsfont)
+{
+    return defsfont->filename;
+}
 
-/*
- * new_fluid_defsfont
+/* Load sample data for a single sample from the Soundfont file.
+ * Returns FLUID_OK on error, otherwise FLUID_FAILED
  */
-fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings)
+int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, fluid_sample_t *sample)
 {
-  fluid_defsfont_t* sfont;
-  int i;
+    int num_samples;
+    unsigned int source_end = sample->source_end;
 
-  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;
-  }
+    /* 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;
+    if(num_samples < 0)
+    {
+        return FLUID_FAILED;
+    }
 
-  /* 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(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;
     }
-  }
 
-  if (sfont->filename != NULL) {
-    FLUID_FREE(sfont->filename);
-  }
+    /* 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;
 
-  for (list = sfont->sample; list; list = fluid_list_next(list)) {
-    delete_fluid_sample((fluid_sample_t*) fluid_list_get(list));
-  }
+    return FLUID_OK;
+}
+
+/* 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
+ */
+int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata)
+{
+    fluid_list_t *list;
+    fluid_sample_t *sample;
+    int sf3_file = (sfdata->version.major == 3);
 
-  if (sfont->sample) {
-    delete_fluid_list(sfont->sample);
-  }
+    /* 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 (sfont->sampledata != NULL) {
-    fluid_cached_sampledata_unload(sfont->sampledata);
-  }
+        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;
+        }
+    }
 
-  while (sfont->preset_stack_size > 0)
-    FLUID_FREE(sfont->preset_stack[--sfont->preset_stack_size]);
-  FLUID_FREE(sfont->preset_stack);
+    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);
+        }
 
-  preset = sfont->preset;
-  while (preset != NULL) {
-    sfont->preset = preset->next;
-    delete_fluid_defpreset(preset);
-    preset = sfont->preset;
-  }
+        fluid_voice_optimize_sample(sample);
+    }
 
-  FLUID_FREE(sfont);
-  return FLUID_OK;
+    return FLUID_OK;
 }
 
 /*
- * fluid_defsfont_get_name
+ * fluid_defsfont_load
  */
-char* fluid_defsfont_get_name(fluid_defsfont_t* sfont)
+int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t *fcbs, const char *file)
 {
-  return sfont->filename;
-}
+    SFData *sfdata;
+    fluid_list_t *p;
+    SFPreset *sfpreset;
+    SFSample *sfsample;
+    fluid_sample_t *sample;
+    fluid_defpreset_t *defpreset = NULL;
 
+    defsfont->filename = FLUID_STRDUP(file);
 
-/*
- * fluid_defsfont_load
- */
-int fluid_defsfont_load(fluid_defsfont_t* sfont, 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);
+    if(defsfont->filename == NULL)
+    {
+        FLUID_LOG(FLUID_ERR, "Out of memory");
+        return FLUID_FAILED;
+    }
 
-  /* 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->fcbs = fcbs;
+
+    /* The actual loading is done in the sfont and sffile files */
+    sfdata = fluid_sffile_open(file, fcbs);
+
+    if(sfdata == NULL)
+    {
+        /* error message already printed */
+        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) */
+    defsfont->samplepos = sfdata->samplepos;
+    defsfont->samplesize = sfdata->samplesize;
+    defsfont->sample24pos = sfdata->sample24pos;
+    defsfont->sample24size = sfdata->sample24size;
+
+    /* Create all samples from sample headers */
+    p = sfdata->sample;
+
+    while(p != NULL)
+    {
+        sfsample = (SFSample *)fluid_list_get(p);
+
+        sample = new_fluid_sample();
+
+        if(sample == NULL)
+        {
+            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;
+        if(fluid_sample_import_sfont(sample, sfsample, defsfont) == FLUID_OK)
+        {
+            fluid_defsfont_add_sample(defsfont, sample);
+        }
+        else
+        {
+            delete_fluid_sample(sample);
+            sample = NULL;
+        }
 
-  /* load sample data in one block */
-  if (fluid_defsfont_load_sampledata(sfont) != FLUID_OK)
-    goto err_exit;
+        /* Store reference to FluidSynth sample in SFSample for later IZone fixups */
+        sfsample->fluid_sample = sample;
+
+        p = fluid_list_next(p);
+    }
 
-  /* Create all the sample headers */
-  p = sfdata->sample;
-  while (p != NULL) {
-    sfsample = (SFSample *) p->data;
+    /* 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;
+        }
+    }
 
-    sample = new_fluid_sample();
-    if (sample == NULL) goto err_exit;
+    /* Load all the presets */
+    p = sfdata->preset;
 
-    if (fluid_sample_import_sfont(sample, sfsample, sfont) != FLUID_OK)
-      goto err_exit;
+    while(p != NULL)
+    {
+        sfpreset = (SFPreset *)fluid_list_get(p);
+        defpreset = new_fluid_defpreset();
 
-    /* Store reference to FluidSynth sample in SFSample for later IZone fixups */
-    sfsample->fluid_sample = sample;
+        if(defpreset == NULL)
+        {
+            goto err_exit;
+        }
 
-    fluid_defsfont_add_sample(sfont, sample);
-    fluid_voice_optimize_sample(sample);
-    p = fluid_list_next(p);
-  }
+        if(fluid_defpreset_import_sfont(defpreset, sfpreset, defsfont) != FLUID_OK)
+        {
+            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_defsfont_add_preset(defsfont, defpreset) == FLUID_FAILED)
+        {
+            goto err_exit;
+        }
 
-    if (fluid_defpreset_import_sfont(preset, sfpreset, sfont) != FLUID_OK)
-      goto err_exit;
+        p = fluid_list_next(p);
+    }
 
-    fluid_defsfont_add_preset(sfont, preset);
-    p = fluid_list_next(p);
-  }
-  sfont_close (sfdata);
+    fluid_sffile_close(sfdata);
 
-  return FLUID_OK;
+    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)
-{
-  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_defsfont_load_sampledata
- */
-int
-fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont)
+int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *defpreset)
 {
-  return fluid_cached_sampledata_load(sfont->filename, sfont->samplepos,
-    sfont->samplesize, &sfont->sampledata, sfont->mlock);
+    fluid_preset_t *preset;
+
+    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;
+    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;
+        }
     }
-    preset = preset->next;
-  }
-  return NULL;
+
+    return NULL;
 }
 
 /*
  * fluid_defsfont_iteration_start
  */
-void fluid_defsfont_iteration_start(fluid_defsfont_tsfont)
+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,657 +620,1029 @@ 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(void)
 {
-  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->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_tpreset)
+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;
+    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;
     }
-    zone = preset->zone;
-  }
-  FLUID_FREE(preset);
-  return err;
+
+    FLUID_FREE(defpreset);
 }
 
 int
-fluid_defpreset_get_banknum(fluid_defpreset_tpreset)
+fluid_defpreset_get_banknum(fluid_defpreset_t *defpreset)
 {
-  return preset->bank;
+    return defpreset->bank;
 }
 
 int
-fluid_defpreset_get_num(fluid_defpreset_tpreset)
+fluid_defpreset_get_num(fluid_defpreset_t *defpreset)
 {
-  return preset->num;
+    return defpreset->num;
 }
 
-char*
-fluid_defpreset_get_name(fluid_defpreset_tpreset)
+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_tpreset)
+fluid_defpreset_t *
+fluid_defpreset_next(fluid_defpreset_t *defpreset)
 {
-  return preset->next;
+    return defpreset->next;
 }
 
+/*
+ * Adds global and local modulators list to the voice. This is done in 2 steps:
+ * - Step 1: Local modulators replace identic global modulators.
+ * - Step 2: global + local modulators are added to the voice using mode.
+ *
+ * Instrument zone list (local/global) must be added using FLUID_VOICE_OVERWRITE.
+ * Preset zone list (local/global) must be added using FLUID_VOICE_ADD.
+ *
+ * @param voice voice instance.
+ * @param global_mod global list of modulators.
+ * @param local_mod local list of modulators.
+ * @param mode Determines how to handle an existing identical modulator.
+ *   #FLUID_VOICE_ADD to add (offset) the modulator amounts,
+ *   #FLUID_VOICE_OVERWRITE to replace the modulator,
+*/
+static void
+fluid_defpreset_noteon_add_mod_to_voice(fluid_voice_t *voice,
+                                        fluid_mod_t *global_mod, fluid_mod_t *local_mod,
+                                        int mode)
+{
+    fluid_mod_t *mod;
+    /* list for 'sorting' global/local modulators */
+    fluid_mod_t *mod_list[FLUID_NUM_MOD];
+    int mod_list_count, i;
+
+    /* identity_limit_count is the modulator upper limit number to handle with
+     * existing identical modulators.
+     * When identity_limit_count is below the actual number of modulators, this
+     * will restrict identity check to this upper limit,
+     * This is useful when we know by advance that there is no duplicate with
+     * modulators at index above this limit. This avoid wasting cpu cycles at
+     * noteon.
+     */
+    int identity_limit_count;
+
+    /* Step 1: Local modulators replace identic global modulators. */
+
+    /* local (instrument zone/preset zone), modulators: Put them all into a list. */
+    mod_list_count = 0;
+
+    while(local_mod)
+    {
+        /* As modulators number in local_mod list was limited to FLUID_NUM_MOD at
+           soundfont loading time (fluid_limit_mod_list()), here we don't need
+           to check if mod_list is full.
+         */
+        mod_list[mod_list_count++] = local_mod;
+        local_mod = local_mod->next;
+    }
+
+    /* global (instrument zone/preset zone), modulators.
+     * Replace modulators with the same definition in the global list:
+     * (Instrument zone: SF 2.01 page 69, 'bullet' 8)
+     * (Preset zone:     SF 2.01 page 69, second-last bullet).
+     *
+     * mod_list contains local modulators. Now we know that there
+     * is no global modulator identic to another global modulator (this has
+     * been checked at soundfont loading time). So global modulators
+     * are only checked against local modulators number.
+     */
+
+    /* Restrict identity check to the number of local modulators */
+    identity_limit_count = mod_list_count;
+
+    while(global_mod)
+    {
+        /* 'Identical' global modulators are ignored.
+         *  SF2.01 section 9.5.1
+         *  page 69, 'bullet' 3 defines 'identical'.  */
+
+        for(i = 0; i < identity_limit_count; i++)
+        {
+            if(fluid_mod_test_identity(global_mod, mod_list[i]))
+            {
+                break;
+            }
+        }
+
+        /* Finally add the new modulator to the list. */
+        if(i >= identity_limit_count)
+        {
+            /* Although local_mod and global_mod lists was limited to
+               FLUID_NUM_MOD at soundfont loading time, it is possible that
+               local + global modulators exceeds FLUID_NUM_MOD.
+               So, checks if mod_list_count reachs the limit.
+            */
+            if(mod_list_count >= FLUID_NUM_MOD)
+            {
+                /* mod_list is full, we silently forget this modulator and
+                   next global modulators. When mod_list will be added to the
+                   voice, a warning will be displayed if the voice list is full.
+                   (see fluid_voice_add_mod_local()).
+                */
+                break;
+            }
+
+            mod_list[mod_list_count++] = global_mod;
+        }
+
+        global_mod = global_mod->next;
+    }
+
+    /* Step 2: global + local modulators are added to the voice using mode. */
+
+    /*
+     * mod_list contains local and global modulators, we know that:
+     * - there is no global modulator identic to another global modulator,
+     * - there is no local modulator identic to another local modulator,
+     * So these local/global modulators are only checked against
+     * actual number of voice modulators.
+     */
+
+    /* Restrict identity check to the actual number of voice modulators */
+    /* Acual number of voice modulators : defaults + [instruments] */
+    identity_limit_count = voice->mod_count;
+
+    for(i = 0; i < mod_list_count; i++)
+    {
+
+        mod = mod_list[i];
+        /* in mode FLUID_VOICE_OVERWRITE disabled instruments modulators CANNOT be skipped. */
+        /* in mode FLUID_VOICE_ADD disabled preset modulators can be skipped. */
+
+        if((mode == FLUID_VOICE_OVERWRITE) || (mod->amount != 0))
+        {
+            /* Instrument modulators -supersede- existing (default) modulators.
+               SF 2.01 page 69, 'bullet' 6 */
+
+            /* Preset modulators -add- to existing instrument modulators.
+               SF2.01 page 70 first bullet on page */
+            fluid_voice_add_mod_local(voice, mod, mode, identity_limit_count);
+        }
+    }
+}
 
 /*
  * 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;
+    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)) {
-
-      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 */
-      inst_zone = fluid_inst_get_zone(inst);
-         while (inst_zone != NULL) {
+    while(preset_zone != NULL)
+    {
 
-       /* 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;
-       }
+        /* 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);
+
+                /* 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;
+
+                    /* 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);
+
+                    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 */
+
+                    /* Adds instrument zone modulators (global and local) to the voice.*/
+                    fluid_defpreset_noteon_add_mod_to_voice(voice,
+                                                            /* global instrument modulators */
+                                                            global_inst_zone ? global_inst_zone->mod : NULL,
+                                                            inst_zone->mod, /* local instrument modulators */
+                                                            FLUID_VOICE_OVERWRITE); /* mode */
+
+                    /* 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 */
+
+                    /* Adds preset zone modulators (global and local) to the voice.*/
+                    fluid_defpreset_noteon_add_mod_to_voice(voice,
+                                                            /* global preset modulators */
+                                                            global_preset_zone ? global_preset_zone->mod : NULL,
+                                                            preset_zone->mod, /* local preset modulators */
+                                                            FLUID_VOICE_ADD); /* mode */
+
+                    /* 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)
+                     */
+                }
+            }
+        }
 
-       /* check if the note falls into the key and velocity range of this
-          instrument */
+        preset_zone = fluid_preset_zone_next(preset_zone);
+    }
 
-       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;
+    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_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_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(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), "pz:%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_tpreset)
+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_tpreset)
+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_init(&zone->gen[0], NULL);
+    zone->mod = NULL; /* list of modulators */
+    return zone;
+}
+
+/*
+ * delete list of modulators.
  */
+void delete_fluid_list_mod(fluid_mod_t *mod)
+{
+    fluid_mod_t *tmp;
+
+    while(mod) /* delete the modulators */
+    {
+        tmp = mod;
+        mod = mod->next;
+        delete_fluid_mod(tmp);
+    }
+}
 
 /*
  * delete_fluid_preset_zone
  */
-int
-delete_fluid_preset_zone(fluid_preset_zone_tzone)
+void
+delete_fluid_preset_zone(fluid_preset_zone_t *zone)
 {
-  fluid_mod_t *mod, *tmp;
+    fluid_list_t *list;
 
-  mod = zone->mod;
-  while (mod)  /* delete the modulators */
+    fluid_return_if_fail(zone != NULL);
+
+    delete_fluid_list_mod(zone->mod);
+
+    for(list = zone->voice_zone; list != NULL; list = fluid_list_next(list))
     {
-      tmp = mod;
-      mod = mod->next;
-      fluid_mod_delete (tmp);
+        FLUID_FREE(fluid_list_get(list));
     }
 
-  if (zone->name) FLUID_FREE (zone->name);
-  if (zone->inst) delete_fluid_inst (zone->inst);
-  FLUID_FREE(zone);
-  return FLUID_OK;
+    delete_fluid_list(zone->voice_zone);
+
+    FLUID_FREE(zone->name);
+    FLUID_FREE(zone);
 }
 
-/*
- * fluid_preset_zone_import_sfont
+static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone)
+{
+    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);
+
+    while(inst_zone != NULL)
+    {
+
+        /* 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);
+    }
+
+    return FLUID_OK;
+}
+
+/**
+ * Checks if modulator mod is identic to another modulator in the list
+ * (specs SF 2.0X  7.4, 7.8).
+ * @param mod, modulator list.
+ * @param name, if not NULL, pointer on a string displayed as warning.
+ * @return TRUE if mod is identic to another modulator, FALSE otherwise.
  */
-int
-fluid_preset_zone_import_sfont(fluid_preset_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 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;
+static int
+fluid_zone_is_mod_identic(fluid_mod_t *mod, char *name)
+{
+    fluid_mod_t *next = mod->next;
 
-    if (mod_dest == NULL){
-      return FLUID_FAILED;
+    while(next)
+    {
+        /* is mod identic to next ? */
+        if(fluid_mod_test_identity(mod, next))
+        {
+            if(name)
+            {
+                FLUID_LOG(FLUID_WARN, "Ignoring identic modulator %s", name);
+            }
+
+            return TRUE;
+        }
+
+        next = next->next;
     }
-    mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/
 
-    /* *** Amount *** */
-    mod_dest->amount = mod_src->amount;
+    return FALSE;
+}
 
-    /* *** 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;
+/**
+ * Limits the number of modulators in a modulator list.
+ * This is appropriate to internal synthesizer modulators tables
+ * which have a fixed size (FLUID_NUM_MOD).
+ *
+ * @param zone_name, zone name
+ * @param list_mod, address of pointer on modulator list.
+ */
+static void fluid_limit_mod_list(char *zone_name, fluid_mod_t **list_mod)
+{
+    int mod_idx = 0; /* modulator index */
+    fluid_mod_t *prev_mod = NULL; /* previous modulator in list_mod */
+    fluid_mod_t *mod = *list_mod; /* first modulator in list_mod */
 
-    /* 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;
+    while(mod)
+    {
+        if((mod_idx + 1) > FLUID_NUM_MOD)
+        {
+            /* truncation of list_mod */
+            if(mod_idx)
+            {
+                prev_mod->next = NULL;
+            }
+            else
+            {
+                *list_mod = NULL;
+            }
+
+            delete_fluid_list_mod(mod);
+            FLUID_LOG(FLUID_WARN, "%s, modulators count limited to %d", zone_name,
+                      FLUID_NUM_MOD);
+            break;
+        }
+
+        mod_idx++;
+        prev_mod = mod;
+        mod = mod->next;
     }
+}
 
-    /* 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;
+/**
+ * Checks and remove invalid modulators from a zone modulators list.
+ * - checks valid modulator sources (specs SF 2.01  7.4, 7.8, 8.2.1).
+ * - checks identic modulators in the list (specs SF 2.01  7.4, 7.8).
+ * @param zone_name, zone name.
+ * @param list_mod, address of pointer on modulators list.
+ */
+static void
+fluid_zone_check_mod(char *zone_name, fluid_mod_t **list_mod)
+{
+    fluid_mod_t *prev_mod = NULL; /* previous modulator in list_mod */
+    fluid_mod_t *mod = *list_mod; /* first modulator in list_mod */
+    int mod_idx = 0; /* modulator index */
+
+    while(mod)
+    {
+        char zone_mod_name[256];
+        fluid_mod_t *next = mod->next;
+
+        /* prepare modulator name: zonename/#modulator */
+        FLUID_SNPRINTF(zone_mod_name, sizeof(zone_mod_name), "%s/mod%d", zone_name, mod_idx);
+
+        /* has mod invalid sources ? */
+        if(!fluid_mod_check_sources(mod,  zone_mod_name)
+                /* or is mod identic to any following modulator ? */
+                || fluid_zone_is_mod_identic(mod, zone_mod_name))
+        {
+            /* the modulator is useless so we remove it */
+            if(prev_mod)
+            {
+                prev_mod->next = next;
+            }
+            else
+            {
+                *list_mod = next;
+            }
+
+            delete_fluid_mod(mod); /* freeing */
+        }
+        else
+        {
+            prev_mod = mod;
+        }
+
+        mod = next;
+        mod_idx++;
     }
 
-    /* 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;
+    /* limits the size of modulators list */
+    fluid_limit_mod_list(zone_name, list_mod);
+}
+
+/*
+ * fluid_zone_gen_import_sfont
+ * Imports generators from sfzone to gen and range.
+ * @param gen, pointer on destination generators table.
+ * @param range, pointer on destination range generators.
+ * @param sfzone, pointer on soundfont zone generators.
+ */
+static void
+fluid_zone_gen_import_sfont(fluid_gen_t *gen, fluid_zone_range_t *range, SFZone *sfzone)
+{
+    fluid_list_t *r;
+    SFGen *sfgen;
+
+    for(r = sfzone->gen; r != NULL;)
+    {
+        sfgen = (SFGen *)fluid_list_get(r);
+
+        switch(sfgen->id)
+        {
+        case GEN_KEYRANGE:
+            range->keylo = sfgen->amount.range.lo;
+            range->keyhi = sfgen->amount.range.hi;
+            break;
+
+        case GEN_VELRANGE:
+            range->vello = sfgen->amount.range.lo;
+            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 */
+            gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
+            gen[sfgen->id].flags = GEN_SET;
+            break;
+
+        default:
+            /* FIXME: some generators have an unsigne word amount value but i don't know which ones */
+            gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
+            gen[sfgen->id].flags = GEN_SET;
+            break;
+        }
+
+        r = fluid_list_next(r);
     }
+}
 
-    /* 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;
+/*
+ * fluid_zone_mod_source_import_sfont
+ * Imports source information from sf_source to src and flags.
+ * @param src, pointer on destination modulator source.
+ * @param flags, pointer on destination modulator flags.
+ * @param sf_source, soundfont modulator source.
+ * @return return TRUE if success, FALSE if source type is unknow.
+ */
+static int
+fluid_zone_mod_source_import_sfont(unsigned char *src, unsigned char *flags, unsigned short sf_source)
+{
+    int type;
+    unsigned char flags_dest; /* destination flags */
+
+    /* sources */
+    *src = sf_source & 127; /* index of source, seven-bit value, SF2.01 section 8.2, page 50 */
 
     /* 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;
+    flags_dest = 0;
+
+    if(sf_source & (1 << 7))
+    {
+        flags_dest |= FLUID_MOD_CC;
+    }
+    else
+    {
+        flags_dest |= 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;
+    if(sf_source & (1 << 8))
+    {
+        flags_dest |= FLUID_MOD_NEGATIVE;
+    }
+    else
+    {
+        flags_dest |= 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;
+    if(sf_source & (1 << 9))
+    {
+        flags_dest |= FLUID_MOD_BIPOLAR;
+    }
+    else
+    {
+        flags_dest |= FLUID_MOD_UNIPOLAR;
     }
 
     /* modulator source types: SF2.01 section 8.2.1 page 52 */
-    type = (mod_src->amtsrc) >> 10;
+    type = sf_source >> 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;
+
+    if(type == 0)
+    {
+        flags_dest |= FLUID_MOD_LINEAR;
     }
+    else if(type == 1)
+    {
+        flags_dest |= FLUID_MOD_CONCAVE;
+    }
+    else if(type == 2)
+    {
+        flags_dest |= FLUID_MOD_CONVEX;
+    }
+    else if(type == 3)
+    {
+        flags_dest |= FLUID_MOD_SWITCH;
+    }
+    else
+    {
+        *flags = flags_dest;
+        /* This shouldn't happen - unknown type! */
+        return FALSE;
+    }
+
+    *flags = flags_dest;
+    return TRUE;
+}
 
-    /* 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;
+/*
+ * fluid_zone_mod_import_sfont
+ * Imports modulators from sfzone to modulators list mod.
+ * @param zone_name, zone name.
+ * @param mod, address of pointer on modulators list to return.
+ * @param sfzone, pointer on soundfont zone.
+ * @return FLUID_OK if success, FLUID_FAILED otherwise.
+ */
+static int
+fluid_zone_mod_import_sfont(char *zone_name, fluid_mod_t **mod, SFZone *sfzone)
+{
+    fluid_list_t *r;
+    int count;
 
-      /* Find the end of the list */
-      while (last_mod->next != NULL){
-       last_mod=last_mod->next;
-      }
+    /* Import the modulators (only SF2.1 and higher) */
+    for(count = 0, r = sfzone->mod; r != NULL; count++)
+    {
 
-      last_mod->next = mod_dest;
-    }
+        SFMod *mod_src = (SFMod *)fluid_list_get(r);
+        fluid_mod_t *mod_dest = new_fluid_mod();
 
-    r = fluid_list_next(r);
-  } /* foreach modulator */
+        if(mod_dest == NULL)
+        {
+            return FLUID_FAILED;
+        }
 
-  return FLUID_OK;
+        mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/
+
+        /* *** Amount *** */
+        mod_dest->amount = mod_src->amount;
+
+        /* *** Source *** */
+        if(!fluid_zone_mod_source_import_sfont(&mod_dest->src1, &mod_dest->flags1, mod_src->src))
+        {
+            /* This shouldn't happen - unknown type!
+             * Deactivate the modulator by setting the amount to 0. */
+            mod_dest->amount = 0;
+        }  
+
+        /* Note: When primary source input (src1) is set to General Controller 'No Controller',
+           output will be forced to 0.0 at synthesis time (see fluid_mod_get_value()).
+           That means that the minimum value of the modulator will be always 0.0.
+           We need to force amount value to 0 to ensure a correct evaluation of the minimum
+           value later (see fluid_voice_get_lower_boundary_for_attenuation()).
+        */
+        if(((mod_dest->flags1 & FLUID_MOD_CC) == FLUID_MOD_GC) && 
+            (mod_dest->src1 == FLUID_MOD_NONE))
+        {
+            mod_dest->amount = 0;
+        }
+
+        /* *** Dest *** */
+        mod_dest->dest = mod_src->dest; /* index of controlled generator */
+
+        /* *** Amount source *** */
+        if(!fluid_zone_mod_source_import_sfont(&mod_dest->src2, &mod_dest->flags2, mod_src->amtsrc))
+        {
+            /* This shouldn't happen - unknown type!
+             * Deactivate the modulator by setting the amount to 0. */
+            mod_dest->amount = 0;
+        }  
+        /* Note: When secondary source input (src2) is set to General Controller 'No Controller',
+           output will be forced to +1.0 at synthesis time (see fluid_mod_get_value()).
+           That means that this source will behave unipolar only. We need to force the
+           unipolar flag to ensure to ensure a correct evaluation of the minimum
+           value later (see fluid_voice_get_lower_boundary_for_attenuation()).
+        */
+        if(((mod_dest->flags2 & FLUID_MOD_CC) == FLUID_MOD_GC) && 
+            (mod_dest->src2 == FLUID_MOD_NONE))
+        {
+            mod_dest->flags2 &= ~FLUID_MOD_BIPOLAR;
+        }
+
+        /* *** 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)
+        {
+            *mod = mod_dest;
+        }
+        else
+        {
+            fluid_mod_t *last_mod = *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 */
+
+    /* checks and removes invalid modulators in modulators list*/
+    fluid_zone_check_mod(zone_name, mod);
+    return FLUID_OK;
 }
 
 /*
- * fluid_preset_zone_get_inst
+ * fluid_preset_zone_import_sfont
  */
-fluid_inst_t*
-fluid_preset_zone_get_inst(fluid_preset_zone_t* zone)
+int
+fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
 {
-  return zone->inst;
+    /* import the generators */
+    fluid_zone_gen_import_sfont(zone->gen, &zone->range, sfzone);
+
+    if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
+    {
+        SFInst *sfinst = sfzone->instsamp->data;
+
+        zone->inst = find_inst_by_idx(defsfont, sfinst->idx);
+
+        if(zone->inst == NULL)
+        {
+            zone->inst = fluid_inst_import_sfont(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) */
+    return fluid_zone_mod_import_sfont(zone->name, &zone->mod, sfzone);
 }
 
 /*
- * fluid_preset_zone_inside_range
+ * fluid_preset_zone_get_inst
  */
-int
-fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel)
+fluid_inst_t *
+fluid_preset_zone_get_inst(fluid_preset_zone_t *zone)
 {
-  return ((zone->keylo <= key) &&
-         (zone->keyhi >= key) &&
-         (zone->vello <= vel) &&
-         (zone->velhi >= vel));
+    return zone->inst;
 }
 
+
 /***************************************************************
  *
  *                           INST
@@ -1379,136 +1651,168 @@ 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_tinst)
+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(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);
+        /* instrument zone name */
+        FLUID_SNPRINTF(zone_name, sizeof(zone_name), "iz:%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_tinst)
+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_tinst)
+fluid_inst_zone_t *
+fluid_inst_get_global_zone(fluid_inst_t *inst)
 {
-  return inst->global_zone;
+    return inst->global_zone;
 }
 
 /***************************************************************
@@ -1519,257 +1823,111 @@ 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;
+fluid_inst_zone_t *
+new_fluid_inst_zone(char *name)
+{
+    fluid_inst_zone_t *zone = NULL;
+    zone = FLUID_NEW(fluid_inst_zone_t);
 
-  /* 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;
+    if(zone == NULL)
+    {
+        FLUID_LOG(FLUID_ERR, "Out of memory");
+        return NULL;
+    }
+
+    zone->next = NULL;
+    zone->name = FLUID_STRDUP(name);
+
+    if(zone->name == NULL)
+    {
+        FLUID_LOG(FLUID_ERR, "Out of memory");
+        FLUID_FREE(zone);
+        return NULL;
+    }
+
+    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_init(&zone->gen[0], NULL);
+    zone->mod = NULL; /* list of modulators */
+    return zone;
 }
 
 /*
  * delete_fluid_inst_zone
  */
-int
-delete_fluid_inst_zone(fluid_inst_zone_tzone)
+void
+delete_fluid_inst_zone(fluid_inst_zone_t *zone)
 {
-  fluid_mod_t *mod, *tmp;
+    fluid_return_if_fail(zone != NULL);
 
-  mod = zone->mod;
-  while (mod)  /* delete the modulators */
-    {
-      tmp = mod;
-      mod = mod->next;
-      fluid_mod_delete (tmp);
-    }
+    delete_fluid_list_mod(zone->mod);
 
-  if (zone->name) FLUID_FREE (zone->name);
-  FLUID_FREE(zone);
-  return FLUID_OK;
+    FLUID_FREE(zone->name);
+    FLUID_FREE(zone);
 }
 
 /*
  * fluid_inst_zone_next
  */
-fluid_inst_zone_t*
-fluid_inst_zone_next(fluid_inst_zone_tzone)
+fluid_inst_zone_t *
+fluid_inst_zone_next(fluid_inst_zone_t *zone)
 {
-  return zone->next;
+    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;
-    }
+fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont)
+{
+    /* import the generators */
+    fluid_zone_gen_import_sfont(inst_zone->gen, &inst_zone->range, sfzone);
 
-    /* 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;
-    }
+    /* FIXME */
+    /*    if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */
+    /*      FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */
+    /*    } */
 
-    /* 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;
+    /* fixup sample pointer */
+    if((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL))
+    {
+        inst_zone->sample = ((SFSample *)(sfzone->instsamp->data))->fluid_sample;
     }
 
-    r = fluid_list_next(r);
-  } /* foreach modulator */
-  return FLUID_OK;
+    /* Import the modulators (only SF2.1 and higher) */
+    return fluid_zone_mod_import_sfont(inst_zone->name, &inst_zone->mod, sfzone);
 }
 
 /*
  * fluid_inst_zone_get_sample
  */
-fluid_sample_t*
-fluid_inst_zone_get_sample(fluid_inst_zone_tzone)
+fluid_sample_t *
+fluid_inst_zone_get_sample(fluid_inst_zone_t *zone)
 {
-  return zone->sample;
+    return zone->sample;
 }
 
-/*
- * fluid_inst_zone_inside_range
- */
+
 int
-fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel)
+fluid_zone_inside_range(fluid_zone_range_t *range, int key, int vel)
 {
-  return ((zone->keylo <= key) &&
-         (zone->keyhi >= key) &&
-         (zone->vello <= vel) &&
-         (zone->velhi >= vel));
+    /* ignoreInstrumentZone is set in mono legato playing */
+    int ignore_zone = range->ignore;
+
+    /* Reset the 'ignore' request */
+    range->ignore = FALSE;
+
+    return !ignore_zone && ((range->keylo <= key) &&
+                            (range->keyhi >= key) &&
+                            (range->vello <= vel) &&
+                            (range->velhi >= vel));
 }
 
 /***************************************************************
@@ -1777,1656 +1935,241 @@ fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel)
  *                           SAMPLE
  */
 
-/*
- * new_fluid_sample
- */
-fluid_sample_t*
-new_fluid_sample()
-{
-  fluid_sample_t* sample = NULL;
-
-  sample = FLUID_NEW(fluid_sample_t);
-  if (sample == NULL) {
-    FLUID_LOG(FLUID_ERR, "Out of memory");
-    return NULL;
-  }
-
-  memset(sample, 0, sizeof(fluid_sample_t));
-  sample->valid = 1;
-
-  return sample;
-}
-
-/*
- * delete_fluid_sample
- */
-int
-delete_fluid_sample(fluid_sample_t* sample)
-{
-  FLUID_FREE(sample);
-  return FLUID_OK;
-}
-
 /*
  * fluid_sample_in_rom
  */
 int
-fluid_sample_in_rom(fluid_sample_tsample)
+fluid_sample_in_rom(fluid_sample_t *sample)
 {
-  return (sample->sampletype & FLUID_SAMPLETYPE_ROM);
+    return (sample->sampletype & FLUID_SAMPLETYPE_ROM);
 }
 
+
 /*
  * fluid_sample_import_sfont
  */
 int
-fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont)
-{
-  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;
-}
-
-
-
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-/********************************************************************************/
-
-
-
-/*=================================sfload.c========================
-  Borrowed from Smurf SoundFont Editor by Josh Green
-  =================================================================*/
-
-/*
-   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;
-
-  p = (unsigned int *) & idlist;
-  for (i = 0; i < sizeof (idlist) / sizeof (int); i++, p += 1)
-    if (*p == id)
-      return (i + 1);
-
-  return (UNKN_ID);
-}
-
-SFData *
-sfload_file (const char * fname)
+fluid_sample_import_sfont(fluid_sample_t *sample, SFSample *sfsample, fluid_defsfont_t *defsfont)
 {
-  SFData *sf = NULL;
-  FILE *fd;
-  int fsize = 0;
-  int err = FALSE;
+    FLUID_STRCPY(sample->name, sfsample->name);
 
-  if (!(fd = fopen (fname, "rb")))
-    {
-      FLUID_LOG (FLUID_ERR, _("Unable to open file \"%s\""), fname);
-      return (NULL);
-    }
+    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 (!(sf = FLUID_NEW (SFData)))
-    {
-      FLUID_LOG(FLUID_ERR, "Out of memory");
-      fclose(fd);
-      err = TRUE;
-    }
+    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;
 
-  if (!err)
+    if(defsfont->dynamic_samples)
     {
-      memset (sf, 0, sizeof (SFData)); /* zero sfdata */
-      sf->fname = FLUID_STRDUP (fname);        /* copy file name */
-      sf->sffd = fd;
-    }
-
-  /* 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"));
+        sample->notify = dynamic_samples_sample_notify;
     }
-  if (!err && (fsize = ftell (fd)) == -1)
-    {                          /* position = size */
-      err = TRUE;
-      FLUID_LOG (FLUID_ERR, _("Get end of file position failed"));
-    }
-  if (!err)
-    rewind (fd);
-
-  if (!err && !load_body (fsize, sf, fd))
-    err = TRUE;                        /* load the sfont */
 
-  if (err)
+    if(fluid_sample_validate(sample, defsfont->samplesize) == FLUID_FAILED)
     {
-      if (sf)
-       sfont_close (sf);
-      return (NULL);
+        return FLUID_FAILED;
     }
 
-  return (sf);
-}
-
-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);
+    return FLUID_OK;
 }
 
-static int
-read_listchunk (SFChunk * chunk, FILE * fd)
+/* 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)
 {
-  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);
-}
-
-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);
-}
-
-static int
-process_sdta (unsigned int size, SFData * sf, FILE * fd)
-{
-  SFChunk chunk;
-
-  if (size == 0)
-    return (OK);               /* no sample data? */
-
-  /* read sub chunk */
-  READCHUNK (&chunk, fd);
-  size -= 8;
-
-  if (chunkid (chunk.id) != SMPL_ID)
-    return (gerr (ErrCorr,
-       _("Expected SMPL chunk found invalid id instead")));
-
-  /* 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")));
-
-  /* sample data follows */
-  sf->samplepos = ftell (fd);
-
-  /* used in fixup_sample() to check validity of sample headers */
-  sdtachunk_size = chunk.size;
-  sf->samplesize = chunk.size;
-
-  FSKIP (size, fd);
-
-  return (OK);
-}
-
-static int
-pdtahelper (unsigned int expid, unsigned int reclen, SFChunk * chunk,
-  int * size, FILE * fd)
-{
-  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);
-}
-
-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 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);
-}
-
-/* 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);
-}
-
-/* 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);
-}
-
-/* -------------------------------------------------------------------
- * 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);
-}
-
-/* instrument bag loader */
-static int
-load_ibag (int size, SFData * sf, FILE * fd)
-{
-  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);
-}
-
-/* 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_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);
-}
-
-/* sample header loader */
-static int
-load_shdr (unsigned int size, SFData * sf, FILE * fd)
-{
-  unsigned int i;
-  SFSample *p;
-
-  if (size % SFSHDRSIZE || size == 0)  /* size is multiple of SHDR size? */
-    return (gerr (ErrCorr, _("Sample header has invalid size")));
-
-  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);
-    }
-
-  /* load all sample headers */
-  for (i = 0; i < size; i++)
+    if(reason == FLUID_SAMPLE_DONE && sample->preset_count == 0)
     {
-      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;
+        unload_sample(sample);
     }
 
-  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)
-{
-  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);
-}
-
-/* "fixup" (sample # -> sample ptr) sample references in instrument list */
-static int
-fixup_igen (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, *p2, *p3;
-  SFZone *z;
-  int i;
+    fluid_defsfont_t *defsfont;
 
-  p = sf->inst;
-  while (p)
+    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)
     {
-      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);
+        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);
     }
 
-  return (OK);
+    return FLUID_OK;
 }
 
-/* convert sample end, loopstart and loopend to offsets and check if valid */
-static int
-fixup_sample (SFData * sf)
-{
-  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);
-}
-
-/*=================================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
-
-unsigned short badgen[] = { Gen_Unused1, Gen_Unused2, Gen_Unused3, Gen_Unused4,
-  Gen_Reserved1, Gen_Reserved2, Gen_Reserved3, 0
-};
-
-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)
-{
-  fluid_list_t *p, *p2;
 
-  if (sf->sffd)
-    fclose (sf->sffd);
+/* 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_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;
 
-  if (sf->fname)
-    free (sf->fname);
+    defpreset = fluid_preset_get_data(preset);
+    preset_zone = fluid_defpreset_get_zone(defpreset);
 
-  p = sf->info;
-  while (p)
+    while(preset_zone != NULL)
     {
-      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;
+        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 = 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);
+        preset_zone = fluid_preset_zone_next(preset_zone);
     }
-  delete_fluid_list (sf->inst);
-  sf->inst = NULL;
 
-  p = sf->sample;
-  while (p)
+    if(sffile != NULL)
     {
-      FLUID_FREE (p->data);
-      p = fluid_list_next (p);
+        fluid_sffile_close(sffile);
     }
-  delete_fluid_list (sf->sample);
-  sf->sample = NULL;
 
-  FLUID_FREE (sf);
+    return FLUID_OK;
 }
 
-/* free all elements of a zone (Preset or Instrument) */
-void
-sfont_free_zone (SFZone * zone)
+/* 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)
 {
-  fluid_list_t *p;
+    fluid_defpreset_t *defpreset;
+    fluid_preset_zone_t *preset_zone;
+    fluid_inst_t *inst;
+    fluid_inst_zone_t *inst_zone;
+    fluid_sample_t *sample;
 
-  if (!zone)
-    return;
+    defpreset = fluid_preset_get_data(preset);
+    preset_zone = fluid_defpreset_get_zone(defpreset);
 
-  p = zone->gen;
-  while (p)
-    {                          /* Free gen chunks for this zone */
-      if (p->data)
-       FLUID_FREE (p->data);
-      p = fluid_list_next (p);
-    }
-  delete_fluid_list (zone->gen);       /* free genlist */
+    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);
+        }
 
-  p = zone->mod;
-  while (p)
-    {                          /* Free mod 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->mod);       /* free modlist */
-
-  FLUID_FREE (zone);   /* free zone chunk */
-}
 
-/* preset sort function, first by bank, then by preset # */
-int
-sfont_preset_compare_func (void* a, void* b)
-{
-  int aval, bval;
-
-  aval = (int) (((SFPreset *) a)->bank) << 16 | ((SFPreset *) a)->prenum;
-  bval = (int) (((SFPreset *) b)->bank) << 16 | ((SFPreset *) b)->prenum;
-
-  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);
-
-  printf("\n");
+    fluid_list_t *list;
+    fluid_inst_t *inst;
 
-  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);
+        if(inst->source_idx == idx)
+        {
+            return inst;
+        }
     }
-  return (OK);
-}
 
-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;
 }