Merge pull request #370 from FluidSynth/unique-sfont-insts

Only import Soundfont instruments once
This commit is contained in:
Marcus Weseloh 2018-04-25 22:58:01 +02:00 committed by GitHub
commit 9ad07430ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 137 additions and 41 deletions

View file

@ -39,6 +39,8 @@ static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *pre
static void unload_sample(fluid_sample_t *sample); 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_preset_notify(fluid_preset_t *preset, int reason, int chan);
static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason); 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);
/*************************************************************** /***************************************************************
@ -248,6 +250,11 @@ int delete_fluid_defsfont(fluid_defsfont_t* defsfont)
} }
delete_fluid_list(defsfont->preset); delete_fluid_list(defsfont->preset);
for (list = defsfont->inst; list; list = fluid_list_next(list)) {
delete_fluid_inst(fluid_list_get(list));
}
delete_fluid_list(defsfont->inst);
FLUID_FREE(defsfont); FLUID_FREE(defsfont);
return FLUID_OK; return FLUID_OK;
} }
@ -636,7 +643,8 @@ fluid_defpreset_noteon(fluid_defpreset_t* defpreset, fluid_synth_t* synth, int c
fluid_preset_zone_t *preset_zone, *global_preset_zone; fluid_preset_zone_t *preset_zone, *global_preset_zone;
fluid_inst_t* inst; fluid_inst_t* inst;
fluid_inst_zone_t *inst_zone, *global_inst_zone; fluid_inst_zone_t *inst_zone, *global_inst_zone;
fluid_sample_t* sample; fluid_voice_zone_t *voice_zone;
fluid_list_t *list;
fluid_voice_t* voice; fluid_voice_t* voice;
fluid_mod_t * mod; fluid_mod_t * mod;
fluid_mod_t * mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */ fluid_mod_t * mod_list[FLUID_NUM_MOD]; /* list for 'sorting' preset modulators */
@ -656,24 +664,20 @@ fluid_defpreset_noteon(fluid_defpreset_t* defpreset, fluid_synth_t* synth, int c
inst = fluid_preset_zone_get_inst(preset_zone); inst = fluid_preset_zone_get_inst(preset_zone);
global_inst_zone = fluid_inst_get_global_zone(inst); global_inst_zone = fluid_inst_get_global_zone(inst);
/* run thru all the zones of this instrument */ /* run thru all the zones of this instrument that could start a voice */
inst_zone = fluid_inst_get_zone(inst); for (list = preset_zone->voice_zone; list != NULL; list = fluid_list_next(list)) {
while (inst_zone != NULL) { voice_zone = fluid_list_get(list);
/* 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 instrument zone is ignored and the note falls into /* check if the instrument zone is ignored and the note falls into
the key and velocity range of this instrument zone. the key and velocity range of this instrument zone.
An instrument zone must be ignored when its voice is already running An instrument zone must be ignored when its voice is already running
played by a legato passage (see fluid_synth_noteon_monopoly_legato()) */ played by a legato passage (see fluid_synth_noteon_monopoly_legato()) */
if (fluid_zone_inside_range(&inst_zone->range, key, vel)) { 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 */ /* this is a good zone. allocate a new synthesis process and initialize it */
voice = fluid_synth_alloc_voice_LOCAL(synth, sample, chan, key, vel, &inst_zone->range); voice = fluid_synth_alloc_voice_LOCAL(synth, inst_zone->sample, chan, key, vel, &voice_zone->range);
if (voice == NULL) { if (voice == NULL) {
return FLUID_FAILED; return FLUID_FAILED;
} }
@ -842,7 +846,6 @@ fluid_defpreset_noteon(fluid_defpreset_t* defpreset, fluid_synth_t* synth, int c
*/ */
} }
inst_zone = fluid_inst_zone_next(inst_zone);
} }
} }
preset_zone = fluid_preset_zone_next(preset_zone); preset_zone = fluid_preset_zone_next(preset_zone);
@ -966,6 +969,7 @@ new_fluid_preset_zone(char *name)
return NULL; return NULL;
} }
zone->next = NULL; zone->next = NULL;
zone->voice_zone = NULL;
zone->name = FLUID_STRDUP(name); zone->name = FLUID_STRDUP(name);
if (zone->name == NULL) { if (zone->name == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory"); FLUID_LOG(FLUID_ERR, "Out of memory");
@ -994,6 +998,7 @@ void
delete_fluid_preset_zone(fluid_preset_zone_t* zone) delete_fluid_preset_zone(fluid_preset_zone_t* zone)
{ {
fluid_mod_t *mod, *tmp; fluid_mod_t *mod, *tmp;
fluid_list_t *list;
fluid_return_if_fail(zone != NULL); fluid_return_if_fail(zone != NULL);
@ -1005,11 +1010,62 @@ delete_fluid_preset_zone(fluid_preset_zone_t* zone)
delete_fluid_mod (tmp); delete_fluid_mod (tmp);
} }
for (list = zone->voice_zone; list != NULL; list = fluid_list_next(list))
{
FLUID_FREE(fluid_list_get(list));
}
delete_fluid_list(zone->voice_zone);
FLUID_FREE (zone->name); FLUID_FREE (zone->name);
delete_fluid_inst (zone->inst);
FLUID_FREE(zone); FLUID_FREE(zone);
} }
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;
preset_zone->voice_zone = fluid_list_append(preset_zone->voice_zone, voice_zone);
inst_zone = fluid_inst_zone_next(inst_zone);
}
return FLUID_OK;
}
/* /*
* fluid_preset_zone_import_sfont * fluid_preset_zone_import_sfont
*/ */
@ -1018,6 +1074,7 @@ fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone *sfzone, fluid_
{ {
fluid_list_t *r; fluid_list_t *r;
SFGen* sfgen; SFGen* sfgen;
SFInst* sfinst;
int count; int count;
for (count = 0, r = sfzone->gen; r != NULL; count++) { for (count = 0, r = sfzone->gen; r != NULL; count++) {
sfgen = (SFGen *)fluid_list_get(r); sfgen = (SFGen *)fluid_list_get(r);
@ -1045,14 +1102,22 @@ fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone *sfzone, fluid_
r = fluid_list_next(r); r = fluid_list_next(r);
} }
if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) { if ((sfzone->instsamp != NULL) && (sfzone->instsamp->data != NULL)) {
zone->inst = (fluid_inst_t*) new_fluid_inst(); sfinst = sfzone->instsamp->data;
if (zone->inst == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory"); zone->inst = find_inst_by_idx(defsfont, sfinst->idx);
if (zone->inst == NULL)
{
zone->inst = fluid_inst_import_sfont(zone, sfinst, defsfont);
}
if (zone->inst == NULL)
{
return FLUID_FAILED; return FLUID_FAILED;
} }
if (fluid_inst_import_sfont(zone, zone->inst,
(SFInst *) sfzone->instsamp->data, defsfont) != FLUID_OK) { if (fluid_preset_zone_create_voice_zones(zone) == FLUID_FAILED)
return FLUID_FAILED; {
return FLUID_FAILED;
} }
} }
@ -1256,16 +1321,24 @@ fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone)
/* /*
* fluid_inst_import_sfont * fluid_inst_import_sfont
*/ */
int fluid_inst_t *
fluid_inst_import_sfont(fluid_preset_zone_t* preset_zone, fluid_inst_t* inst, fluid_inst_import_sfont(fluid_preset_zone_t* preset_zone, SFInst *sfinst, fluid_defsfont_t* defsfont)
SFInst *sfinst, fluid_defsfont_t* defsfont)
{ {
fluid_list_t *p; fluid_list_t *p;
fluid_inst_t *inst;
SFZone* sfzone; SFZone* sfzone;
fluid_inst_zone_t* inst_zone; fluid_inst_zone_t* inst_zone;
char zone_name[256]; char zone_name[256];
int count; int count;
inst = (fluid_inst_t*) new_fluid_inst();
if (inst == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
inst->source_idx = sfinst->idx;
p = sfinst->zone; p = sfinst->zone;
if (FLUID_STRLEN(sfinst->name) > 0) { if (FLUID_STRLEN(sfinst->name) > 0) {
FLUID_STRCPY(inst->name, sfinst->name); FLUID_STRCPY(inst->name, sfinst->name);
@ -1281,25 +1354,27 @@ fluid_inst_import_sfont(fluid_preset_zone_t* preset_zone, fluid_inst_t* inst,
inst_zone = new_fluid_inst_zone(zone_name); inst_zone = new_fluid_inst_zone(zone_name);
if (inst_zone == NULL) { if (inst_zone == NULL) {
return FLUID_FAILED; return NULL;
} }
if (fluid_inst_zone_import_sfont(preset_zone, inst_zone, sfzone, defsfont) != FLUID_OK) { if (fluid_inst_zone_import_sfont(inst_zone, sfzone, defsfont) != FLUID_OK) {
delete_fluid_inst_zone(inst_zone); delete_fluid_inst_zone(inst_zone);
return FLUID_FAILED; return NULL;
} }
if ((count == 0) && (fluid_inst_zone_get_sample(inst_zone) == NULL)) { if ((count == 0) && (fluid_inst_zone_get_sample(inst_zone) == NULL)) {
fluid_inst_set_global_zone(inst, inst_zone); fluid_inst_set_global_zone(inst, inst_zone);
} else if (fluid_inst_add_zone(inst, inst_zone) != FLUID_OK) { } else if (fluid_inst_add_zone(inst, inst_zone) != FLUID_OK) {
return FLUID_FAILED; return NULL;
} }
p = fluid_list_next(p); p = fluid_list_next(p);
count++; count++;
} }
return FLUID_OK;
defsfont->inst = fluid_list_append(defsfont->inst, inst);
return inst;
} }
/* /*
@ -1408,8 +1483,7 @@ fluid_inst_zone_next(fluid_inst_zone_t* zone)
* fluid_inst_zone_import_sfont * fluid_inst_zone_import_sfont
*/ */
int int
fluid_inst_zone_import_sfont(fluid_preset_zone_t* preset_zone, fluid_inst_zone_t* inst_zone, fluid_inst_zone_import_sfont(fluid_inst_zone_t* inst_zone, SFZone *sfzone, fluid_defsfont_t* defsfont)
SFZone *sfzone, fluid_defsfont_t* defsfont)
{ {
fluid_list_t *r; fluid_list_t *r;
SFGen* sfgen; SFGen* sfgen;
@ -1441,13 +1515,6 @@ fluid_inst_zone_import_sfont(fluid_preset_zone_t* preset_zone, fluid_inst_zone_t
} }
r = fluid_list_next(r); r = fluid_list_next(r);
} }
/* adjust instrument zone keyrange to integrate preset zone keyrange */
if (preset_zone->range.keylo > inst_zone->range.keylo) inst_zone->range.keylo = preset_zone->range.keylo;
if (preset_zone->range.keyhi < inst_zone->range.keyhi) inst_zone->range.keyhi = preset_zone->range.keyhi;
/* adjust instrument zone to integrate preset zone velrange */
if (preset_zone->range.vello > inst_zone->range.vello) inst_zone->range.vello = preset_zone->range.vello;
if (preset_zone->range.velhi < inst_zone->range.velhi) inst_zone->range.velhi = preset_zone->range.velhi;
/* FIXME */ /* FIXME */
/* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */ /* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */
@ -1829,3 +1896,21 @@ static void unload_sample(fluid_sample_t *sample)
sample->data24 = NULL; sample->data24 = NULL;
} }
} }
static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx)
{
fluid_list_t *list;
fluid_inst_t *inst;
for (list = defsfont->inst; list != NULL; list = fluid_list_next(list))
{
inst = fluid_list_get(list);
if (inst->source_idx == idx)
{
return inst;
}
}
return NULL;
}

View file

@ -53,6 +53,7 @@ typedef struct _fluid_defpreset_t fluid_defpreset_t;
typedef struct _fluid_preset_zone_t fluid_preset_zone_t; typedef struct _fluid_preset_zone_t fluid_preset_zone_t;
typedef struct _fluid_inst_t fluid_inst_t; typedef struct _fluid_inst_t fluid_inst_t;
typedef struct _fluid_inst_zone_t fluid_inst_zone_t; /**< Soundfont Instrument Zone */ typedef struct _fluid_inst_zone_t fluid_inst_zone_t; /**< Soundfont Instrument Zone */
typedef struct _fluid_voice_zone_t fluid_voice_zone_t;
/* defines the velocity and key range for a zone */ /* defines the velocity and key range for a zone */
struct _fluid_zone_range_t struct _fluid_zone_range_t
@ -64,6 +65,13 @@ struct _fluid_zone_range_t
unsigned char ignore; /* set to TRUE for legato playing to ignore this range zone */ unsigned char ignore; /* set to TRUE for legato playing to ignore this range zone */
}; };
/* Stored on a preset zone to keep track of the inst zones that could start a voice
* and their combined preset zone/instument zone ranges */
struct _fluid_voice_zone_t
{
fluid_inst_zone_t *inst_zone;
fluid_zone_range_t range;
};
/* /*
@ -107,6 +115,7 @@ struct _fluid_defsfont_t
fluid_sfont_t *sfont; /* pointer to parent sfont */ fluid_sfont_t *sfont; /* pointer to parent sfont */
fluid_list_t* sample; /* the samples in this soundfont */ fluid_list_t* sample; /* the samples in this soundfont */
fluid_list_t* preset; /* the presets of this soundfont */ fluid_list_t* preset; /* the presets of this soundfont */
fluid_list_t* inst; /* the instruments of this soundfont */
int mlock; /* Should we try memlock (avoid swapping)? */ int mlock; /* Should we try memlock (avoid swapping)? */
int dynamic_samples; /* Enables dynamic sample loading if set */ int dynamic_samples; /* Enables dynamic sample loading if set */
@ -163,6 +172,7 @@ struct _fluid_preset_zone_t
fluid_preset_zone_t* next; fluid_preset_zone_t* next;
char* name; char* name;
fluid_inst_t* inst; fluid_inst_t* inst;
fluid_list_t* voice_zone;
fluid_zone_range_t range; fluid_zone_range_t range;
fluid_gen_t gen[GEN_LAST]; fluid_gen_t gen[GEN_LAST];
fluid_mod_t * mod; /* List of modulators */ fluid_mod_t * mod; /* List of modulators */
@ -180,13 +190,13 @@ fluid_inst_t* fluid_preset_zone_get_inst(fluid_preset_zone_t* zone);
struct _fluid_inst_t struct _fluid_inst_t
{ {
char name[21]; char name[21];
int source_idx; /* Index of instrument in source Soundfont */
fluid_inst_zone_t* global_zone; fluid_inst_zone_t* global_zone;
fluid_inst_zone_t* zone; fluid_inst_zone_t* zone;
}; };
fluid_inst_t* new_fluid_inst(void); fluid_inst_t* new_fluid_inst(void);
int fluid_inst_import_sfont(fluid_preset_zone_t* preset_zone, fluid_inst_t* inst, fluid_inst_t* fluid_inst_import_sfont(fluid_preset_zone_t* preset_zone, SFInst *sfinst, fluid_defsfont_t* defsfont);
SFInst *sfinst, fluid_defsfont_t* defsfont);
void delete_fluid_inst(fluid_inst_t* inst); void delete_fluid_inst(fluid_inst_t* inst);
int fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone); int fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
int fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone); int fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
@ -210,8 +220,7 @@ struct _fluid_inst_zone_t
fluid_inst_zone_t* new_fluid_inst_zone(char* name); fluid_inst_zone_t* new_fluid_inst_zone(char* name);
void delete_fluid_inst_zone(fluid_inst_zone_t* zone); void delete_fluid_inst_zone(fluid_inst_zone_t* zone);
fluid_inst_zone_t* fluid_inst_zone_next(fluid_inst_zone_t* zone); fluid_inst_zone_t* fluid_inst_zone_next(fluid_inst_zone_t* zone);
int fluid_inst_zone_import_sfont(fluid_preset_zone_t* preset_zone, int fluid_inst_zone_import_sfont(fluid_inst_zone_t* inst_zone, SFZone *sfzone, fluid_defsfont_t* defsfont);
fluid_inst_zone_t* inst_zone, SFZone *sfzone, fluid_defsfont_t* defsfont);
fluid_sample_t* fluid_inst_zone_get_sample(fluid_inst_zone_t* zone); fluid_sample_t* fluid_inst_zone_get_sample(fluid_inst_zone_t* zone);

View file

@ -1281,6 +1281,7 @@ static int load_ihdr(SFData *sf, int size)
p = FLUID_NEW(SFInst); p = FLUID_NEW(SFInst);
sf->inst = fluid_list_append(sf->inst, p); sf->inst = fluid_list_append(sf->inst, p);
p->zone = NULL; /* For proper cleanup if fail (fluid_sffile_close) */ p->zone = NULL; /* For proper cleanup if fail (fluid_sffile_close) */
p->idx = i;
READSTR(sf, &p->name); /* Possible read failure ^ */ READSTR(sf, &p->name); /* Possible read failure ^ */
READW(sf, zndx); READW(sf, zndx);

View file

@ -114,6 +114,7 @@ struct _SFSample
struct _SFInst struct _SFInst
{ /* Instrument structure */ { /* Instrument structure */
char name[21]; /* Name of instrument */ char name[21]; /* Name of instrument */
int idx; /* Index of this instrument in the Soundfont */
fluid_list_t *zone; /* list of instrument zones */ fluid_list_t *zone; /* list of instrument zones */
}; };