Path: blob/master/libs/fluidsynth/src/sfloader/fluid_sffile.c
8723 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_sffile.h"25#include "fluid_sfont.h"26#include "fluid_sys.h"2728#if LIBSNDFILE_SUPPORT29#include <sndfile.h>30#endif3132#if LIBINSTPATCH_SUPPORT33#include <libinstpatch/libinstpatch.h>34#endif3536/*=================================sfload.c========================37Borrowed from Smurf SoundFont Editor by Josh Green38=================================================================*/3940/* FOURCC definitions */41#define RIFF_FCC FLUID_FOURCC('R','I','F','F')42#define LIST_FCC FLUID_FOURCC('L','I','S','T')43#define SFBK_FCC FLUID_FOURCC('s','f','b','k')44#define INFO_FCC FLUID_FOURCC('I','N','F','O')45#define SDTA_FCC FLUID_FOURCC('s','d','t','a')46#define PDTA_FCC FLUID_FOURCC('p','d','t','a') /* info/sample/preset */4748#define IFIL_FCC FLUID_FOURCC('i','f','i','l')49#define ISNG_FCC FLUID_FOURCC('i','s','n','g')50#define INAM_FCC FLUID_FOURCC('I','N','A','M')51#define IROM_FCC FLUID_FOURCC('i','r','o','m') /* info ids (1st byte of info strings) */52#define IVER_FCC FLUID_FOURCC('i','v','e','r')53#define ICRD_FCC FLUID_FOURCC('I','C','R','D')54#define IENG_FCC FLUID_FOURCC('I','E','N','G')55#define IPRD_FCC FLUID_FOURCC('I','P','R','D') /* more info ids */56#define ICOP_FCC FLUID_FOURCC('I','C','O','P')57#define ICMT_FCC FLUID_FOURCC('I','C','M','T')58#define ISFT_FCC FLUID_FOURCC('I','S','F','T') /* and yet more info ids */5960#define SNAM_FCC FLUID_FOURCC('s','n','a','m')61#define SMPL_FCC FLUID_FOURCC('s','m','p','l') /* sample ids */62#define PHDR_FCC FLUID_FOURCC('p','h','d','r')63#define PBAG_FCC FLUID_FOURCC('p','b','a','g')64#define PMOD_FCC FLUID_FOURCC('p','m','o','d')65#define PGEN_FCC FLUID_FOURCC('p','g','e','n') /* preset ids */66#define IHDR_FCC FLUID_FOURCC('i','n','s','t')67#define IBAG_FCC FLUID_FOURCC('i','b','a','g')68#define IMOD_FCC FLUID_FOURCC('i','m','o','d')69#define IGEN_FCC FLUID_FOURCC('i','g','e','n') /* instrument ids */70#define SHDR_FCC FLUID_FOURCC('s','h','d','r') /* sample info */71#define SM24_FCC FLUID_FOURCC('s','m','2','4')7273/* Set when the FCC code is unknown */74#define UNKN_ID FLUID_N_ELEMENTS(idlist)7576/*77* This declares a uint32_t array containing the SF2 chunk identifiers.78*/79static const uint32_t idlist[] =80{81RIFF_FCC,82LIST_FCC,83SFBK_FCC,84INFO_FCC,85SDTA_FCC,86PDTA_FCC,8788IFIL_FCC,89ISNG_FCC,90INAM_FCC,91IROM_FCC,92IVER_FCC,93ICRD_FCC,94IENG_FCC,95IPRD_FCC,96ICOP_FCC,97ICMT_FCC,98ISFT_FCC,99100SNAM_FCC,101SMPL_FCC,102PHDR_FCC,103PBAG_FCC,104PMOD_FCC,105PGEN_FCC,106IHDR_FCC,107IBAG_FCC,108IMOD_FCC,109IGEN_FCC,110SHDR_FCC,111SM24_FCC112};113114static const unsigned short invalid_inst_gen[] =115{116GEN_UNUSED1,117GEN_UNUSED2,118GEN_UNUSED3,119GEN_UNUSED4,120GEN_RESERVED1,121GEN_RESERVED2,122GEN_RESERVED3,123GEN_INSTRUMENT,124};125126static const unsigned short invalid_preset_gen[] =127{128GEN_STARTADDROFS,129GEN_ENDADDROFS,130GEN_STARTLOOPADDROFS,131GEN_ENDLOOPADDROFS,132GEN_STARTADDRCOARSEOFS,133GEN_ENDADDRCOARSEOFS,134GEN_STARTLOOPADDRCOARSEOFS,135GEN_KEYNUM,136GEN_VELOCITY,137GEN_ENDLOOPADDRCOARSEOFS,138GEN_SAMPLEMODE,139GEN_EXCLUSIVECLASS,140GEN_OVERRIDEROOTKEY,141GEN_SAMPLEID,142};143144145/* sfont file chunk sizes */146#define SF_PHDR_SIZE (38)147#define SF_BAG_SIZE (4)148#define SF_MOD_SIZE (10)149#define SF_GEN_SIZE (4)150#define SF_IHDR_SIZE (22)151#define SF_SHDR_SIZE (46)152153154#define READCHUNK(sf, var) \155do \156{ \157if (sf->fcbs->fread(var, 8, sf->sffd) == FLUID_FAILED) \158return FALSE; \159((SFChunk *)(var))->size = FLUID_LE32TOH(((SFChunk *)(var))->size); \160} while (0)161162#define READD(sf, var) \163do \164{ \165uint32_t _temp; \166if (sf->fcbs->fread(&_temp, 4, sf->sffd) == FLUID_FAILED) \167return FALSE; \168var = FLUID_LE32TOH(_temp); \169} while (0)170171#define READW(sf, var) \172do \173{ \174uint16_t _temp; \175if (sf->fcbs->fread(&_temp, 2, sf->sffd) == FLUID_FAILED) \176return FALSE; \177var = FLUID_LE16TOH(_temp); \178} while (0)179180#define READID(sf, var) \181do \182{ \183if (sf->fcbs->fread(var, 4, sf->sffd) == FLUID_FAILED) \184return FALSE; \185} while (0)186187#define READSTR(sf, var) \188do \189{ \190if (sf->fcbs->fread(var, 20, sf->sffd) == FLUID_FAILED) \191return FALSE; \192(*var)[20] = '\0'; \193} while (0)194195#define READB(sf, var) \196do \197{ \198if (sf->fcbs->fread(&var, 1, sf->sffd) == FLUID_FAILED) \199return FALSE; \200} while (0)201202#define FSKIP(sf, size) \203do \204{ \205if (sf->fcbs->fseek(sf->sffd, size, SEEK_CUR) == FLUID_FAILED) \206return FALSE; \207} while (0)208209#define FSKIPW(sf) \210do \211{ \212if (sf->fcbs->fseek(sf->sffd, 2, SEEK_CUR) == FLUID_FAILED) \213return FALSE; \214} while (0)215216/* removes and advances a fluid_list_t pointer */217#define SLADVREM(list, item) \218do \219{ \220fluid_list_t *_temp = item; \221item = fluid_list_next(item); \222list = fluid_list_remove_link(list, _temp); \223delete1_fluid_list(_temp); \224} while (0)225226227static int load_header(SFData *sf);228static int load_body(SFData *sf);229static int process_info(SFData *sf, int size);230static int process_sdta(SFData *sf, unsigned int size);231static int process_pdta(SFData *sf, int size);232static int load_phdr(SFData *sf, unsigned int size);233static int load_pbag(SFData *sf, int size);234static int load_pmod(SFData *sf, int size);235static int load_ihdr(SFData *sf, unsigned int size);236static int load_ibag(SFData *sf, int size);237static int load_imod(SFData *sf, int size);238static int load_shdr(SFData *sf, unsigned int size);239240static int chunkid(uint32_t id);241static int read_listchunk(SFData *sf, SFChunk *chunk);242static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size);243static int preset_compare_func(const void *a, const void *b);244static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist);245static int valid_inst_genid(unsigned short genid);246static int valid_preset_genid(unsigned short genid);247248static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data);249static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24);250251/**252* Check if a file is a SoundFont file.253*254* @param filename Path to the file to check255* @return TRUE if it could be a SF2, SF3 or DLS file, FALSE otherwise256*257* If fluidsynth was built with DLS support, this function will also identify DLS files.258*259* @note This function only checks whether header(s) in the RIFF chunk are present.260* A call to fluid_synth_sfload() might still fail.261*/262int fluid_is_soundfont(const char *filename)263{264FILE *fp;265uint32_t fcc;266int retcode = FALSE;267const char* err_msg;268269do270{271if((fp = fluid_file_open(filename, &err_msg)) == NULL)272{273FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): fopen() failed: '%s'", err_msg);274return retcode;275}276277if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)278{279FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): failed to read RIFF chunk id.");280break;281}282283if(fcc != RIFF_FCC)284{285FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): expected RIFF chunk id '0x%04X' but got '0x%04X'.", (unsigned int) RIFF_FCC, (unsigned int)fcc);286break;287}288289if(FLUID_FSEEK(fp, 4, SEEK_CUR))290{291FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): cannot seek +4 bytes.");292break;293}294295if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)296{297FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): failed to read SFBK chunk id.");298break;299}300301retcode = (fcc == SFBK_FCC);302if(retcode)303{304break; // seems to be SF2, stop here305}306#ifdef LIBINSTPATCH_SUPPORT307else308{309IpatchFileHandle *fhandle = ipatch_file_identify_open(filename, NULL);310if(fhandle != NULL)311{312retcode = (ipatch_file_identify(fhandle->file, NULL) == IPATCH_TYPE_DLS_FILE);313ipatch_file_close(fhandle);314}315}316#endif317}318while(0);319320FLUID_FCLOSE(fp);321322return retcode;323}324325/*326* Open a SoundFont file and parse it's contents into a SFData structure.327*328* @param fname filename329* @param fcbs file callback structure330* @return the partially parsed SoundFont as SFData structure or NULL on error331*/332SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs)333{334SFData *sf;335fluid_long_long_t fsize = 0;336337if(!(sf = FLUID_NEW(SFData)))338{339FLUID_LOG(FLUID_ERR, "Out of memory");340return NULL;341}342343FLUID_MEMSET(sf, 0, sizeof(SFData));344345fluid_rec_mutex_init(sf->mtx);346sf->fcbs = fcbs;347348if((sf->sffd = fcbs->fopen(fname)) == NULL)349{350FLUID_LOG(FLUID_ERR, "Unable to open file '%s'", fname);351goto error_exit;352}353354sf->fname = FLUID_STRDUP(fname);355356if(sf->fname == NULL)357{358FLUID_LOG(FLUID_ERR, "Out of memory");359goto error_exit;360}361362/* get size of file by seeking to end */363if(fcbs->fseek(sf->sffd, 0L, SEEK_END) == FLUID_FAILED)364{365FLUID_LOG(FLUID_ERR, "Seek to end of file failed");366goto error_exit;367}368369if((fsize = fcbs->ftell(sf->sffd)) == FLUID_FAILED)370{371FLUID_LOG(FLUID_ERR, "Get end of file position failed");372goto error_exit;373}374375sf->filesize = fsize;376377if(fcbs->fseek(sf->sffd, 0, SEEK_SET) == FLUID_FAILED)378{379FLUID_LOG(FLUID_ERR, "Rewind to start of file failed");380goto error_exit;381}382383if(!load_header(sf))384{385goto error_exit;386}387388return sf;389390error_exit:391fluid_sffile_close(sf);392return NULL;393}394395/*396* Parse all preset information from the soundfont397*398* @return FLUID_OK on success, otherwise FLUID_FAILED399*/400int fluid_sffile_parse_presets(SFData *sf)401{402if(!load_body(sf))403{404return FLUID_FAILED;405}406407return FLUID_OK;408}409410/* Load sample data from the soundfont file411*412* This function will always return the sample data in WAV format. If the sample_type specifies an413* Ogg Vorbis compressed sample, it will be decompressed automatically before returning.414*415* @param sf SFData instance416* @param sample_start index of first sample point in Soundfont sample chunk417* @param sample_end index of last sample point in Soundfont sample chunk418* @param sample_type type of the sample in Soundfont419* @param data pointer to sample data pointer, will point to loaded sample data on success420* @param data24 pointer to 24-bit sample data pointer if 24-bit data present, will point to loaded421* 24-bit sample data on success or NULL if no 24-bit data is present in file422*423* @return The number of sample words in returned buffers or -1 on failure424*/425int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,426int sample_type, short **data, char **data24)427{428int num_samples;429430if(sample_type & FLUID_SAMPLETYPE_OGG_VORBIS)431{432num_samples = fluid_sffile_read_vorbis(sf, sample_start, sample_end, data);433}434else435{436num_samples = fluid_sffile_read_wav(sf, sample_start, sample_end, data, data24);437}438439return num_samples;440}441442/*443* Close a SoundFont file and free the SFData structure.444*445* @param sf pointer to SFData structure446* @param fcbs file callback structure447*/448void fluid_sffile_close(SFData *sf)449{450fluid_list_t *entry;451SFPreset *preset;452SFInst *inst;453454fluid_rec_mutex_destroy(sf->mtx);455if(sf->sffd)456{457sf->fcbs->fclose(sf->sffd);458}459460FLUID_FREE(sf->fname);461462entry = sf->info;463464while(entry)465{466FLUID_FREE(fluid_list_get(entry));467entry = fluid_list_next(entry);468}469470delete_fluid_list(sf->info);471472entry = sf->preset;473474while(entry)475{476preset = (SFPreset *)fluid_list_get(entry);477delete_preset(preset);478entry = fluid_list_next(entry);479}480481delete_fluid_list(sf->preset);482483entry = sf->inst;484485while(entry)486{487inst = (SFInst *)fluid_list_get(entry);488delete_inst(inst);489entry = fluid_list_next(entry);490}491492delete_fluid_list(sf->inst);493494entry = sf->sample;495496while(entry)497{498FLUID_FREE(fluid_list_get(entry));499entry = fluid_list_next(entry);500}501502delete_fluid_list(sf->sample);503504FLUID_FREE(sf);505}506507508/*509* Private functions510*/511512/* sound font file load functions */513static int chunkid(uint32_t id)514{515unsigned int i;516517for(i = 0; i < FLUID_N_ELEMENTS(idlist); i++)518{519if(idlist[i] == id)520{521break;522}523}524525/* Return chunk id or UNKN_ID if not found */526return i;527}528529static int load_header(SFData *sf)530{531SFChunk chunk;532533READCHUNK(sf, &chunk); /* load RIFF chunk */534535if(chunk.id != RIFF_FCC)536{537/* error if not RIFF */538FLUID_LOG(FLUID_ERR, "Not a RIFF file");539return FALSE;540}541542READID(sf, &chunk.id); /* load file ID */543544if(chunk.id != SFBK_FCC)545{546/* error if not SFBK_ID */547FLUID_LOG(FLUID_ERR, "Not a SoundFont file");548return FALSE;549}550551if(chunk.size != sf->filesize - 8)552{553FLUID_LOG(FLUID_ERR, "SoundFont file size mismatch");554return FALSE;555}556557/* Process INFO block */558if(!read_listchunk(sf, &chunk))559{560return FALSE;561}562563if(chunk.id != INFO_FCC)564{565FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting INFO chunk");566return FALSE;567}568569if(!process_info(sf, chunk.size))570{571return FALSE;572}573574/* Process sample chunk */575if(!read_listchunk(sf, &chunk))576{577return FALSE;578}579580if(chunk.id != SDTA_FCC)581{582FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting SAMPLE chunk");583return FALSE;584}585586if(!process_sdta(sf, chunk.size))587{588return FALSE;589}590591/* process HYDRA chunk */592if(!read_listchunk(sf, &chunk))593{594return FALSE;595}596597if(chunk.id != PDTA_FCC)598{599FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting HYDRA chunk");600return FALSE;601}602603sf->hydrapos = sf->fcbs->ftell(sf->sffd);604sf->hydrasize = chunk.size;605606return TRUE;607}608609static int load_body(SFData *sf)610{611if(sf->fcbs->fseek(sf->sffd, sf->hydrapos, SEEK_SET) == FLUID_FAILED)612{613FLUID_LOG(FLUID_ERR, "Failed to seek to HYDRA position");614return FALSE;615}616617if(!process_pdta(sf, sf->hydrasize))618{619return FALSE;620}621622/* sort preset list by bank, preset # */623sf->preset = fluid_list_sort(sf->preset, preset_compare_func);624625return TRUE;626}627628static int read_listchunk(SFData *sf, SFChunk *chunk)629{630READCHUNK(sf, chunk); /* read list chunk */631632if(chunk->id != LIST_FCC) /* error if ! list chunk */633{634FLUID_LOG(FLUID_ERR, "Invalid chunk id in level 0 parse");635return FALSE;636}637638READID(sf, &chunk->id); /* read id string */639chunk->size -= 4;640return TRUE;641}642643static int process_info(SFData *sf, int size)644{645SFChunk chunk;646union647{648char *chr;649uint32_t *fcc;650} item;651unsigned short ver;652653while(size > 0)654{655READCHUNK(sf, &chunk);656size -= 8;657658if(chunk.id == IFIL_FCC)659{660/* sound font version chunk? */661if(chunk.size != 4)662{663FLUID_LOG(FLUID_ERR, "Sound font version info chunk has invalid size");664return FALSE;665}666667READW(sf, ver);668sf->version.major = ver;669READW(sf, ver);670sf->version.minor = ver;671FLUID_LOG(FLUID_DBG, "SF Version: %hu.%hu", sf->version.major, sf->version.minor);672673if(sf->version.major < 2)674{675FLUID_LOG(FLUID_ERR, "Sound font version is %d.%d which is not"676" supported, convert to version 2.0x",677sf->version.major, sf->version.minor);678return FALSE;679}680681if(sf->version.major == 3)682{683#if !LIBSNDFILE_SUPPORT684FLUID_LOG(FLUID_WARN,685"Sound font version is %d.%d but fluidsynth was compiled without"686" support for (v3.x)",687sf->version.major, sf->version.minor);688return FALSE;689#endif690}691else if(sf->version.major > 2)692{693FLUID_LOG(FLUID_WARN,694"Sound font version is %d.%d which is newer than"695" what this version of fluidsynth was designed for (v2.0x)",696sf->version.major, sf->version.minor);697return FALSE;698}699}700else if(chunk.id == IVER_FCC)701{702/* ROM version chunk? */703if(chunk.size != 4)704{705FLUID_LOG(FLUID_ERR, "ROM version info chunk has invalid size");706return FALSE;707}708709READW(sf, ver);710sf->romver.major = ver;711READW(sf, ver);712sf->romver.minor = ver;713FLUID_LOG(FLUID_DBG, "ROM Version: %hu.%hu", sf->version.major, sf->version.minor);714}715else if(chunkid(chunk.id) != UNKN_ID)716{717if((chunk.id != ICMT_FCC && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))718{719FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes",720(char*)&chunk.id, chunk.size);721return FALSE;722}723724/* alloc for chunk fcc and da chunk */725if(!(item.fcc = FLUID_MALLOC(chunk.size + sizeof(uint32_t) + 1)))726{727FLUID_LOG(FLUID_ERR, "Out of memory");728return FALSE;729}730731/* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */732sf->info = fluid_list_append(sf->info, item.fcc);733734/* save chunk fcc and update pointer to data value */735*item.fcc++ = chunk.id;736737if(sf->fcbs->fread(item.chr, chunk.size, sf->sffd) == FLUID_FAILED)738{739return FALSE;740}741742/* force terminate info item */743item.chr[chunk.size] = '\0';744}745else746{747FLUID_LOG(FLUID_ERR, "Invalid chunk id in INFO chunk");748return FALSE;749}750751size -= chunk.size;752}753754if(size < 0)755{756FLUID_LOG(FLUID_ERR, "INFO chunk size mismatch");757return FALSE;758}759760return TRUE;761}762763static int process_sdta(SFData *sf, unsigned int size)764{765SFChunk chunk;766767if(size == 0)768{769return TRUE; /* no sample data? */770}771772/* read sub chunk */773READCHUNK(sf, &chunk);774size -= 8;775776if(chunk.id != SMPL_FCC)777{778FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead");779return FALSE;780}781782/* SDTA chunk may also contain sm24 chunk for 24 bit samples783* (not yet supported), only an error if SMPL chunk size is784* greater than SDTA. */785if(chunk.size > size)786{787FLUID_LOG(FLUID_ERR, "SDTA chunk size mismatch");788return FALSE;789}790791/* sample data follows */792sf->samplepos = sf->fcbs->ftell(sf->sffd);793794/* used to check validity of sample headers */795sf->samplesize = chunk.size;796797FSKIP(sf, chunk.size);798size -= chunk.size;799800if(sf->version.major >= 2 && sf->version.minor >= 4)801{802/* any chance to find another chunk here? */803if(size > 8)804{805/* read sub chunk */806READCHUNK(sf, &chunk);807size -= 8;808809if(chunk.id == SM24_FCC)810{811int sm24size, sdtahalfsize;812813FLUID_LOG(FLUID_DBG, "Found SM24 chunk");814815if(chunk.size > size)816{817FLUID_LOG(FLUID_WARN, "SM24 exceeds SDTA chunk, ignoring SM24");818goto ret; // no error819}820821sdtahalfsize = sf->samplesize / 2;822/* + 1 byte in the case that half the size of smpl chunk is an odd value */823sdtahalfsize += sdtahalfsize % 2;824sm24size = chunk.size;825826if(sdtahalfsize != sm24size)827{828FLUID_LOG(FLUID_WARN, "SM24 not equal to half the size of SMPL chunk (0x%X != "829"0x%X), ignoring SM24",830sm24size, sdtahalfsize);831goto ret; // no error832}833834/* sample data24 follows */835sf->sample24pos = sf->fcbs->ftell(sf->sffd);836sf->sample24size = sm24size;837}838}839}840841ret:842FSKIP(sf, size);843844return TRUE;845}846847static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size)848{849READCHUNK(sf, chunk);850*size -= 8;851852if(chunk->id != expid)853{854FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", (char*)&expid);855return FALSE;856}857858if(chunk->size % reclen) /* valid chunk size? */859{860FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", (char*)&expid, reclen);861return FALSE;862}863864if((*size -= chunk->size) < 0)865{866FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", (char*)&expid);867return FALSE;868}869870return TRUE;871}872873static int process_pdta(SFData *sf, int size)874{875SFChunk chunk;876877if(!pdtahelper(sf, PHDR_FCC, SF_PHDR_SIZE, &chunk, &size))878{879return FALSE;880}881882if(!load_phdr(sf, chunk.size))883{884return FALSE;885}886887if(!pdtahelper(sf, PBAG_FCC, SF_BAG_SIZE, &chunk, &size))888{889return FALSE;890}891892if(!load_pbag(sf, chunk.size))893{894return FALSE;895}896897if(!pdtahelper(sf, PMOD_FCC, SF_MOD_SIZE, &chunk, &size))898{899return FALSE;900}901902if(!load_pmod(sf, chunk.size))903{904return FALSE;905}906907if(!pdtahelper(sf, PGEN_FCC, SF_GEN_SIZE, &chunk, &size))908{909return FALSE;910}911912if(!load_pgen(sf, chunk.size))913{914return FALSE;915}916917if(!pdtahelper(sf, IHDR_FCC, SF_IHDR_SIZE, &chunk, &size))918{919return FALSE;920}921922if(!load_ihdr(sf, chunk.size))923{924return FALSE;925}926927if(!pdtahelper(sf, IBAG_FCC, SF_BAG_SIZE, &chunk, &size))928{929return FALSE;930}931932if(!load_ibag(sf, chunk.size))933{934return FALSE;935}936937if(!pdtahelper(sf, IMOD_FCC, SF_MOD_SIZE, &chunk, &size))938{939return FALSE;940}941942if(!load_imod(sf, chunk.size))943{944return FALSE;945}946947if(!pdtahelper(sf, IGEN_FCC, SF_GEN_SIZE, &chunk, &size))948{949return FALSE;950}951952if(!load_igen(sf, chunk.size))953{954return FALSE;955}956957if(!pdtahelper(sf, SHDR_FCC, SF_SHDR_SIZE, &chunk, &size))958{959return FALSE;960}961962if(!load_shdr(sf, chunk.size))963{964return FALSE;965}966967return TRUE;968}969970/* preset header loader */971static int load_phdr(SFData *sf, unsigned int size)972{973unsigned int i;974int i2;975SFPreset *preset, *prev_preset = NULL;976unsigned short pbag_idx, prev_pbag_idx = 0;977978if(size % SF_PHDR_SIZE || size == 0)979{980FLUID_LOG(FLUID_ERR, "Preset header chunk size is invalid");981return FALSE;982}983984i = size / SF_PHDR_SIZE - 1;985986if(i == 0)987{988/* at least one preset + term record */989FLUID_LOG(FLUID_WARN, "File contains no presets");990FSKIP(sf, SF_PHDR_SIZE);991return TRUE;992}993994for(; i > 0; i--)995{996/* load all preset headers */997if((preset = FLUID_NEW(SFPreset)) == NULL)998{999FLUID_LOG(FLUID_ERR, "Out of memory");1000return FALSE;1001}10021003sf->preset = fluid_list_append(sf->preset, preset);1004preset->zone = NULL; /* In case of failure, fluid_sffile_close can cleanup */1005READSTR(sf, &preset->name); /* possible read failure ^ */1006READW(sf, preset->prenum);1007READW(sf, preset->bank);1008READW(sf, pbag_idx);1009FSKIP(sf, 4); /* library ignored */1010FSKIP(sf, 4); /* genre ignored */1011FSKIP(sf, 4); /* morphology ignored */10121013if(prev_preset)1014{1015/* not first preset? */1016if(pbag_idx < prev_pbag_idx)1017{1018FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");1019return FALSE;1020}10211022i2 = pbag_idx - prev_pbag_idx;10231024while(i2--)1025{1026prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);1027}1028}1029else if(pbag_idx > 0) /* 1st preset, warn if ofs >0 */1030{1031FLUID_LOG(FLUID_WARN, "%d preset zones not referenced, discarding", pbag_idx);1032}10331034prev_preset = preset; /* update preset ptr */1035prev_pbag_idx = pbag_idx;1036}10371038FSKIP(sf, 24);1039READW(sf, pbag_idx); /* Read terminal generator index */1040FSKIP(sf, 12);10411042if(pbag_idx < prev_pbag_idx)1043{1044FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");1045return FALSE;1046}10471048i2 = pbag_idx - prev_pbag_idx;10491050while(i2--)1051{1052prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);1053}10541055return TRUE;1056}10571058/* preset bag loader */1059static int load_pbag(SFData *sf, int size)1060{1061fluid_list_t *preset_list;1062fluid_list_t *zone_list;1063SFZone *z, *pz = NULL;1064unsigned short genndx, modndx;1065unsigned short pgenndx = 0, pmodndx = 0;1066unsigned short i;10671068if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */1069{1070FLUID_LOG(FLUID_ERR, "Preset bag chunk size is invalid");1071return FALSE;1072}10731074preset_list = sf->preset;10751076/* traverse through presets */1077while(preset_list)1078{1079zone_list = ((SFPreset *)(preset_list->data))->zone;10801081/* traverse preset's zones */1082while(zone_list)1083{1084if((size -= SF_BAG_SIZE) < 0)1085{1086FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");1087return FALSE;1088}10891090if((z = FLUID_NEW(SFZone)) == NULL)1091{1092FLUID_LOG(FLUID_ERR, "Out of memory");1093return FALSE;1094}10951096zone_list->data = z;1097z->gen = NULL; /* Init gen and mod before possible failure, */1098z->mod = NULL; /* to ensure proper cleanup (fluid_sffile_close) */1099READW(sf, genndx); /* possible read failure ^ */1100READW(sf, modndx);11011102if(pz)1103{1104/* if not first zone */1105if(genndx < pgenndx)1106{1107FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");1108return FALSE;1109}11101111if(modndx < pmodndx)1112{1113FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");1114return FALSE;1115}11161117i = genndx - pgenndx;11181119while(i--)1120{1121pz->gen = fluid_list_prepend(pz->gen, NULL);1122}11231124i = modndx - pmodndx;11251126while(i--)1127{1128pz->mod = fluid_list_prepend(pz->mod, NULL);1129}1130}11311132pz = z; /* update previous zone ptr */1133pgenndx = genndx; /* update previous zone gen index */1134pmodndx = modndx; /* update previous zone mod index */1135zone_list = fluid_list_next(zone_list);1136}11371138preset_list = fluid_list_next(preset_list);1139}11401141size -= SF_BAG_SIZE;11421143if(size != 0)1144{1145FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");1146return FALSE;1147}11481149READW(sf, genndx);1150READW(sf, modndx);11511152if(!pz)1153{1154if(genndx > 0)1155{1156FLUID_LOG(FLUID_WARN, "No preset generators and terminal index not 0");1157}11581159if(modndx > 0)1160{1161FLUID_LOG(FLUID_WARN, "No preset modulators and terminal index not 0");1162}11631164return TRUE;1165}11661167if(genndx < pgenndx)1168{1169FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");1170return FALSE;1171}11721173if(modndx < pmodndx)1174{1175FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");1176return FALSE;1177}11781179i = genndx - pgenndx;11801181while(i--)1182{1183pz->gen = fluid_list_prepend(pz->gen, NULL);1184}11851186i = modndx - pmodndx;11871188while(i--)1189{1190pz->mod = fluid_list_prepend(pz->mod, NULL);1191}11921193return TRUE;1194}11951196/* preset modulator loader */1197static int load_pmod(SFData *sf, int size)1198{1199fluid_list_t *preset_list;1200fluid_list_t *zone_list;1201fluid_list_t *mod_list;1202SFMod *m;12031204preset_list = sf->preset;12051206while(preset_list)1207{1208/* traverse through all presets */1209zone_list = ((SFPreset *)(preset_list->data))->zone;12101211while(zone_list)1212{1213/* traverse this preset's zones */1214mod_list = ((SFZone *)(zone_list->data))->mod;12151216while(mod_list)1217{1218/* load zone's modulators */1219if((size -= SF_MOD_SIZE) < 0)1220{1221FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");1222return FALSE;1223}12241225if((m = FLUID_NEW(SFMod)) == NULL)1226{1227FLUID_LOG(FLUID_ERR, "Out of memory");1228return FALSE;1229}12301231mod_list->data = m;1232READW(sf, m->src);1233READW(sf, m->dest);1234READW(sf, m->amount);1235READW(sf, m->amtsrc);1236READW(sf, m->trans);1237mod_list = fluid_list_next(mod_list);1238}12391240zone_list = fluid_list_next(zone_list);1241}12421243preset_list = fluid_list_next(preset_list);1244}12451246/*1247If there isn't even a terminal record1248Hmmm, the specs say there should be one, but..1249*/1250if(size == 0)1251{1252return TRUE;1253}12541255size -= SF_MOD_SIZE;12561257if(size != 0)1258{1259FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");1260return FALSE;1261}12621263FSKIP(sf, SF_MOD_SIZE); /* terminal mod */12641265return TRUE;1266}12671268/* -------------------------------------------------------------------1269* preset generator loader1270* generator (per preset) loading rules:1271* Zones with no generators or modulators shall be annihilated1272* Global zone must be 1st zone, discard additional ones (instrumentless zones)1273*1274* generator (per zone) loading rules (in order of decreasing precedence):1275* KeyRange is 1st in list (if exists), else discard1276* if a VelRange exists only preceded by a KeyRange, else discard1277* if a generator follows an instrument discard it1278* if a duplicate generator exists replace previous one1279* ------------------------------------------------------------------- */1280int load_pgen(SFData *sf, int size)1281{1282fluid_list_t *dup;1283fluid_list_t *preset_list;1284fluid_list_t *zone_list;1285fluid_list_t *gen_list;1286SFZone *zone;1287SFGen *g;1288SFPreset *preset;1289SFGenAmount genval;1290unsigned short genid;1291int level, skip, drop, discarded;12921293preset_list = sf->preset;12941295while(preset_list)1296{1297preset = fluid_list_get(preset_list);12981299/* traverse through all presets */1300discarded = FALSE;1301zone_list = preset->zone;13021303/* traverse preset's zones */1304while(zone_list)1305{1306zone = fluid_list_get(zone_list);1307level = 0;1308gen_list = zone->gen;13091310while(gen_list)1311{1312/* load zone's generators */1313dup = NULL;1314skip = FALSE;1315drop = FALSE;13161317if((size -= SF_GEN_SIZE) < 0)1318{1319FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");1320return FALSE;1321}13221323READW(sf, genid);13241325if(genid == GEN_KEYRANGE)1326{1327/* nothing precedes */1328if(level == 0)1329{1330level = 1;1331READB(sf, genval.range.lo);1332READB(sf, genval.range.hi);1333}1334else1335{1336skip = TRUE;1337}1338}1339else if(genid == GEN_VELRANGE)1340{1341/* only KeyRange precedes */1342if(level <= 1)1343{1344level = 2;1345READB(sf, genval.range.lo);1346READB(sf, genval.range.hi);1347}1348else1349{1350skip = TRUE;1351}1352}1353else if(genid == GEN_INSTRUMENT)1354{1355/* inst is last gen */1356level = 3;1357READW(sf, genval.uword);1358}1359else1360{1361level = 2;13621363if(valid_preset_genid(genid))1364{1365/* generator valid? */1366READW(sf, genval.sword);1367dup = find_gen_by_id(genid, zone->gen);1368}1369else1370{1371skip = TRUE;1372}1373}13741375if(!skip)1376{1377if(!dup)1378{1379/* if gen ! dup alloc new */1380if((g = FLUID_NEW(SFGen)) == NULL)1381{1382FLUID_LOG(FLUID_ERR, "Out of memory");1383return FALSE;1384}13851386gen_list->data = g;1387g->id = genid;1388}1389else1390{1391g = (SFGen *)(dup->data); /* ptr to orig gen */1392drop = TRUE;1393}13941395g->amount = genval;1396}1397else1398{1399/* Skip this generator */1400discarded = TRUE;1401drop = TRUE;1402FSKIPW(sf);1403}14041405if(!drop)1406{1407gen_list = fluid_list_next(gen_list); /* next gen */1408}1409else1410{1411SLADVREM(zone->gen, gen_list); /* drop place holder */1412}14131414/* GEN_INSTRUMENT should be the last generator */1415if (level == 3)1416{1417break;1418}14191420} /* generator loop */14211422/* Anything below level 3 means it's a global zone. The global zone1423* should always be the first zone in the list, so discard any1424* other global zones we encounter */1425if(level < 3 && (zone_list != preset->zone))1426{1427/* advance to next zone before deleting the current list element */1428zone_list = fluid_list_next(zone_list);14291430FLUID_LOG(FLUID_WARN, "Preset '%s': Discarding invalid global zone",1431preset->name);1432preset->zone = fluid_list_remove(preset->zone, zone);1433delete_zone(zone);14341435/* we have already advanced the zone_list pointer, so continue with next zone */1436continue;1437}14381439/* All remaining generators are invalid and should be discarded1440* (because they come after an instrument generator) */1441while(gen_list)1442{1443discarded = TRUE;14441445if((size -= SF_GEN_SIZE) < 0)1446{1447FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");1448return FALSE;1449}14501451FSKIP(sf, SF_GEN_SIZE);1452SLADVREM(zone->gen, gen_list);1453}14541455zone_list = fluid_list_next(zone_list);1456}14571458if(discarded)1459{1460FLUID_LOG(FLUID_WARN,1461"Preset '%s': Some invalid generators were discarded",1462preset->name);1463}14641465preset_list = fluid_list_next(preset_list);1466}14671468/* in case there isn't a terminal record */1469if(size == 0)1470{1471return TRUE;1472}14731474size -= SF_GEN_SIZE;14751476if(size != 0)1477{1478FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");1479return FALSE;1480}14811482FSKIP(sf, SF_GEN_SIZE); /* terminal gen */14831484return TRUE;1485}14861487/* instrument header loader */1488static int load_ihdr(SFData *sf, unsigned int size)1489{1490unsigned int i;1491int i2;1492SFInst *inst, *prev_inst = NULL; /* ptr to current & previous instrument */1493unsigned short zndx, pzndx = 0;14941495if(size % SF_IHDR_SIZE || size == 0) /* chunk size is valid? */1496{1497FLUID_LOG(FLUID_ERR, "Instrument header has invalid size");1498return FALSE;1499}15001501size = size / SF_IHDR_SIZE - 1;15021503if(size == 0)1504{1505/* at least one preset + term record */1506FLUID_LOG(FLUID_WARN, "File contains no instruments");1507FSKIP(sf, SF_IHDR_SIZE);1508return TRUE;1509}15101511for(i = 0; i < size; i++)1512{1513/* load all instrument headers */1514if((inst = FLUID_NEW(SFInst)) == NULL)1515{1516FLUID_LOG(FLUID_ERR, "Out of memory");1517return FALSE;1518}15191520sf->inst = fluid_list_append(sf->inst, inst);1521inst->zone = NULL; /* For proper cleanup if fail (fluid_sffile_close) */1522inst->idx = i;1523READSTR(sf, &inst->name); /* Possible read failure ^ */1524READW(sf, zndx);15251526if(prev_inst)1527{1528/* not first instrument? */1529if(zndx < pzndx)1530{1531FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");1532return FALSE;1533}15341535i2 = zndx - pzndx;15361537while(i2--)1538{1539prev_inst->zone = fluid_list_prepend(prev_inst->zone, NULL);1540}1541}1542else if(zndx > 0) /* 1st inst, warn if ofs >0 */1543{1544FLUID_LOG(FLUID_WARN, "%d instrument zones not referenced, discarding", zndx);1545}15461547pzndx = zndx;1548prev_inst = inst; /* update instrument ptr */1549}15501551FSKIP(sf, 20);1552READW(sf, zndx);15531554if(zndx < pzndx)1555{1556FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");1557return FALSE;1558}15591560i2 = zndx - pzndx;15611562while(i2--)1563{1564prev_inst->zone = fluid_list_prepend(prev_inst->zone, NULL);1565}15661567return TRUE;1568}15691570/* instrument bag loader */1571static int load_ibag(SFData *sf, int size)1572{1573fluid_list_t *inst_list;1574fluid_list_t *zone_list;1575SFZone *z, *pz = NULL;1576unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0;1577int i;15781579if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */1580{1581FLUID_LOG(FLUID_ERR, "Instrument bag chunk size is invalid");1582return FALSE;1583}15841585inst_list = sf->inst;15861587while(inst_list)1588{1589/* traverse through inst */1590zone_list = ((SFInst *)(inst_list->data))->zone;15911592while(zone_list)1593{1594/* load this inst's zones */1595if((size -= SF_BAG_SIZE) < 0)1596{1597FLUID_LOG(FLUID_ERR, "Instrument bag chunk size mismatch");1598return FALSE;1599}16001601if((z = FLUID_NEW(SFZone)) == NULL)1602{1603FLUID_LOG(FLUID_ERR, "Out of memory");1604return FALSE;1605}16061607zone_list->data = z;1608z->gen = NULL; /* In case of failure, */1609z->mod = NULL; /* fluid_sffile_close can clean up */1610READW(sf, genndx); /* READW = possible read failure */1611READW(sf, modndx);16121613if(pz)1614{1615/* if not first zone */1616if(genndx < pgenndx)1617{1618FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");1619return FALSE;1620}16211622if(modndx < pmodndx)1623{1624FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");1625return FALSE;1626}16271628i = genndx - pgenndx;16291630while(i--)1631{1632pz->gen = fluid_list_prepend(pz->gen, NULL);1633}16341635i = modndx - pmodndx;16361637while(i--)1638{1639pz->mod = fluid_list_prepend(pz->mod, NULL);1640}1641}16421643pz = z; /* update previous zone ptr */1644pgenndx = genndx;1645pmodndx = modndx;1646zone_list = fluid_list_next(zone_list);1647}16481649inst_list = fluid_list_next(inst_list);1650}16511652size -= SF_BAG_SIZE;16531654if(size != 0)1655{1656FLUID_LOG(FLUID_ERR, "Instrument chunk size mismatch");1657return FALSE;1658}16591660READW(sf, genndx);1661READW(sf, modndx);16621663if(!pz)1664{1665/* in case that all are no zoners */1666if(genndx > 0)1667{1668FLUID_LOG(FLUID_WARN, "No instrument generators and terminal index not 0");1669}16701671if(modndx > 0)1672{1673FLUID_LOG(FLUID_WARN, "No instrument modulators and terminal index not 0");1674}16751676return TRUE;1677}16781679if(genndx < pgenndx)1680{1681FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");1682return FALSE;1683}16841685if(modndx < pmodndx)1686{1687FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");1688return FALSE;1689}16901691i = genndx - pgenndx;16921693while(i--)1694{1695pz->gen = fluid_list_prepend(pz->gen, NULL);1696}16971698i = modndx - pmodndx;16991700while(i--)1701{1702pz->mod = fluid_list_prepend(pz->mod, NULL);1703}17041705return TRUE;1706}17071708/* instrument modulator loader */1709static int load_imod(SFData *sf, int size)1710{1711fluid_list_t *inst_list;1712fluid_list_t *zone_list;1713fluid_list_t *mod_list;1714SFMod *m;17151716inst_list = sf->inst;17171718while(inst_list)1719{1720/* traverse through all inst */1721zone_list = ((SFInst *)(inst_list->data))->zone;17221723while(zone_list)1724{1725/* traverse this inst's zones */1726mod_list = ((SFZone *)(zone_list->data))->mod;17271728while(mod_list)1729{1730/* load zone's modulators */1731if((size -= SF_MOD_SIZE) < 0)1732{1733FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");1734return FALSE;1735}17361737if((m = FLUID_NEW(SFMod)) == NULL)1738{1739FLUID_LOG(FLUID_ERR, "Out of memory");1740return FALSE;1741}17421743mod_list->data = m;1744READW(sf, m->src);1745READW(sf, m->dest);1746READW(sf, m->amount);1747READW(sf, m->amtsrc);1748READW(sf, m->trans);1749mod_list = fluid_list_next(mod_list);1750}17511752zone_list = fluid_list_next(zone_list);1753}17541755inst_list = fluid_list_next(inst_list);1756}17571758/*1759If there isn't even a terminal record1760Hmmm, the specs say there should be one, but..1761*/1762if(size == 0)1763{1764return TRUE;1765}17661767size -= SF_MOD_SIZE;17681769if(size != 0)1770{1771FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");1772return FALSE;1773}17741775FSKIP(sf, SF_MOD_SIZE); /* terminal mod */17761777return TRUE;1778}17791780/* load instrument generators (see load_pgen for loading rules) */1781int load_igen(SFData *sf, int size)1782{1783fluid_list_t *dup;1784fluid_list_t *inst_list;1785fluid_list_t *zone_list;1786fluid_list_t *gen_list;1787SFZone *zone;1788SFGen *g;1789SFInst *inst;1790SFGenAmount genval;1791unsigned short genid;1792int level, skip, drop, discarded;17931794inst_list = sf->inst;17951796/* traverse through all instruments */1797while(inst_list)1798{1799inst = fluid_list_get(inst_list);18001801discarded = FALSE;1802zone_list = inst->zone;18031804/* traverse this instrument's zones */1805while(zone_list)1806{1807zone = fluid_list_get(zone_list);18081809level = 0;1810gen_list = zone->gen;18111812while(gen_list)1813{1814/* load zone's generators */1815dup = NULL;1816skip = FALSE;1817drop = FALSE;18181819if((size -= SF_GEN_SIZE) < 0)1820{1821FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");1822return FALSE;1823}18241825READW(sf, genid);18261827if(genid == GEN_KEYRANGE)1828{1829/* nothing precedes */1830if(level == 0)1831{1832level = 1;1833READB(sf, genval.range.lo);1834READB(sf, genval.range.hi);1835}1836else1837{1838skip = TRUE;1839}1840}1841else if(genid == GEN_VELRANGE)1842{1843/* only KeyRange precedes */1844if(level <= 1)1845{1846level = 2;1847READB(sf, genval.range.lo);1848READB(sf, genval.range.hi);1849}1850else1851{1852skip = TRUE;1853}1854}1855else if(genid == GEN_SAMPLEID)1856{1857/* sample is last gen */1858level = 3;1859READW(sf, genval.uword);1860}1861else1862{1863level = 2;18641865if(valid_inst_genid(genid))1866{1867/* gen valid? */1868READW(sf, genval.sword);1869dup = find_gen_by_id(genid, zone->gen);1870}1871else1872{1873skip = TRUE;1874}1875}18761877if(!skip)1878{1879if(!dup)1880{1881/* if gen ! dup alloc new */1882if((g = FLUID_NEW(SFGen)) == NULL)1883{1884FLUID_LOG(FLUID_ERR, "Out of memory");1885return FALSE;1886}18871888gen_list->data = g;1889g->id = genid;1890}1891else1892{1893g = (SFGen *)(dup->data);1894drop = TRUE;1895}18961897g->amount = genval;1898}1899else1900{1901/* skip this generator */1902discarded = TRUE;1903drop = TRUE;1904FSKIPW(sf);1905}19061907if(!drop)1908{1909gen_list = fluid_list_next(gen_list); /* next gen */1910}1911else1912{1913SLADVREM(zone->gen, gen_list);1914}19151916/* GEN_SAMPLEID should be last generator */1917if (level == 3)1918{1919break;1920}19211922} /* generator loop */19231924/* Anything below level 3 means it's a global zone. The global zone1925* should always be the first zone in the list, so discard any1926* other global zones we encounter */1927if(level < 3 && (zone_list != inst->zone))1928{1929/* advance to next zone before deleting the current list element */1930zone_list = fluid_list_next(zone_list);19311932FLUID_LOG(FLUID_WARN, "Instrument '%s': Discarding invalid global zone",1933inst->name);1934inst->zone = fluid_list_remove(inst->zone, zone);1935delete_zone(zone);19361937/* we have already advanced the zone_list pointer, so continue with next zone */1938continue;1939}19401941/* All remaining generators must be invalid and should be discarded1942* (because they come after a sampleid generator) */1943while(gen_list)1944{1945discarded = TRUE;19461947if((size -= SF_GEN_SIZE) < 0)1948{1949FLUID_LOG(FLUID_ERR, "Instrument generator chunk size mismatch");1950return FALSE;1951}19521953FSKIP(sf, SF_GEN_SIZE);1954SLADVREM(zone->gen, gen_list);1955}19561957zone_list = fluid_list_next(zone_list); /* next zone */1958}19591960if(discarded)1961{1962FLUID_LOG(FLUID_WARN,1963"Instrument '%s': Some invalid generators were discarded",1964inst->name);1965}19661967inst_list = fluid_list_next(inst_list);1968}19691970/* for those non-terminal record cases, grr! */1971if(size == 0)1972{1973return TRUE;1974}19751976size -= SF_GEN_SIZE;19771978if(size != 0)1979{1980FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");1981return FALSE;1982}19831984FSKIP(sf, SF_GEN_SIZE); /* terminal gen */19851986return TRUE;1987}19881989/* sample header loader */1990static int load_shdr(SFData *sf, unsigned int size)1991{1992unsigned int i;1993SFSample *p;19941995if(size % SF_SHDR_SIZE || size == 0) /* size is multiple of SHDR size? */1996{1997FLUID_LOG(FLUID_ERR, "Sample header has invalid size");1998return FALSE;1999}20002001size = size / SF_SHDR_SIZE - 1;20022003if(size == 0)2004{2005/* at least one sample + term record? */2006FLUID_LOG(FLUID_WARN, "File contains no samples");2007FSKIP(sf, SF_SHDR_SIZE);2008return TRUE;2009}20102011/* load all sample headers */2012for(i = 0; i < size; i++)2013{2014if((p = FLUID_NEW(SFSample)) == NULL)2015{2016FLUID_LOG(FLUID_ERR, "Out of memory");2017return FALSE;2018}2019p->idx = i;20202021sf->sample = fluid_list_prepend(sf->sample, p);2022READSTR(sf, &p->name);2023READD(sf, p->start);2024READD(sf, p->end);2025READD(sf, p->loopstart);2026READD(sf, p->loopend);2027READD(sf, p->samplerate);2028READB(sf, p->origpitch);2029READB(sf, p->pitchadj);2030FSKIPW(sf); /* skip sample link */2031READW(sf, p->sampletype);2032}20332034FSKIP(sf, SF_SHDR_SIZE); /* skip terminal shdr */20352036return TRUE;2037}20382039void delete_preset(SFPreset *preset)2040{2041fluid_list_t *entry;2042SFZone *zone;20432044if(!preset)2045{2046return;2047}20482049entry = preset->zone;20502051while(entry)2052{2053zone = (SFZone *)fluid_list_get(entry);2054delete_zone(zone);2055entry = fluid_list_next(entry);2056}20572058delete_fluid_list(preset->zone);20592060FLUID_FREE(preset);2061}20622063void delete_inst(SFInst *inst)2064{2065fluid_list_t *entry;2066SFZone *zone;20672068if(!inst)2069{2070return;2071}20722073entry = inst->zone;20742075while(entry)2076{2077zone = (SFZone *)fluid_list_get(entry);2078delete_zone(zone);2079entry = fluid_list_next(entry);2080}20812082delete_fluid_list(inst->zone);20832084FLUID_FREE(inst);2085}208620872088/* Free all elements of a zone (Preset or Instrument) */2089void delete_zone(SFZone *zone)2090{2091fluid_list_t *entry;20922093if(!zone)2094{2095return;2096}20972098entry = zone->gen;20992100while(entry)2101{2102FLUID_FREE(fluid_list_get(entry));2103entry = fluid_list_next(entry);2104}21052106delete_fluid_list(zone->gen);21072108entry = zone->mod;21092110while(entry)2111{2112FLUID_FREE(fluid_list_get(entry));2113entry = fluid_list_next(entry);2114}21152116delete_fluid_list(zone->mod);21172118FLUID_FREE(zone);2119}21202121/* preset sort function, first by bank, then by preset # */2122static int preset_compare_func(const void *a, const void *b)2123{2124int aval, bval;21252126aval = (int)(((const SFPreset *)a)->bank) << 16 | ((const SFPreset *)a)->prenum;2127bval = (int)(((const SFPreset *)b)->bank) << 16 | ((const SFPreset *)b)->prenum;21282129return (aval - bval);2130}21312132/* Find a generator by its id in the passed in list.2133*2134* @return pointer to SFGen if found, otherwise NULL2135*/2136static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist)2137{2138/* is generator in gen list? */2139fluid_list_t *p;21402141p = genlist;21422143while(p)2144{2145if(p->data == NULL)2146{2147return NULL;2148}21492150if(gen == ((SFGen *)p->data)->id)2151{2152break;2153}21542155p = fluid_list_next(p);2156}21572158return p;2159}21602161/* check validity of instrument generator */2162static int valid_inst_genid(unsigned short genid)2163{2164size_t i;21652166/* OVERRIDEROOTKEY is the last official generator, everything2167* following it are generators internal to FluidSynth and will2168* never appear in a SoundFont file. */2169if(genid > GEN_OVERRIDEROOTKEY)2170{2171return FALSE;2172}21732174for(i = 0; i < FLUID_N_ELEMENTS(invalid_inst_gen); i++)2175{2176if (invalid_inst_gen[i] == genid)2177{2178return FALSE;2179}2180}21812182return TRUE;2183}21842185/* check validity of preset generator */2186static int valid_preset_genid(unsigned short genid)2187{2188size_t i;21892190if(!valid_inst_genid(genid))2191{2192return FALSE;2193}21942195for(i = 0; i < FLUID_N_ELEMENTS(invalid_preset_gen); i++)2196{2197if (invalid_preset_gen[i] == genid)2198{2199return FALSE;2200}2201}22022203return TRUE;2204}220522062207static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24)2208{2209short *loaded_data = NULL;2210char *loaded_data24 = NULL;2211unsigned int num_samples;22122213fluid_return_val_if_fail((end + 1) > start , -1);22142215num_samples = (end + 1) - start;22162217if((start * sizeof(short) > sf->samplesize) || (end * sizeof(short) > sf->samplesize))2218{2219FLUID_LOG(FLUID_ERR, "Sample offsets exceed sample data chunk");2220goto error_exit;2221}22222223fluid_rec_mutex_lock(sf->mtx);22242225/* Load 16-bit sample data */2226if(sf->fcbs->fseek(sf->sffd, sf->samplepos + (start * sizeof(short)), SEEK_SET) == FLUID_FAILED)2227{2228FLUID_LOG(FLUID_ERR, "Failed to seek to sample position");2229goto error_exit_unlock;2230}22312232loaded_data = FLUID_ARRAY(short, num_samples);2233if(loaded_data == NULL)2234{2235FLUID_LOG(FLUID_ERR, "Out of memory");2236goto error_exit_unlock;2237}22382239FLUID_LOG(FLUID_DBG, "ftell(): %llu, fread(): %Id bytes", sf->fcbs->ftell(sf->sffd), num_samples*sizeof(short));2240if(sf->fcbs->fread(loaded_data, num_samples * sizeof(short), sf->sffd) == FLUID_FAILED)2241{2242#if FLUID_VERSION_CHECK(FLUIDSYNTH_VERSION_MAJOR, FLUIDSYNTH_VERSION_MINOR, FLUIDSYNTH_VERSION_MICRO) < FLUID_VERSION_CHECK(2,2,0)2243if((int)(num_samples * sizeof(short)) < 0)2244{2245FLUID_LOG(FLUID_INFO,2246"This SoundFont seems to be bigger than 2GB, which is not supported in this version of fluidsynth. "2247"You need to use at least fluidsynth 2.2.0");2248}2249#endif2250FLUID_LOG(FLUID_ERR, "Failed to read sample data");2251goto error_exit_unlock;2252}22532254fluid_rec_mutex_unlock(sf->mtx);22552256/* If this machine is big endian, byte swap the 16 bit samples */2257if(FLUID_IS_BIG_ENDIAN)2258{2259unsigned int i;22602261for(i = 0; i < num_samples; i++)2262{2263loaded_data[i] = FLUID_LE16TOH(loaded_data[i]);2264}2265}22662267*data = loaded_data;22682269/* Optionally load additional 8 bit sample data for 24-bit support. Any failures while loading2270* the 24-bit sample data will be logged as errors but won't prevent the sample reading to2271* fail, as sound output is still possible with the 16-bit sample data. */2272if(sf->sample24pos)2273{2274if((start > sf->sample24size) || (end > sf->sample24size))2275{2276FLUID_LOG(FLUID_ERR, "Sample offsets exceed 24-bit sample data chunk");2277goto error24_exit;2278}22792280loaded_data24 = FLUID_ARRAY(char, num_samples);2281if(loaded_data24 == NULL)2282{2283FLUID_LOG(FLUID_ERR, "Out of memory reading 24-bit sample data");2284goto error24_exit;2285}22862287fluid_rec_mutex_lock(sf->mtx);22882289if(sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED)2290{2291FLUID_LOG(FLUID_ERR, "Failed to seek position for 24-bit sample data in data file");2292goto error24_exit_unlock;2293}22942295if(sf->fcbs->fread(loaded_data24, num_samples, sf->sffd) == FLUID_FAILED)2296{2297FLUID_LOG(FLUID_ERR, "Failed to read 24-bit sample data");2298goto error24_exit_unlock;2299}23002301fluid_rec_mutex_unlock(sf->mtx);2302}23032304*data24 = loaded_data24;23052306return num_samples;23072308error24_exit_unlock:2309fluid_rec_mutex_unlock(sf->mtx);2310error24_exit:2311FLUID_LOG(FLUID_WARN, "Ignoring 24-bit sample data, sound quality might suffer");2312FLUID_FREE(loaded_data24);2313*data24 = NULL;2314return num_samples;23152316error_exit_unlock:2317fluid_rec_mutex_unlock(sf->mtx);2318error_exit:2319FLUID_FREE(loaded_data);2320FLUID_FREE(loaded_data24);2321return -1;2322}232323242325/* Ogg Vorbis loading and decompression */2326#if LIBSNDFILE_SUPPORT23272328/* Virtual file access routines to allow loading individually compressed2329* samples from the Soundfont sample data chunk using the file callbacks2330* passing in during opening of the file */2331typedef struct _sfvio_data_t2332{2333SFData *sffile;2334sf_count_t start; /* start byte offset of compressed data */2335sf_count_t end; /* end byte offset of compressed data */2336sf_count_t offset; /* current virtual file offset from start byte offset */23372338} sfvio_data_t;23392340static sf_count_t sfvio_get_filelen(void *user_data)2341{2342sfvio_data_t *data = user_data;23432344return (data->end + 1) - data->start;2345}23462347static sf_count_t sfvio_seek(sf_count_t offset, int whence, void *user_data)2348{2349sfvio_data_t *data = user_data;2350SFData *sf = data->sffile;2351sf_count_t new_offset;23522353switch(whence)2354{2355case SEEK_SET:2356new_offset = offset;2357break;23582359case SEEK_CUR:2360new_offset = data->offset + offset;2361break;23622363case SEEK_END:2364new_offset = sfvio_get_filelen(user_data) + offset;2365break;23662367default:2368goto fail; /* proper error handling not possible?? */2369}23702371new_offset += data->start;2372fluid_rec_mutex_lock(sf->mtx);2373if (data->start <= new_offset && new_offset <= data->end &&2374sf->fcbs->fseek(sf->sffd, new_offset, SEEK_SET) != FLUID_FAILED)2375{2376data->offset = new_offset - data->start;2377}2378fluid_rec_mutex_unlock(sf->mtx);23792380fail:2381return data->offset;2382}23832384static sf_count_t sfvio_read(void *ptr, sf_count_t count, void *user_data)2385{2386sfvio_data_t *data = user_data;2387SFData *sf = data->sffile;2388sf_count_t remain;23892390remain = sfvio_get_filelen(user_data) - data->offset;23912392if(count > remain)2393{2394count = remain;2395}23962397if(count == 0)2398{2399return count;2400}24012402fluid_rec_mutex_lock(sf->mtx);2403if (sf->fcbs->fseek(sf->sffd, data->start + data->offset, SEEK_SET) == FLUID_FAILED)2404{2405FLUID_LOG(FLUID_ERR, "This should never happen: fseek failed in sfvoid_read()");2406count = 0;2407}2408else2409{2410if (sf->fcbs->fread(ptr, count, sf->sffd) == FLUID_FAILED)2411{2412FLUID_LOG(FLUID_ERR, "Failed to read compressed sample data");2413count = 0;2414}2415}2416fluid_rec_mutex_unlock(sf->mtx);24172418data->offset += count;24192420return count;2421}24222423static sf_count_t sfvio_tell(void *user_data)2424{2425sfvio_data_t *data = user_data;24262427return data->offset;2428}24292430/**2431* Read Ogg Vorbis compressed data from the Soundfont and decompress it, returning the number of samples2432* in the decompressed WAV. Only 16-bit mono samples are supported.2433*2434* Note that this function takes byte indices for start and end source data. The sample headers in SF32435* files use byte indices, so those pointers can be passed directly to this function.2436*2437* This function uses a virtual file structure in order to read the Ogg Vorbis2438* data from arbitrary locations in the source file.2439*/2440static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)2441{2442SNDFILE *sndfile;2443SF_INFO sfinfo;2444SF_VIRTUAL_IO sfvio =2445{2446sfvio_get_filelen,2447sfvio_seek,2448sfvio_read,2449NULL,2450sfvio_tell2451};2452sfvio_data_t sfdata;2453short *wav_data = NULL;24542455if((start_byte > sf->samplesize) || (end_byte > sf->samplesize))2456{2457FLUID_LOG(FLUID_ERR, "Ogg Vorbis data offsets exceed sample data chunk");2458return -1;2459}24602461// Initialize file position indicator and SF_INFO structure2462sfdata.sffile = sf;2463sfdata.start = sf->samplepos + start_byte;2464sfdata.end = sf->samplepos + end_byte;2465sfdata.offset = -1;24662467/* Seek to sfdata.start, the beginning of Ogg Vorbis data in Soundfont */2468sfvio_seek(0, SEEK_SET, &sfdata);2469if (sfdata.offset != 0)2470{2471FLUID_LOG(FLUID_ERR, "Failed to seek to compressed sample position");2472return -1;2473}24742475FLUID_MEMSET(&sfinfo, 0, sizeof(sfinfo));24762477// Open sample as a virtual file2478sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, &sfdata);24792480if(!sndfile)2481{2482FLUID_LOG(FLUID_ERR, "sf_open_virtual(): %s", sf_strerror(sndfile));2483return -1;2484}24852486// Empty sample2487if(sfinfo.frames <= 0 || sfinfo.channels <= 0)2488{2489FLUID_LOG(FLUID_DBG, "Empty decompressed sample");2490*data = NULL;2491sf_close(sndfile);2492return 0;2493}24942495// Mono sample2496if(sfinfo.channels != 1)2497{2498FLUID_LOG(FLUID_DBG, "Unsupported channel count %d in ogg sample", sfinfo.channels);2499goto error_exit;2500}25012502if((sfinfo.format & SF_FORMAT_OGG) == 0)2503{2504FLUID_LOG(FLUID_WARN, "OGG sample is not OGG compressed, this is not officially supported");2505}25062507wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels);25082509if(!wav_data)2510{2511FLUID_LOG(FLUID_ERR, "Out of memory");2512goto error_exit;2513}25142515// Avoid clipping for loud samples, see2516// https://github.com/FluidSynth/fluidsynth/issues/13802517// and2518// https://github.com/libsndfile/libsndfile/issues/1942519sf_command(sndfile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);25202521/* Automatically decompresses the Ogg Vorbis data to 16-bit PCM */2522if(sf_readf_short(sndfile, wav_data, sfinfo.frames) < sfinfo.frames)2523{2524FLUID_LOG(FLUID_DBG, "Decompression failed!");2525FLUID_LOG(FLUID_ERR, "sf_readf_short(): %s", sf_strerror(sndfile));2526goto error_exit;2527}25282529sf_close(sndfile);25302531*data = wav_data;25322533return sfinfo.frames;25342535error_exit:2536FLUID_FREE(wav_data);2537sf_close(sndfile);2538return -1;2539}2540#else2541static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)2542{2543return -1;2544}2545#endif254625472548