Path: blob/master/libs/fluidsynth/src/sfloader/fluid_defsfont.c
4396 views
/* FluidSynth - A Software Synthesizer1*2* Copyright (C) 2003 Peter Hanappe and others.3*4* SoundFont file loading code borrowed from Smurf SoundFont Editor5* Copyright (C) 1999-2001 Josh Green6*7* This library is free software; you can redistribute it and/or8* modify it under the terms of the GNU Lesser General Public License9* as published by the Free Software Foundation; either version 2.1 of10* the License, or (at your option) any later version.11*12* This library is distributed in the hope that it will be useful, but13* WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU15* Lesser General Public License for more details.16*17* You should have received a copy of the GNU Lesser General Public18* License along with this library; if not, write to the Free19* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA20* 02110-1301, USA21*/222324#include "fluid_defsfont.h"25#include "fluid_sfont.h"26#include "fluid_sys.h"27#include "fluid_synth.h"28#include "fluid_samplecache.h"29#include "fluid_chan.h"3031/* EMU8k/10k hardware applies this factor to initial attenuation generator values set at preset and32* instrument level in a soundfont. We apply this factor when loading the generator values to stay33* compatible as most existing soundfonts expect exactly this (strange, non-standard) behaviour. */34#define EMU_ATTENUATION_FACTOR (0.4f)3536/* Dynamic sample loading functions */37static int pin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);38static int unpin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);39static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);40static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset);41static void unload_sample(fluid_sample_t *sample);42static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int chan);43static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason);44static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone);45static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx);464748/***************************************************************49*50* SFONT LOADER51*/5253/**54* Creates a default soundfont2 loader that can be used with fluid_synth_add_sfloader().55* By default every synth instance has an initial default soundfont loader instance.56* Calling this function is usually only necessary to load a soundfont from memory, by providing custom callback functions via fluid_sfloader_set_callbacks().57*58* @param settings A settings instance obtained by new_fluid_settings()59* @return A default soundfont2 loader struct60*/61fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings)62{63fluid_sfloader_t *loader;64fluid_return_val_if_fail(settings != NULL, NULL);6566loader = new_fluid_sfloader(fluid_defsfloader_load, delete_fluid_sfloader);6768if(loader == NULL)69{70FLUID_LOG(FLUID_ERR, "Out of memory");71return NULL;72}7374fluid_sfloader_set_data(loader, settings);7576return loader;77}7879fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *filename)80{81fluid_defsfont_t *defsfont;82fluid_sfont_t *sfont;8384defsfont = new_fluid_defsfont(fluid_sfloader_get_data(loader));8586if(defsfont == NULL)87{88return NULL;89}9091sfont = new_fluid_sfont(fluid_defsfont_sfont_get_name,92fluid_defsfont_sfont_get_preset,93fluid_defsfont_sfont_iteration_start,94fluid_defsfont_sfont_iteration_next,95fluid_defsfont_sfont_delete);9697if(sfont == NULL)98{99delete_fluid_defsfont(defsfont);100return NULL;101}102103fluid_sfont_set_data(sfont, defsfont);104105defsfont->sfont = sfont;106107if(fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED)108{109fluid_defsfont_sfont_delete(sfont);110return NULL;111}112113return sfont;114}115116117118/***************************************************************119*120* PUBLIC INTERFACE121*/122123int fluid_defsfont_sfont_delete(fluid_sfont_t *sfont)124{125if(delete_fluid_defsfont(fluid_sfont_get_data(sfont)) != FLUID_OK)126{127return -1;128}129130delete_fluid_sfont(sfont);131return 0;132}133134const char *fluid_defsfont_sfont_get_name(fluid_sfont_t *sfont)135{136return fluid_defsfont_get_name(fluid_sfont_get_data(sfont));137}138139fluid_preset_t *140fluid_defsfont_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum)141{142return fluid_defsfont_get_preset(fluid_sfont_get_data(sfont), bank, prenum);143}144145void fluid_defsfont_sfont_iteration_start(fluid_sfont_t *sfont)146{147fluid_defsfont_iteration_start(fluid_sfont_get_data(sfont));148}149150fluid_preset_t *fluid_defsfont_sfont_iteration_next(fluid_sfont_t *sfont)151{152return fluid_defsfont_iteration_next(fluid_sfont_get_data(sfont));153}154155void fluid_defpreset_preset_delete(fluid_preset_t *preset)156{157fluid_defsfont_t *defsfont;158fluid_defpreset_t *defpreset;159160defsfont = fluid_sfont_get_data(preset->sfont);161defpreset = fluid_preset_get_data(preset);162163if(defsfont)164{165defsfont->preset = fluid_list_remove(defsfont->preset, defpreset);166}167168delete_fluid_defpreset(defpreset);169delete_fluid_preset(preset);170}171172const char *fluid_defpreset_preset_get_name(fluid_preset_t *preset)173{174return fluid_defpreset_get_name(fluid_preset_get_data(preset));175}176177int fluid_defpreset_preset_get_banknum(fluid_preset_t *preset)178{179return fluid_defpreset_get_banknum(fluid_preset_get_data(preset));180}181182int fluid_defpreset_preset_get_num(fluid_preset_t *preset)183{184return fluid_defpreset_get_num(fluid_preset_get_data(preset));185}186187int fluid_defpreset_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth,188int chan, int key, int vel)189{190return fluid_defpreset_noteon(fluid_preset_get_data(preset), synth, chan, key, vel);191}192193194/***************************************************************195*196* SFONT197*/198199/*200* new_fluid_defsfont201*/202fluid_defsfont_t *new_fluid_defsfont(fluid_settings_t *settings)203{204fluid_defsfont_t *defsfont;205206defsfont = FLUID_NEW(fluid_defsfont_t);207208if(defsfont == NULL)209{210FLUID_LOG(FLUID_ERR, "Out of memory");211return NULL;212}213214FLUID_MEMSET(defsfont, 0, sizeof(*defsfont));215216fluid_settings_getint(settings, "synth.lock-memory", &defsfont->mlock);217fluid_settings_getint(settings, "synth.dynamic-sample-loading", &defsfont->dynamic_samples);218219return defsfont;220}221222/*223* delete_fluid_defsfont224*/225int delete_fluid_defsfont(fluid_defsfont_t *defsfont)226{227fluid_list_t *list;228fluid_preset_t *preset;229fluid_sample_t *sample;230231fluid_return_val_if_fail(defsfont != NULL, FLUID_OK);232233/* If we use dynamic sample loading, make sure we unpin any234* pinned presets before removing this soundfont */235if(defsfont->dynamic_samples)236{237for(list = defsfont->preset; list; list = fluid_list_next(list))238{239preset = (fluid_preset_t *)fluid_list_get(list);240unpin_preset_samples(defsfont, preset);241}242}243244/* Check that no samples are currently used */245for(list = defsfont->sample; list; list = fluid_list_next(list))246{247sample = (fluid_sample_t *) fluid_list_get(list);248249if(sample->refcount != 0)250{251return FLUID_FAILED;252}253}254255if(defsfont->filename != NULL)256{257FLUID_FREE(defsfont->filename);258}259260for(list = defsfont->sample; list; list = fluid_list_next(list))261{262sample = (fluid_sample_t *) fluid_list_get(list);263264/* If the sample data pointer is different to the sampledata chunk of265* the soundfont, then the sample has been loaded individually (SF3)266* and needs to be unloaded explicitly. This is safe even if using267* dynamic sample loading, as the sample_unload mechanism sets268* sample->data to NULL after unload. */269if ((sample->data != NULL) && (sample->data != defsfont->sampledata))270{271fluid_samplecache_unload(sample->data);272}273delete_fluid_sample(sample);274}275276if(defsfont->sample)277{278delete_fluid_list(defsfont->sample);279}280281if(defsfont->sampledata != NULL)282{283fluid_samplecache_unload(defsfont->sampledata);284}285286for(list = defsfont->preset; list; list = fluid_list_next(list))287{288preset = (fluid_preset_t *)fluid_list_get(list);289fluid_defpreset_preset_delete(preset);290}291292delete_fluid_list(defsfont->preset);293294for(list = defsfont->inst; list; list = fluid_list_next(list))295{296delete_fluid_inst(fluid_list_get(list));297}298299delete_fluid_list(defsfont->inst);300301FLUID_FREE(defsfont);302return FLUID_OK;303}304305/*306* fluid_defsfont_get_name307*/308const char *fluid_defsfont_get_name(fluid_defsfont_t *defsfont)309{310return defsfont->filename;311}312313/* Load sample data for a single sample from the Soundfont file.314* Returns FLUID_OK on error, otherwise FLUID_FAILED315*/316int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, fluid_sample_t *sample)317{318int num_samples;319unsigned int source_end = sample->source_end;320321/* For uncompressed samples we want to include the 46 zero sample word area following each sample322* in the Soundfont. Otherwise samples with loopend > end, which we have decided not to correct, would323* be corrected after all in fluid_sample_sanitize_loop */324if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS))325{326source_end += 46; /* Length of zero sample word after each sample, according to SF specs */327328/* Safeguard against Soundfonts that are not quite valid and don't include 46 sample words after the329* last sample */330if(source_end >= (defsfont->samplesize / sizeof(short)))331{332source_end = defsfont->samplesize / sizeof(short);333}334}335336num_samples = fluid_samplecache_load(337sfdata, sample->source_start, source_end, sample->sampletype,338defsfont->mlock, &sample->data, &sample->data24);339340if(num_samples < 0)341{342return FLUID_FAILED;343}344345if(num_samples == 0)346{347sample->start = sample->end = 0;348sample->loopstart = sample->loopend = 0;349return FLUID_OK;350}351352/* Ogg Vorbis samples already have loop pointers relative to the individual decompressed sample,353* but SF2 samples are relative to sample chunk start, so they need to be adjusted */354if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS))355{356sample->loopstart = sample->source_loopstart - sample->source_start;357sample->loopend = sample->source_loopend - sample->source_start;358}359360/* As we've just loaded an individual sample into it's own buffer, we need to adjust the start361* and end pointers */362sample->start = 0;363sample->end = num_samples - 1;364365return FLUID_OK;366}367368/* Loads the sample data for all samples from the Soundfont file. For SF2 files, it loads the data in369* one large block. For SF3 files, each compressed sample gets loaded individually.370* Returns FLUID_OK on success, otherwise FLUID_FAILED371*/372int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata)373{374fluid_list_t *list;375fluid_sample_t *sample;376int sf3_file = (sfdata->version.major == 3);377int sample_parsing_result = FLUID_OK;378int invalid_loops_were_sanitized = FALSE;379380/* For SF2 files, we load the sample data in one large block */381if(!sf3_file)382{383int read_samples;384int num_samples = sfdata->samplesize / sizeof(short);385386read_samples = fluid_samplecache_load(sfdata, 0, num_samples - 1, 0, defsfont->mlock,387&defsfont->sampledata, &defsfont->sample24data);388389if(read_samples != num_samples)390{391FLUID_LOG(FLUID_ERR, "Attempted to read %d words of sample data, but got %d instead",392num_samples, read_samples);393return FLUID_FAILED;394}395}396397#pragma omp parallel398#pragma omp single399for(list = defsfont->sample; list; list = fluid_list_next(list))400{401sample = fluid_list_get(list);402403if(sf3_file)404{405/* SF3 samples get loaded individually, as most (or all) of them are in Ogg Vorbis format406* anyway */407#pragma omp task firstprivate(sample,sfdata,defsfont) shared(sample_parsing_result, invalid_loops_were_sanitized) default(none)408{409if(fluid_defsfont_load_sampledata(defsfont, sfdata, sample) == FLUID_FAILED)410{411#pragma omp critical412{413FLUID_LOG(FLUID_ERR, "Failed to load sample '%s'", sample->name);414sample_parsing_result = FLUID_FAILED;415}416}417else418{419int modified = fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short));420if(modified)421{422#pragma omp critical423{424invalid_loops_were_sanitized = TRUE;425}426}427fluid_voice_optimize_sample(sample);428}429}430}431else432{433#pragma omp task firstprivate(sample, defsfont) shared(invalid_loops_were_sanitized) default(none)434{435int modified;436/* Data pointers of SF2 samples point to large sample data block loaded above */437sample->data = defsfont->sampledata;438sample->data24 = defsfont->sample24data;439modified = fluid_sample_sanitize_loop(sample, defsfont->samplesize);440if(modified)441{442#pragma omp critical443{444invalid_loops_were_sanitized = TRUE;445}446}447fluid_voice_optimize_sample(sample);448}449}450}451452if(invalid_loops_were_sanitized)453{454FLUID_LOG(FLUID_WARN,455"Some invalid sample loops were sanitized! If you experience audible glitches, "456"start fluidsynth in verbose mode for detailed information.");457}458459return sample_parsing_result;460}461462/*463* fluid_defsfont_load464*/465int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t *fcbs, const char *file)466{467SFData *sfdata;468fluid_list_t *p;469SFPreset *sfpreset;470SFSample *sfsample;471fluid_sample_t *sample;472fluid_defpreset_t *defpreset = NULL;473474defsfont->filename = FLUID_STRDUP(file);475476if(defsfont->filename == NULL)477{478FLUID_LOG(FLUID_ERR, "Out of memory");479return FLUID_FAILED;480}481482defsfont->fcbs = fcbs;483484/* The actual loading is done in the sfont and sffile files */485sfdata = fluid_sffile_open(file, fcbs);486487if(sfdata == NULL)488{489/* error message already printed */490return FLUID_FAILED;491}492493if(fluid_sffile_parse_presets(sfdata) == FLUID_FAILED)494{495FLUID_LOG(FLUID_ERR, "Couldn't parse presets from soundfont file");496goto err_exit;497}498499/* Keep track of the position and size of the sample data because500it's loaded separately (and might be unoaded/reloaded in future) */501defsfont->samplepos = sfdata->samplepos;502defsfont->samplesize = sfdata->samplesize;503defsfont->sample24pos = sfdata->sample24pos;504defsfont->sample24size = sfdata->sample24size;505506/* Create all samples from sample headers */507p = sfdata->sample;508509while(p != NULL)510{511sfsample = (SFSample *)fluid_list_get(p);512513sample = new_fluid_sample();514515if(sample == NULL)516{517goto err_exit;518}519520if(fluid_sample_import_sfont(sample, sfsample, defsfont) == FLUID_OK)521{522fluid_defsfont_add_sample(defsfont, sample);523}524else525{526delete_fluid_sample(sample);527sample = NULL;528}529530/* Store reference to FluidSynth sample in SFSample for later IZone fixups */531sfsample->fluid_sample = sample;532533p = fluid_list_next(p);534}535536/* If dynamic sample loading is disabled, load all samples in the Soundfont */537if(!defsfont->dynamic_samples)538{539if(fluid_defsfont_load_all_sampledata(defsfont, sfdata) == FLUID_FAILED)540{541FLUID_LOG(FLUID_ERR, "Unable to load all sample data");542goto err_exit;543}544}545546/* Load all the presets */547p = sfdata->preset;548549while(p != NULL)550{551sfpreset = (SFPreset *)fluid_list_get(p);552defpreset = new_fluid_defpreset();553554if(defpreset == NULL)555{556goto err_exit;557}558559if(fluid_defpreset_import_sfont(defpreset, sfpreset, defsfont, sfdata) != FLUID_OK)560{561goto err_exit;562}563564if(fluid_defsfont_add_preset(defsfont, defpreset) == FLUID_FAILED)565{566goto err_exit;567}568569p = fluid_list_next(p);570}571572fluid_sffile_close(sfdata);573574return FLUID_OK;575576err_exit:577fluid_sffile_close(sfdata);578delete_fluid_defpreset(defpreset);579return FLUID_FAILED;580}581582/* fluid_defsfont_add_sample583*584* Add a sample to the SoundFont585*/586int fluid_defsfont_add_sample(fluid_defsfont_t *defsfont, fluid_sample_t *sample)587{588defsfont->sample = fluid_list_prepend(defsfont->sample, sample);589return FLUID_OK;590}591592/* fluid_defsfont_add_preset593*594* Add a preset to the SoundFont595*/596int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *defpreset)597{598fluid_preset_t *preset;599600preset = new_fluid_preset(defsfont->sfont,601fluid_defpreset_preset_get_name,602fluid_defpreset_preset_get_banknum,603fluid_defpreset_preset_get_num,604fluid_defpreset_preset_noteon,605fluid_defpreset_preset_delete);606607if(preset == NULL)608{609return FLUID_FAILED;610}611612if(defsfont->dynamic_samples)613{614preset->notify = dynamic_samples_preset_notify;615}616617fluid_preset_set_data(preset, defpreset);618619defsfont->preset = fluid_list_append(defsfont->preset, preset);620621return FLUID_OK;622}623624/*625* fluid_defsfont_get_preset626*/627fluid_preset_t *fluid_defsfont_get_preset(fluid_defsfont_t *defsfont, int bank, int num)628{629fluid_preset_t *preset;630fluid_list_t *list;631632for(list = defsfont->preset; list != NULL; list = fluid_list_next(list))633{634preset = (fluid_preset_t *)fluid_list_get(list);635636if((fluid_preset_get_banknum(preset) == bank) && (fluid_preset_get_num(preset) == num))637{638return preset;639}640}641642return NULL;643}644645/*646* fluid_defsfont_iteration_start647*/648void fluid_defsfont_iteration_start(fluid_defsfont_t *defsfont)649{650defsfont->preset_iter_cur = defsfont->preset;651}652653/*654* fluid_defsfont_iteration_next655*/656fluid_preset_t *fluid_defsfont_iteration_next(fluid_defsfont_t *defsfont)657{658fluid_preset_t *preset = (fluid_preset_t *)fluid_list_get(defsfont->preset_iter_cur);659660defsfont->preset_iter_cur = fluid_list_next(defsfont->preset_iter_cur);661662return preset;663}664665/***************************************************************666*667* PRESET668*/669670/*671* new_fluid_defpreset672*/673fluid_defpreset_t *674new_fluid_defpreset(void)675{676fluid_defpreset_t *defpreset = FLUID_NEW(fluid_defpreset_t);677678if(defpreset == NULL)679{680FLUID_LOG(FLUID_ERR, "Out of memory");681return NULL;682}683684defpreset->next = NULL;685defpreset->name[0] = 0;686defpreset->bank = 0;687defpreset->num = 0;688defpreset->global_zone = NULL;689defpreset->zone = NULL;690defpreset->pinned = FALSE;691return defpreset;692}693694/*695* delete_fluid_defpreset696*/697void698delete_fluid_defpreset(fluid_defpreset_t *defpreset)699{700fluid_preset_zone_t *zone;701702fluid_return_if_fail(defpreset != NULL);703704delete_fluid_preset_zone(defpreset->global_zone);705defpreset->global_zone = NULL;706707zone = defpreset->zone;708709while(zone != NULL)710{711defpreset->zone = zone->next;712delete_fluid_preset_zone(zone);713zone = defpreset->zone;714}715716FLUID_FREE(defpreset);717}718719int720fluid_defpreset_get_banknum(fluid_defpreset_t *defpreset)721{722return defpreset->bank;723}724725int726fluid_defpreset_get_num(fluid_defpreset_t *defpreset)727{728return defpreset->num;729}730731const char *732fluid_defpreset_get_name(fluid_defpreset_t *defpreset)733{734return defpreset->name;735}736737/*738* fluid_defpreset_next739*/740fluid_defpreset_t *741fluid_defpreset_next(fluid_defpreset_t *defpreset)742{743return defpreset->next;744}745746/*747* Adds global and local modulators list to the voice. This is done in 2 steps:748* - Step 1: Local modulators replace identical global modulators.749* - Step 2: global + local modulators are added to the voice using mode.750*751* Instrument zone list (local/global) must be added using FLUID_VOICE_OVERWRITE.752* Preset zone list (local/global) must be added using FLUID_VOICE_ADD.753*754* @param voice voice instance.755* @param global_mod global list of modulators.756* @param local_mod local list of modulators.757* @param mode Determines how to handle an existing identical modulator.758* #FLUID_VOICE_ADD to add (offset) the modulator amounts,759* #FLUID_VOICE_OVERWRITE to replace the modulator,760*/761static void762fluid_defpreset_noteon_add_mod_to_voice(fluid_voice_t *voice,763fluid_mod_t *global_mod, fluid_mod_t *local_mod,764int mode)765{766fluid_mod_t *mod;767/* list for 'sorting' global/local modulators */768fluid_mod_t *mod_list[FLUID_NUM_MOD];769int mod_list_count, i;770771/* identity_limit_count is the modulator upper limit number to handle with772* existing identical modulators.773* When identity_limit_count is below the actual number of modulators, this774* will restrict identity check to this upper limit,775* This is useful when we know by advance that there is no duplicate with776* modulators at index above this limit. This avoid wasting cpu cycles at777* noteon.778*/779int identity_limit_count;780781/* Step 1: Local modulators replace identical global modulators. */782783/* local (instrument zone/preset zone), modulators: Put them all into a list. */784mod_list_count = 0;785786while(local_mod)787{788/* As modulators number in local_mod list was limited to FLUID_NUM_MOD at789soundfont loading time (fluid_limit_mod_list()), here we don't need790to check if mod_list is full.791*/792mod_list[mod_list_count++] = local_mod;793local_mod = local_mod->next;794}795796/* global (instrument zone/preset zone), modulators.797* Replace modulators with the same definition in the global list:798* (Instrument zone: SF 2.01 page 69, 'bullet' 8)799* (Preset zone: SF 2.01 page 69, second-last bullet).800*801* mod_list contains local modulators. Now we know that there802* is no global modulator identical to another global modulator (this has803* been checked at soundfont loading time). So global modulators804* are only checked against local modulators number.805*/806807/* Restrict identity check to the number of local modulators */808identity_limit_count = mod_list_count;809810while(global_mod)811{812/* 'Identical' global modulators are ignored.813* SF2.01 section 9.5.1814* page 69, 'bullet' 3 defines 'identical'. */815816for(i = 0; i < identity_limit_count; i++)817{818if(fluid_mod_test_identity(global_mod, mod_list[i]))819{820break;821}822}823824/* Finally add the new modulator to the list. */825if(i >= identity_limit_count)826{827/* Although local_mod and global_mod lists was limited to828FLUID_NUM_MOD at soundfont loading time, it is possible that829local + global modulators exceeds FLUID_NUM_MOD.830So, checks if mod_list_count reaches the limit.831*/832if(mod_list_count >= FLUID_NUM_MOD)833{834/* mod_list is full, we silently forget this modulator and835next global modulators. When mod_list will be added to the836voice, a warning will be displayed if the voice list is full.837(see fluid_voice_add_mod_local()).838*/839break;840}841842mod_list[mod_list_count++] = global_mod;843}844845global_mod = global_mod->next;846}847848/* Step 2: global + local modulators are added to the voice using mode. */849850/*851* mod_list contains local and global modulators, we know that:852* - there is no global modulator identical to another global modulator,853* - there is no local modulator identical to another local modulator,854* So these local/global modulators are only checked against855* actual number of voice modulators.856*/857858/* Restrict identity check to the actual number of voice modulators */859/* Actual number of voice modulators : defaults + [instruments] */860identity_limit_count = voice->mod_count;861862for(i = 0; i < mod_list_count; i++)863{864865mod = mod_list[i];866/* in mode FLUID_VOICE_OVERWRITE disabled instruments modulators CANNOT be skipped. */867/* in mode FLUID_VOICE_ADD disabled preset modulators can be skipped. */868869if((mode == FLUID_VOICE_OVERWRITE) || (mod->amount != 0))870{871/* Instrument modulators -supersede- existing (default) modulators.872SF 2.01 page 69, 'bullet' 6 */873874/* Preset modulators -add- to existing instrument modulators.875SF2.01 page 70 first bullet on page */876fluid_voice_add_mod_local(voice, mod, mode, identity_limit_count);877}878}879}880881/*882* fluid_defpreset_noteon883*/884int885fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int chan, int key, int vel)886{887fluid_preset_zone_t *preset_zone, *global_preset_zone;888fluid_inst_t *inst;889fluid_inst_zone_t *inst_zone, *global_inst_zone;890fluid_voice_zone_t *voice_zone;891fluid_list_t *list;892fluid_voice_t *voice;893int tuned_key;894int i;895896/* For detuned channels it might be better to use another key for Soundfont sample selection897* giving better approximations for the pitch than the original key.898* Example: play key 60 on 6370 Hz => use tuned key 64 for sample selection899*900* This feature is only enabled for melodic channels.901* For drum channels we always select Soundfont samples by key numbers.902*/903904if(synth->channel[chan]->channel_type == CHANNEL_TYPE_MELODIC)905{906tuned_key = (int)(fluid_channel_get_key_pitch(synth->channel[chan], key) / 100.0f + 0.5f);907}908else909{910tuned_key = key;911}912913global_preset_zone = fluid_defpreset_get_global_zone(defpreset);914915/* run thru all the zones of this preset */916preset_zone = fluid_defpreset_get_zone(defpreset);917918while(preset_zone != NULL)919{920921/* check if the note falls into the key and velocity range of this922preset */923if(fluid_zone_inside_range(&preset_zone->range, tuned_key, vel))924{925926inst = fluid_preset_zone_get_inst(preset_zone);927global_inst_zone = fluid_inst_get_global_zone(inst);928929/* run thru all the zones of this instrument that could start a voice */930for(list = preset_zone->voice_zone; list != NULL; list = fluid_list_next(list))931{932voice_zone = fluid_list_get(list);933934/* check if the instrument zone is ignored and the note falls into935the key and velocity range of this instrument zone.936An instrument zone must be ignored when its voice is already running937played by a legato passage (see fluid_synth_noteon_monopoly_legato()) */938if(fluid_zone_inside_range(&voice_zone->range, tuned_key, vel))939{940941inst_zone = voice_zone->inst_zone;942943/* this is a good zone. allocate a new synthesis process and initialize it */944voice = fluid_synth_alloc_voice_LOCAL(synth, inst_zone->sample, chan, key, vel, &voice_zone->range);945946if(voice == NULL)947{948return FLUID_FAILED;949}950951952/* Instrument level, generators */953954for(i = 0; i < GEN_LAST; i++)955{956/* SF 2.01 section 9.4 'bullet' 4:957*958* A generator in a local instrument zone supersedes a959* global instrument zone generator. Both cases supersede960* the default generator -> voice_gen_set */961962if(inst_zone->gen[i].flags)963{964fluid_voice_gen_set(voice, i, inst_zone->gen[i].val);965966}967else if((global_inst_zone != NULL) && (global_inst_zone->gen[i].flags))968{969fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val);970971}972else973{974/* The generator has not been defined in this instrument.975* Do nothing, leave it at the default.976*/977}978} /* for all generators */979980/* Adds instrument zone modulators (global and local) to the voice.*/981fluid_defpreset_noteon_add_mod_to_voice(voice,982/* global instrument modulators */983global_inst_zone ? global_inst_zone->mod : NULL,984inst_zone->mod, /* local instrument modulators */985FLUID_VOICE_OVERWRITE); /* mode */986987/* Preset level, generators */988989for(i = 0; i < GEN_LAST; i++)990{991fluid_real_t awe_val;992/* SF 2.01 section 8.5 page 58: If some generators are993encountered at preset level, they should be ignored.994However this check is not necessary when the soundfont995loader has ignored invalid preset generators.996Actually load_pgen()has ignored these invalid preset997generators:998GEN_STARTADDROFS, GEN_ENDADDROFS,999GEN_STARTLOOPADDROFS, GEN_ENDLOOPADDROFS,1000GEN_STARTADDRCOARSEOFS,GEN_ENDADDRCOARSEOFS,1001GEN_STARTLOOPADDRCOARSEOFS,1002GEN_KEYNUM, GEN_VELOCITY,1003GEN_ENDLOOPADDRCOARSEOFS,1004GEN_SAMPLEMODE, GEN_EXCLUSIVECLASS,GEN_OVERRIDEROOTKEY1005*/10061007/* SF 2.01 section 9.4 'bullet' 9: A generator in a1008* local preset zone supersedes a global preset zone1009* generator. The effect is -added- to the destination1010* summing node -> voice_gen_incr */10111012if(preset_zone->gen[i].flags)1013{1014fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val);1015}1016else if((global_preset_zone != NULL) && global_preset_zone->gen[i].flags)1017{1018fluid_voice_gen_incr(voice, i, global_preset_zone->gen[i].val);1019}1020else1021{1022/* The generator has not been defined in this preset1023* Do nothing, leave it unchanged.1024*/1025}10261027/* ...unless the default value has been overridden by an AWE32 NRPN */1028if (fluid_channel_get_override_gen_default(synth->channel[chan], i, &awe_val))1029{1030fluid_voice_gen_set(voice, i, awe_val);1031}1032} /* for all generators */10331034/* Adds preset zone modulators (global and local) to the voice.*/1035fluid_defpreset_noteon_add_mod_to_voice(voice,1036/* global preset modulators */1037global_preset_zone ? global_preset_zone->mod : NULL,1038preset_zone->mod, /* local preset modulators */1039FLUID_VOICE_ADD); /* mode */10401041/* add the synthesis process to the synthesis loop. */1042fluid_synth_start_voice(synth, voice);10431044/* Store the ID of the first voice that was created by this noteon event.1045* Exclusive class may only terminate older voices.1046* That avoids killing voices, which have just been created.1047* (a noteon event can create several voice processes with the same exclusive1048* class - for example when using stereo samples)1049*/1050}1051}1052}10531054preset_zone = fluid_preset_zone_next(preset_zone);1055}10561057return FLUID_OK;1058}10591060/*1061* fluid_defpreset_set_global_zone1062*/1063int1064fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone)1065{1066defpreset->global_zone = zone;1067return FLUID_OK;1068}10691070/*1071* fluid_defpreset_import_sfont1072*/1073int1074fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset,1075SFPreset *sfpreset,1076fluid_defsfont_t *defsfont,1077SFData *sfdata)1078{1079fluid_list_t *p;1080SFZone *sfzone;1081fluid_preset_zone_t *zone;1082int count;1083char zone_name[256];10841085if(FLUID_STRLEN(sfpreset->name) > 0)1086{1087FLUID_STRCPY(defpreset->name, sfpreset->name);1088}1089else1090{1091FLUID_SNPRINTF(defpreset->name, sizeof(defpreset->name), "Bank%d,Pre%d", sfpreset->bank, sfpreset->prenum);1092}10931094defpreset->bank = sfpreset->bank;1095defpreset->num = sfpreset->prenum;1096p = sfpreset->zone;1097count = 0;10981099while(p != NULL)1100{1101sfzone = (SFZone *)fluid_list_get(p);1102FLUID_SNPRINTF(zone_name, sizeof(zone_name), "pz:%s/%d", defpreset->name, count);1103zone = new_fluid_preset_zone(zone_name);11041105if(zone == NULL)1106{1107return FLUID_FAILED;1108}11091110if(fluid_preset_zone_import_sfont(zone, defpreset->global_zone, sfzone, defsfont, sfdata) != FLUID_OK)1111{1112delete_fluid_preset_zone(zone);1113return FLUID_FAILED;1114}11151116if((count == 0) && (fluid_preset_zone_get_inst(zone) == NULL))1117{1118fluid_defpreset_set_global_zone(defpreset, zone);1119}1120else if(fluid_defpreset_add_zone(defpreset, zone) != FLUID_OK)1121{1122delete_fluid_preset_zone(zone);1123return FLUID_FAILED;1124}11251126p = fluid_list_next(p);1127count++;1128}11291130return FLUID_OK;1131}11321133/*1134* fluid_defpreset_add_zone1135*/1136int1137fluid_defpreset_add_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone)1138{1139if(defpreset->zone == NULL)1140{1141zone->next = NULL;1142defpreset->zone = zone;1143}1144else1145{1146zone->next = defpreset->zone;1147defpreset->zone = zone;1148}11491150return FLUID_OK;1151}11521153/*1154* fluid_defpreset_get_zone1155*/1156fluid_preset_zone_t *1157fluid_defpreset_get_zone(fluid_defpreset_t *defpreset)1158{1159return defpreset->zone;1160}11611162/*1163* fluid_defpreset_get_global_zone1164*/1165fluid_preset_zone_t *1166fluid_defpreset_get_global_zone(fluid_defpreset_t *defpreset)1167{1168return defpreset->global_zone;1169}11701171/***************************************************************1172*1173* PRESET_ZONE1174*/11751176/*1177* fluid_preset_zone_next1178*/1179fluid_preset_zone_t *1180fluid_preset_zone_next(fluid_preset_zone_t *zone)1181{1182return zone->next;1183}11841185/*1186* new_fluid_preset_zone1187*/1188fluid_preset_zone_t *1189new_fluid_preset_zone(char *name)1190{1191fluid_preset_zone_t *zone = NULL;1192zone = FLUID_NEW(fluid_preset_zone_t);11931194if(zone == NULL)1195{1196FLUID_LOG(FLUID_ERR, "Out of memory");1197return NULL;1198}11991200zone->next = NULL;1201zone->voice_zone = NULL;1202zone->name = FLUID_STRDUP(name);12031204if(zone->name == NULL)1205{1206FLUID_LOG(FLUID_ERR, "Out of memory");1207FLUID_FREE(zone);1208return NULL;1209}12101211zone->inst = NULL;1212zone->range.keylo = 0;1213zone->range.keyhi = 128;1214zone->range.vello = 0;1215zone->range.velhi = 128;1216zone->range.ignore = FALSE;12171218/* Flag all generators as unused (default, they will be set when they are found1219* in the sound font).1220* This also sets the generator values to default, but that is of no concern here.*/1221fluid_gen_init(&zone->gen[0], NULL);1222zone->mod = NULL; /* list of modulators */1223return zone;1224}12251226/*1227* delete list of modulators.1228*/1229void delete_fluid_list_mod(fluid_mod_t *mod)1230{1231fluid_mod_t *tmp;12321233while(mod) /* delete the modulators */1234{1235tmp = mod;1236mod = mod->next;1237delete_fluid_mod(tmp);1238}1239}12401241/*1242* delete_fluid_preset_zone1243*/1244void1245delete_fluid_preset_zone(fluid_preset_zone_t *zone)1246{1247fluid_list_t *list;12481249fluid_return_if_fail(zone != NULL);12501251delete_fluid_list_mod(zone->mod);12521253for(list = zone->voice_zone; list != NULL; list = fluid_list_next(list))1254{1255FLUID_FREE(fluid_list_get(list));1256}12571258delete_fluid_list(zone->voice_zone);12591260FLUID_FREE(zone->name);1261FLUID_FREE(zone);1262}12631264static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone)1265{1266fluid_inst_zone_t *inst_zone;1267fluid_sample_t *sample;1268fluid_voice_zone_t *voice_zone;1269fluid_zone_range_t *irange;1270fluid_zone_range_t *prange = &preset_zone->range;12711272fluid_return_val_if_fail(preset_zone->inst != NULL, FLUID_FAILED);12731274inst_zone = fluid_inst_get_zone(preset_zone->inst);12751276while(inst_zone != NULL)1277{12781279/* We only create voice ranges for zones that could actually start a voice,1280* i.e. that have a sample and don't point to ROM */1281sample = fluid_inst_zone_get_sample(inst_zone);12821283if((sample == NULL) || fluid_sample_in_rom(sample))1284{1285inst_zone = fluid_inst_zone_next(inst_zone);1286continue;1287}12881289voice_zone = FLUID_NEW(fluid_voice_zone_t);12901291if(voice_zone == NULL)1292{1293FLUID_LOG(FLUID_ERR, "Out of memory");1294return FLUID_FAILED;1295}12961297voice_zone->inst_zone = inst_zone;12981299irange = &inst_zone->range;13001301voice_zone->range.keylo = (prange->keylo > irange->keylo) ? prange->keylo : irange->keylo;1302voice_zone->range.keyhi = (prange->keyhi < irange->keyhi) ? prange->keyhi : irange->keyhi;1303voice_zone->range.vello = (prange->vello > irange->vello) ? prange->vello : irange->vello;1304voice_zone->range.velhi = (prange->velhi < irange->velhi) ? prange->velhi : irange->velhi;1305voice_zone->range.ignore = FALSE;13061307preset_zone->voice_zone = fluid_list_append(preset_zone->voice_zone, voice_zone);13081309inst_zone = fluid_inst_zone_next(inst_zone);1310}13111312return FLUID_OK;1313}13141315/**1316* Checks if modulator mod is identical to another modulator in the list1317* (specs SF 2.0X 7.4, 7.8).1318* @param mod, modulator list.1319* @param name, if not NULL, pointer on a string displayed as warning.1320* @return TRUE if mod is identical to another modulator, FALSE otherwise.1321*/1322static int1323fluid_zone_is_mod_identical(fluid_mod_t *mod, char *name)1324{1325fluid_mod_t *next = mod->next;13261327while(next)1328{1329/* is mod identical to next ? */1330if(fluid_mod_test_identity(mod, next))1331{1332if(name)1333{1334FLUID_LOG(FLUID_WARN, "Ignoring identical modulator %s", name);1335}13361337return TRUE;1338}13391340next = next->next;1341}13421343return FALSE;1344}13451346/**1347* Limits the number of modulators in a modulator list.1348* This is appropriate to internal synthesizer modulators tables1349* which have a fixed size (FLUID_NUM_MOD).1350*1351* @param zone_name, zone name1352* @param list_mod, address of pointer on modulator list.1353*/1354static void fluid_limit_mod_list(char *zone_name, fluid_mod_t **list_mod)1355{1356int mod_idx = 0; /* modulator index */1357fluid_mod_t *prev_mod = NULL; /* previous modulator in list_mod */1358fluid_mod_t *mod = *list_mod; /* first modulator in list_mod */13591360while(mod)1361{1362if((mod_idx + 1) > FLUID_NUM_MOD)1363{1364/* truncation of list_mod */1365if(mod_idx)1366{1367prev_mod->next = NULL;1368}1369else1370{1371*list_mod = NULL;1372}13731374delete_fluid_list_mod(mod);1375FLUID_LOG(FLUID_WARN, "%s, modulators count limited to %d", zone_name,1376FLUID_NUM_MOD);1377break;1378}13791380mod_idx++;1381prev_mod = mod;1382mod = mod->next;1383}1384}13851386/**1387* Checks and remove invalid modulators from a zone modulators list.1388* - checks valid modulator sources (specs SF 2.01 7.4, 7.8, 8.2.1).1389* - checks identical modulators in the list (specs SF 2.01 7.4, 7.8).1390* @param zone_name, zone name.1391* @param list_mod, address of pointer on modulators list.1392*/1393static void1394fluid_zone_check_mod(char *zone_name, fluid_mod_t **list_mod)1395{1396fluid_mod_t *prev_mod = NULL; /* previous modulator in list_mod */1397fluid_mod_t *mod = *list_mod; /* first modulator in list_mod */1398int mod_idx = 0; /* modulator index */13991400while(mod)1401{1402char zone_mod_name[256];1403fluid_mod_t *next = mod->next;14041405/* prepare modulator name: zonename/#modulator */1406FLUID_SNPRINTF(zone_mod_name, sizeof(zone_mod_name), "%s/mod%d", zone_name, mod_idx);14071408/* has mod invalid sources ? */1409if(!fluid_mod_check_sources(mod, zone_mod_name)1410/* or is mod identical to any following modulator ? */1411|| fluid_zone_is_mod_identical(mod, zone_mod_name))1412{1413/* the modulator is useless so we remove it */1414if(prev_mod)1415{1416prev_mod->next = next;1417}1418else1419{1420*list_mod = next;1421}14221423delete_fluid_mod(mod); /* freeing */1424}1425else1426{1427prev_mod = mod;1428}14291430mod = next;1431mod_idx++;1432}14331434/* limits the size of modulators list */1435fluid_limit_mod_list(zone_name, list_mod);1436}14371438/*1439* fluid_zone_gen_import_sfont1440* Imports generators from sfzone to gen and range.1441* @param gen, pointer on destination generators table.1442* @param range, pointer on destination range generators.1443* @param sfzone, pointer on soundfont zone generators.1444*/1445static void1446fluid_zone_gen_import_sfont(fluid_gen_t *gen, fluid_zone_range_t *range, fluid_zone_range_t *global_range, SFZone *sfzone)1447{1448fluid_list_t *r;1449SFGen *sfgen;14501451if(global_range != NULL)1452{1453// All zones are initialized with the default range of 0-127. However, local zones should be superseded by1454// the range of their global zone in case that local zone lacks a GEN_KEYRANGE or GEN_VELRANGE1455// (see issue #1250).1456range->keylo = global_range->keylo;1457range->keyhi = global_range->keyhi;1458range->vello = global_range->vello;1459range->velhi = global_range->velhi;1460}14611462for(r = sfzone->gen; r != NULL;)1463{1464sfgen = (SFGen *)fluid_list_get(r);14651466switch(sfgen->id)1467{1468case GEN_KEYRANGE:1469range->keylo = sfgen->amount.range.lo;1470range->keyhi = sfgen->amount.range.hi;1471break;14721473case GEN_VELRANGE:1474range->vello = sfgen->amount.range.lo;1475range->velhi = sfgen->amount.range.hi;1476break;14771478case GEN_ATTENUATION:1479/* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at1480* preset and instrument level */1481gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;1482gen[sfgen->id].flags = GEN_SET;1483break;14841485case GEN_INSTRUMENT:1486case GEN_SAMPLEID:1487gen[sfgen->id].val = (fluid_real_t) sfgen->amount.uword;1488gen[sfgen->id].flags = GEN_SET;1489break;14901491default:1492gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;1493gen[sfgen->id].flags = GEN_SET;1494break;1495}14961497r = fluid_list_next(r);1498}1499}15001501/*1502* fluid_zone_mod_source_import_sfont1503* Imports source information from sf_source to src and flags.1504* @param src, pointer on destination modulator source.1505* @param flags, pointer on destination modulator flags.1506* @param sf_source, soundfont modulator source.1507* @return return TRUE if success, FALSE if source type is unknown.1508*/1509static int1510fluid_zone_mod_source_import_sfont(unsigned char *src, unsigned char *flags, unsigned short sf_source)1511{1512int type;1513unsigned char flags_dest; /* destination flags */15141515/* sources */1516*src = sf_source & 127; /* index of source, seven-bit value, SF2.01 section 8.2, page 50 */15171518/* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/1519flags_dest = 0;15201521if(sf_source & (1 << 7))1522{1523flags_dest |= FLUID_MOD_CC;1524}1525else1526{1527flags_dest |= FLUID_MOD_GC;1528}15291530/* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/1531if(sf_source & (1 << 8))1532{1533flags_dest |= FLUID_MOD_NEGATIVE;1534}1535else1536{1537flags_dest |= FLUID_MOD_POSITIVE;1538}15391540/* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/1541if(sf_source & (1 << 9))1542{1543flags_dest |= FLUID_MOD_BIPOLAR;1544}1545else1546{1547flags_dest |= FLUID_MOD_UNIPOLAR;1548}15491550/* modulator source types: SF2.01 section 8.2.1 page 52 */1551type = sf_source >> 10;1552type &= 63; /* type is a 6-bit value */15531554if(type == 0)1555{1556flags_dest |= FLUID_MOD_LINEAR;1557}1558else if(type == 1)1559{1560flags_dest |= FLUID_MOD_CONCAVE;1561}1562else if(type == 2)1563{1564flags_dest |= FLUID_MOD_CONVEX;1565}1566else if(type == 3)1567{1568flags_dest |= FLUID_MOD_SWITCH;1569}1570else1571{1572*flags = flags_dest;1573/* This shouldn't happen - unknown type! */1574return FALSE;1575}15761577*flags = flags_dest;1578return TRUE;1579}15801581/*1582* fluid_zone_mod_import_sfont1583* Imports modulators from sfzone to modulators list mod.1584* @param zone_name, zone name.1585* @param mod, address of pointer on modulators list to return.1586* @param sfzone, pointer on soundfont zone.1587* @return FLUID_OK if success, FLUID_FAILED otherwise.1588*/1589static int1590fluid_zone_mod_import_sfont(char *zone_name, fluid_mod_t **mod, SFZone *sfzone)1591{1592fluid_list_t *r;1593int count;15941595/* Import the modulators (only SF2.1 and higher) */1596for(count = 0, r = sfzone->mod; r != NULL; count++)1597{15981599SFMod *mod_src = (SFMod *)fluid_list_get(r);1600fluid_mod_t *mod_dest = new_fluid_mod();16011602if(mod_dest == NULL)1603{1604return FLUID_FAILED;1605}16061607mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/16081609/* *** Amount *** */1610mod_dest->amount = mod_src->amount;16111612/* *** Source *** */1613if(!fluid_zone_mod_source_import_sfont(&mod_dest->src1, &mod_dest->flags1, mod_src->src))1614{1615/* This shouldn't happen - unknown type!1616* Deactivate the modulator by setting the amount to 0. */1617mod_dest->amount = 0;1618}16191620/* *** Dest *** */1621mod_dest->dest = mod_src->dest; /* index of controlled generator */16221623/* *** Amount source *** */1624if(!fluid_zone_mod_source_import_sfont(&mod_dest->src2, &mod_dest->flags2, mod_src->amtsrc))1625{1626/* This shouldn't happen - unknown type!1627* Deactivate the modulator by setting the amount to 0. */1628mod_dest->amount = 0;1629}16301631/**1632* *** Transform Type ***1633* Only 2 types of transform are defined in the sf2 specification.1634*/1635if(mod_src->trans != FLUID_MOD_TRANSFORM_LINEAR && mod_src->trans != FLUID_MOD_TRANSFORM_ABS)1636{1637/* disable the modulator as the transform is invalid */1638mod_dest->amount = 0;1639mod_dest->trans = FLUID_MOD_TRANSFORM_LINEAR;1640}1641else1642{1643mod_dest->trans = mod_src->trans;1644}16451646/* Store the new modulator in the zone The order of modulators1647* will make a difference, at least in an instrument context: The1648* second modulator overwrites the first one, if they only differ1649* in amount. */1650if(count == 0)1651{1652*mod = mod_dest;1653}1654else1655{1656fluid_mod_t *last_mod = *mod;16571658/* Find the end of the list */1659while(last_mod->next != NULL)1660{1661last_mod = last_mod->next;1662}16631664last_mod->next = mod_dest;1665}16661667r = fluid_list_next(r);1668} /* foreach modulator */16691670/* checks and removes invalid modulators in modulators list*/1671fluid_zone_check_mod(zone_name, mod);1672return FLUID_OK;1673}16741675/*1676* fluid_preset_zone_import_sfont1677*/1678int1679fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, fluid_preset_zone_t *global_zone, SFZone *sfzone, fluid_defsfont_t *defsfont, SFData *sfdata)1680{1681/* import the generators */1682fluid_zone_gen_import_sfont(zone->gen, &zone->range, global_zone ? &global_zone->range : NULL, sfzone);16831684if(zone->gen[GEN_INSTRUMENT].flags == GEN_SET)1685{1686int inst_idx = (int) zone->gen[GEN_INSTRUMENT].val;16871688zone->inst = find_inst_by_idx(defsfont, inst_idx);16891690if(zone->inst == NULL)1691{1692zone->inst = fluid_inst_import_sfont(inst_idx, defsfont, sfdata);1693}16941695if(zone->inst == NULL)1696{16971698FLUID_LOG(FLUID_ERR, "Preset zone %s: Invalid instrument reference",1699zone->name);1700return FLUID_FAILED;1701}17021703if(fluid_preset_zone_create_voice_zones(zone) == FLUID_FAILED)1704{1705return FLUID_FAILED;1706}17071708/* We don't need this generator anymore */1709zone->gen[GEN_INSTRUMENT].flags = GEN_UNUSED;1710}17111712/* Import the modulators (only SF2.1 and higher) */1713return fluid_zone_mod_import_sfont(zone->name, &zone->mod, sfzone);1714}17151716/*1717* fluid_preset_zone_get_inst1718*/1719fluid_inst_t *1720fluid_preset_zone_get_inst(fluid_preset_zone_t *zone)1721{1722return zone->inst;1723}172417251726/***************************************************************1727*1728* INST1729*/17301731/*1732* new_fluid_inst1733*/1734fluid_inst_t *1735new_fluid_inst(void)1736{1737fluid_inst_t *inst = FLUID_NEW(fluid_inst_t);17381739if(inst == NULL)1740{1741FLUID_LOG(FLUID_ERR, "Out of memory");1742return NULL;1743}17441745inst->name[0] = 0;1746inst->global_zone = NULL;1747inst->zone = NULL;1748return inst;1749}17501751/*1752* delete_fluid_inst1753*/1754void1755delete_fluid_inst(fluid_inst_t *inst)1756{1757fluid_inst_zone_t *zone;17581759fluid_return_if_fail(inst != NULL);17601761delete_fluid_inst_zone(inst->global_zone);1762inst->global_zone = NULL;17631764zone = inst->zone;17651766while(zone != NULL)1767{1768inst->zone = zone->next;1769delete_fluid_inst_zone(zone);1770zone = inst->zone;1771}17721773FLUID_FREE(inst);1774}17751776/*1777* fluid_inst_set_global_zone1778*/1779int1780fluid_inst_set_global_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone)1781{1782inst->global_zone = zone;1783return FLUID_OK;1784}17851786/*1787* fluid_inst_import_sfont1788*/1789fluid_inst_t *1790fluid_inst_import_sfont(int inst_idx, fluid_defsfont_t *defsfont, SFData *sfdata)1791{1792fluid_list_t *p;1793fluid_list_t *inst_list;1794fluid_inst_t *inst;1795SFZone *sfzone;1796SFInst *sfinst;1797fluid_inst_zone_t *inst_zone;1798char zone_name[256];1799int count;18001801for (inst_list = sfdata->inst; inst_list; inst_list = fluid_list_next(inst_list))1802{1803sfinst = fluid_list_get(inst_list);1804if (sfinst->idx == inst_idx)1805{1806break;1807}1808}1809if (inst_list == NULL)1810{1811return NULL;1812}18131814inst = (fluid_inst_t *) new_fluid_inst();18151816if(inst == NULL)1817{1818FLUID_LOG(FLUID_ERR, "Out of memory");1819return NULL;1820}18211822inst->source_idx = sfinst->idx;18231824p = sfinst->zone;18251826if(FLUID_STRLEN(sfinst->name) > 0)1827{1828FLUID_STRCPY(inst->name, sfinst->name);1829}1830else1831{1832FLUID_STRCPY(inst->name, "<untitled>");1833}18341835count = 0;18361837while(p != NULL)1838{18391840sfzone = (SFZone *)fluid_list_get(p);1841/* instrument zone name */1842FLUID_SNPRINTF(zone_name, sizeof(zone_name), "iz:%s/%d", inst->name, count);18431844inst_zone = new_fluid_inst_zone(zone_name);1845if(inst_zone == NULL)1846{1847FLUID_LOG(FLUID_ERR, "Out of memory");1848goto error;1849}18501851if(fluid_inst_zone_import_sfont(inst_zone, inst->global_zone, sfzone, defsfont, sfdata) != FLUID_OK)1852{1853FLUID_LOG(FLUID_ERR, "fluid_inst_zone_import_sfont() failed for instrument %s", inst->name);1854delete_fluid_inst_zone(inst_zone);1855goto error;1856}18571858if((count == 0) && (fluid_inst_zone_get_sample(inst_zone) == NULL))1859{1860fluid_inst_set_global_zone(inst, inst_zone);18611862}1863else if(fluid_inst_add_zone(inst, inst_zone) != FLUID_OK)1864{1865FLUID_LOG(FLUID_ERR, "fluid_inst_add_zone() failed for instrument %s", inst->name);1866delete_fluid_inst_zone(inst_zone);1867goto error;1868}18691870p = fluid_list_next(p);1871count++;1872}18731874defsfont->inst = fluid_list_append(defsfont->inst, inst);1875return inst;18761877error:1878delete_fluid_inst(inst);1879return NULL;1880}18811882/*1883* fluid_inst_add_zone1884*/1885int1886fluid_inst_add_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone)1887{1888if(inst->zone == NULL)1889{1890zone->next = NULL;1891inst->zone = zone;1892}1893else1894{1895zone->next = inst->zone;1896inst->zone = zone;1897}18981899return FLUID_OK;1900}19011902/*1903* fluid_inst_get_zone1904*/1905fluid_inst_zone_t *1906fluid_inst_get_zone(fluid_inst_t *inst)1907{1908return inst->zone;1909}19101911/*1912* fluid_inst_get_global_zone1913*/1914fluid_inst_zone_t *1915fluid_inst_get_global_zone(fluid_inst_t *inst)1916{1917return inst->global_zone;1918}19191920/***************************************************************1921*1922* INST_ZONE1923*/19241925/*1926* new_fluid_inst_zone1927*/1928fluid_inst_zone_t *1929new_fluid_inst_zone(char *name)1930{1931fluid_inst_zone_t *zone = NULL;1932zone = FLUID_NEW(fluid_inst_zone_t);19331934if(zone == NULL)1935{1936FLUID_LOG(FLUID_ERR, "Out of memory");1937return NULL;1938}19391940zone->next = NULL;1941zone->name = FLUID_STRDUP(name);19421943if(zone->name == NULL)1944{1945FLUID_LOG(FLUID_ERR, "Out of memory");1946FLUID_FREE(zone);1947return NULL;1948}19491950zone->sample = NULL;1951zone->range.keylo = 0;1952zone->range.keyhi = 128;1953zone->range.vello = 0;1954zone->range.velhi = 128;1955zone->range.ignore = FALSE;1956/* Flag the generators as unused.1957* This also sets the generator values to default, but they will be overwritten anyway, if used.*/1958fluid_gen_init(&zone->gen[0], NULL);1959zone->mod = NULL; /* list of modulators */1960return zone;1961}19621963/*1964* delete_fluid_inst_zone1965*/1966void1967delete_fluid_inst_zone(fluid_inst_zone_t *zone)1968{1969fluid_return_if_fail(zone != NULL);19701971delete_fluid_list_mod(zone->mod);19721973FLUID_FREE(zone->name);1974FLUID_FREE(zone);1975}19761977/*1978* fluid_inst_zone_next1979*/1980fluid_inst_zone_t *1981fluid_inst_zone_next(fluid_inst_zone_t *zone)1982{1983return zone->next;1984}19851986/*1987* fluid_inst_zone_import_sfont1988*/1989int1990fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, fluid_inst_zone_t *global_inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont, SFData *sfdata)1991{1992/* import the generators */1993fluid_zone_gen_import_sfont(inst_zone->gen, &inst_zone->range, global_inst_zone ? &global_inst_zone->range : NULL, sfzone);19941995/* FIXME */1996/* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */1997/* FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */1998/* } */19992000if (inst_zone->gen[GEN_SAMPLEID].flags == GEN_SET)2001{2002fluid_list_t *list;2003SFSample *sfsample;2004int sample_idx = (int) inst_zone->gen[GEN_SAMPLEID].val;20052006/* find the SFSample by index */2007for(list = sfdata->sample; list; list = fluid_list_next(list))2008{2009sfsample = fluid_list_get(list);2010if (sfsample->idx == sample_idx)2011{2012break;2013}2014}2015if (list == NULL)2016{2017FLUID_LOG(FLUID_ERR, "Instrument zone '%s': Invalid sample reference",2018inst_zone->name);2019return FLUID_FAILED;2020}20212022inst_zone->sample = sfsample->fluid_sample;20232024/* we don't need this generator anymore, mark it as unused */2025inst_zone->gen[GEN_SAMPLEID].flags = GEN_UNUSED;2026}20272028/* Import the modulators (only SF2.1 and higher) */2029return fluid_zone_mod_import_sfont(inst_zone->name, &inst_zone->mod, sfzone);2030}20312032/*2033* fluid_inst_zone_get_sample2034*/2035fluid_sample_t *2036fluid_inst_zone_get_sample(fluid_inst_zone_t *zone)2037{2038return zone->sample;2039}204020412042int2043fluid_zone_inside_range(fluid_zone_range_t *range, int key, int vel)2044{2045/* ignoreInstrumentZone is set in mono legato playing */2046int ignore_zone = range->ignore;20472048/* Reset the 'ignore' request */2049range->ignore = FALSE;20502051return !ignore_zone && ((range->keylo <= key) &&2052(range->keyhi >= key) &&2053(range->vello <= vel) &&2054(range->velhi >= vel));2055}20562057/***************************************************************2058*2059* SAMPLE2060*/20612062/*2063* fluid_sample_in_rom2064*/2065int2066fluid_sample_in_rom(fluid_sample_t *sample)2067{2068return (sample->sampletype & FLUID_SAMPLETYPE_ROM);2069}207020712072/*2073* fluid_sample_import_sfont2074*/2075int2076fluid_sample_import_sfont(fluid_sample_t *sample, SFSample *sfsample, fluid_defsfont_t *defsfont)2077{2078FLUID_STRCPY(sample->name, sfsample->name);20792080sample->source_start = sfsample->start;2081sample->source_end = (sfsample->end > 0) ? sfsample->end - 1 : 0; /* marks last sample, contrary to SF spec. */2082sample->source_loopstart = sfsample->loopstart;2083sample->source_loopend = sfsample->loopend;20842085sample->start = sample->source_start;2086sample->end = sample->source_end;2087sample->loopstart = sample->source_loopstart;2088sample->loopend = sample->source_loopend;2089sample->samplerate = sfsample->samplerate;2090sample->origpitch = sfsample->origpitch;2091sample->pitchadj = sfsample->pitchadj;2092sample->sampletype = sfsample->sampletype;20932094if(defsfont->dynamic_samples)2095{2096sample->notify = dynamic_samples_sample_notify;2097}20982099if(fluid_sample_validate(sample, defsfont->samplesize) == FLUID_FAILED)2100{2101return FLUID_FAILED;2102}21032104return FLUID_OK;2105}21062107/* Called if a sample is no longer used by a voice. Used by dynamic sample loading2108* to unload a sample that is not used by any loaded presets anymore but couldn't2109* be unloaded straight away because it was still in use by a voice. */2110static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason)2111{2112if(reason == FLUID_SAMPLE_DONE && sample->preset_count == 0)2113{2114unload_sample(sample);2115}21162117return FLUID_OK;2118}21192120/* Called if a preset has been selected for or unselected from a channel. Used by2121* dynamic sample loading to load and unload samples on demand. */2122static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int chan)2123{2124fluid_defsfont_t *defsfont;21252126if(reason == FLUID_PRESET_SELECTED)2127{2128FLUID_LOG(FLUID_DBG, "Selected preset '%s' on channel %d", fluid_preset_get_name(preset), chan);2129defsfont = fluid_sfont_get_data(preset->sfont);2130return load_preset_samples(defsfont, preset);2131}21322133if(reason == FLUID_PRESET_UNSELECTED)2134{2135FLUID_LOG(FLUID_DBG, "Deselected preset '%s' from channel %d", fluid_preset_get_name(preset), chan);2136defsfont = fluid_sfont_get_data(preset->sfont);2137return unload_preset_samples(defsfont, preset);2138}21392140if(reason == FLUID_PRESET_PIN)2141{2142defsfont = fluid_sfont_get_data(preset->sfont);2143return pin_preset_samples(defsfont, preset);2144}21452146if(reason == FLUID_PRESET_UNPIN)2147{2148defsfont = fluid_sfont_get_data(preset->sfont);2149return unpin_preset_samples(defsfont, preset);2150}21512152return FLUID_OK;2153}215421552156static int pin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset)2157{2158fluid_defpreset_t *defpreset;21592160defpreset = fluid_preset_get_data(preset);2161if (defpreset->pinned)2162{2163return FLUID_OK;2164}21652166FLUID_LOG(FLUID_DBG, "Pinning preset '%s'", fluid_preset_get_name(preset));21672168if(load_preset_samples(defsfont, preset) == FLUID_FAILED)2169{2170return FLUID_FAILED;2171}21722173defpreset->pinned = TRUE;21742175return FLUID_OK;2176}217721782179static int unpin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset)2180{2181fluid_defpreset_t *defpreset;21822183defpreset = fluid_preset_get_data(preset);2184if (!defpreset->pinned)2185{2186return FLUID_OK;2187}21882189FLUID_LOG(FLUID_DBG, "Unpinning preset '%s'", fluid_preset_get_name(preset));21902191if(unload_preset_samples(defsfont, preset) == FLUID_FAILED)2192{2193return FLUID_FAILED;2194}21952196defpreset->pinned = FALSE;21972198return FLUID_OK;2199}220022012202/* Walk through all samples used by the passed in preset and make sure that the2203* sample data is loaded for each sample. Used by dynamic sample loading. */2204static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset)2205{2206fluid_defpreset_t *defpreset;2207fluid_preset_zone_t *preset_zone;2208fluid_inst_t *inst;2209fluid_inst_zone_t *inst_zone;2210fluid_sample_t *sample;2211SFData *sffile = NULL;22122213defpreset = fluid_preset_get_data(preset);2214preset_zone = fluid_defpreset_get_zone(defpreset);22152216while(preset_zone != NULL)2217{2218inst = fluid_preset_zone_get_inst(preset_zone);2219inst_zone = fluid_inst_get_zone(inst);22202221while(inst_zone != NULL)2222{2223sample = fluid_inst_zone_get_sample(inst_zone);22242225if((sample != NULL) && (sample->start != sample->end))2226{2227sample->preset_count++;22282229/* If this is the first time this sample has been selected,2230* load the sampledata */2231if(sample->preset_count == 1)2232{2233/* Make sure we have an open Soundfont file. Do this here2234* to avoid having to open the file if no loading is necessary2235* for a preset */2236if(sffile == NULL)2237{2238sffile = fluid_sffile_open(defsfont->filename, defsfont->fcbs);22392240if(sffile == NULL)2241{2242FLUID_LOG(FLUID_ERR, "Unable to open Soundfont file");2243return FLUID_FAILED;2244}2245}22462247if(fluid_defsfont_load_sampledata(defsfont, sffile, sample) == FLUID_OK)2248{2249fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short));2250fluid_voice_optimize_sample(sample);2251}2252else2253{2254FLUID_LOG(FLUID_ERR, "Unable to load sample '%s', disabling", sample->name);2255sample->start = sample->end = 0;2256}2257}2258}22592260inst_zone = fluid_inst_zone_next(inst_zone);2261}22622263preset_zone = fluid_preset_zone_next(preset_zone);2264}22652266if(sffile != NULL)2267{2268fluid_sffile_close(sffile);2269}22702271return FLUID_OK;2272}22732274/* Walk through all samples used by the passed in preset and unload the sample data2275* of each sample that is not used by any selected preset anymore. Used by dynamic2276* sample loading. */2277static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset)2278{2279fluid_defpreset_t *defpreset;2280fluid_preset_zone_t *preset_zone;2281fluid_inst_t *inst;2282fluid_inst_zone_t *inst_zone;2283fluid_sample_t *sample;22842285defpreset = fluid_preset_get_data(preset);2286preset_zone = fluid_defpreset_get_zone(defpreset);22872288while(preset_zone != NULL)2289{2290inst = fluid_preset_zone_get_inst(preset_zone);2291inst_zone = fluid_inst_get_zone(inst);22922293while(inst_zone != NULL)2294{2295sample = fluid_inst_zone_get_sample(inst_zone);22962297if((sample != NULL) && (sample->preset_count > 0))2298{2299sample->preset_count--;23002301/* If the sample is not used by any preset or used by a2302* sounding voice, unload it from the sample cache. If it's2303* still in use by a voice, dynamic_samples_sample_notify will2304* take care of unloading the sample as soon as the voice is2305* finished with it (but only on the next API call). */2306if(sample->preset_count == 0 && sample->refcount == 0)2307{2308unload_sample(sample);2309}2310}23112312inst_zone = fluid_inst_zone_next(inst_zone);2313}23142315preset_zone = fluid_preset_zone_next(preset_zone);2316}23172318return FLUID_OK;2319}23202321/* Unload an unused sample from the samplecache */2322static void unload_sample(fluid_sample_t *sample)2323{2324fluid_return_if_fail(sample != NULL);2325fluid_return_if_fail(sample->data != NULL);2326fluid_return_if_fail(sample->preset_count == 0);2327fluid_return_if_fail(sample->refcount == 0);23282329FLUID_LOG(FLUID_DBG, "Unloading sample '%s'", sample->name);23302331if(fluid_samplecache_unload(sample->data) == FLUID_FAILED)2332{2333FLUID_LOG(FLUID_ERR, "Unable to unload sample '%s'", sample->name);2334}2335else2336{2337sample->data = NULL;2338sample->data24 = NULL;2339}2340}23412342static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx)2343{2344fluid_list_t *list;2345fluid_inst_t *inst;23462347for(list = defsfont->inst; list != NULL; list = fluid_list_next(list))2348{2349inst = fluid_list_get(list);23502351if(inst->source_idx == idx)2352{2353return inst;2354}2355}23562357return NULL;2358}235923602361