Path: blob/master/libs/fluidsynth/src/sfloader/fluid_sffile.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_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;671672if(sf->version.major < 2)673{674FLUID_LOG(FLUID_ERR, "Sound font version is %d.%d which is not"675" supported, convert to version 2.0x",676sf->version.major, sf->version.minor);677return FALSE;678}679680if(sf->version.major == 3)681{682#if !LIBSNDFILE_SUPPORT683FLUID_LOG(FLUID_WARN,684"Sound font version is %d.%d but fluidsynth was compiled without"685" support for (v3.x)",686sf->version.major, sf->version.minor);687return FALSE;688#endif689}690else if(sf->version.major > 2)691{692FLUID_LOG(FLUID_WARN,693"Sound font version is %d.%d which is newer than"694" what this version of fluidsynth was designed for (v2.0x)",695sf->version.major, sf->version.minor);696return FALSE;697}698}699else if(chunk.id == IVER_FCC)700{701/* ROM version chunk? */702if(chunk.size != 4)703{704FLUID_LOG(FLUID_ERR, "ROM version info chunk has invalid size");705return FALSE;706}707708READW(sf, ver);709sf->romver.major = ver;710READW(sf, ver);711sf->romver.minor = ver;712}713else if(chunkid(chunk.id) != UNKN_ID)714{715if((chunk.id != ICMT_FCC && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))716{717FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes",718(char*)&chunk.id, chunk.size);719return FALSE;720}721722/* alloc for chunk fcc and da chunk */723if(!(item.fcc = FLUID_MALLOC(chunk.size + sizeof(uint32_t) + 1)))724{725FLUID_LOG(FLUID_ERR, "Out of memory");726return FALSE;727}728729/* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */730sf->info = fluid_list_append(sf->info, item.fcc);731732/* save chunk fcc and update pointer to data value */733*item.fcc++ = chunk.id;734735if(sf->fcbs->fread(item.chr, chunk.size, sf->sffd) == FLUID_FAILED)736{737return FALSE;738}739740/* force terminate info item */741item.chr[chunk.size] = '\0';742}743else744{745FLUID_LOG(FLUID_ERR, "Invalid chunk id in INFO chunk");746return FALSE;747}748749size -= chunk.size;750}751752if(size < 0)753{754FLUID_LOG(FLUID_ERR, "INFO chunk size mismatch");755return FALSE;756}757758return TRUE;759}760761static int process_sdta(SFData *sf, unsigned int size)762{763SFChunk chunk;764765if(size == 0)766{767return TRUE; /* no sample data? */768}769770/* read sub chunk */771READCHUNK(sf, &chunk);772size -= 8;773774if(chunk.id != SMPL_FCC)775{776FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead");777return FALSE;778}779780/* SDTA chunk may also contain sm24 chunk for 24 bit samples781* (not yet supported), only an error if SMPL chunk size is782* greater than SDTA. */783if(chunk.size > size)784{785FLUID_LOG(FLUID_ERR, "SDTA chunk size mismatch");786return FALSE;787}788789/* sample data follows */790sf->samplepos = sf->fcbs->ftell(sf->sffd);791792/* used to check validity of sample headers */793sf->samplesize = chunk.size;794795FSKIP(sf, chunk.size);796size -= chunk.size;797798if(sf->version.major >= 2 && sf->version.minor >= 4)799{800/* any chance to find another chunk here? */801if(size > 8)802{803/* read sub chunk */804READCHUNK(sf, &chunk);805size -= 8;806807if(chunk.id == SM24_FCC)808{809int sm24size, sdtahalfsize;810811FLUID_LOG(FLUID_DBG, "Found SM24 chunk");812813if(chunk.size > size)814{815FLUID_LOG(FLUID_WARN, "SM24 exceeds SDTA chunk, ignoring SM24");816goto ret; // no error817}818819sdtahalfsize = sf->samplesize / 2;820/* + 1 byte in the case that half the size of smpl chunk is an odd value */821sdtahalfsize += sdtahalfsize % 2;822sm24size = chunk.size;823824if(sdtahalfsize != sm24size)825{826FLUID_LOG(FLUID_WARN, "SM24 not equal to half the size of SMPL chunk (0x%X != "827"0x%X), ignoring SM24",828sm24size, sdtahalfsize);829goto ret; // no error830}831832/* sample data24 follows */833sf->sample24pos = sf->fcbs->ftell(sf->sffd);834sf->sample24size = sm24size;835}836}837}838839ret:840FSKIP(sf, size);841842return TRUE;843}844845static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size)846{847READCHUNK(sf, chunk);848*size -= 8;849850if(chunk->id != expid)851{852FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", (char*)&expid);853return FALSE;854}855856if(chunk->size % reclen) /* valid chunk size? */857{858FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", (char*)&expid, reclen);859return FALSE;860}861862if((*size -= chunk->size) < 0)863{864FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", (char*)&expid);865return FALSE;866}867868return TRUE;869}870871static int process_pdta(SFData *sf, int size)872{873SFChunk chunk;874875if(!pdtahelper(sf, PHDR_FCC, SF_PHDR_SIZE, &chunk, &size))876{877return FALSE;878}879880if(!load_phdr(sf, chunk.size))881{882return FALSE;883}884885if(!pdtahelper(sf, PBAG_FCC, SF_BAG_SIZE, &chunk, &size))886{887return FALSE;888}889890if(!load_pbag(sf, chunk.size))891{892return FALSE;893}894895if(!pdtahelper(sf, PMOD_FCC, SF_MOD_SIZE, &chunk, &size))896{897return FALSE;898}899900if(!load_pmod(sf, chunk.size))901{902return FALSE;903}904905if(!pdtahelper(sf, PGEN_FCC, SF_GEN_SIZE, &chunk, &size))906{907return FALSE;908}909910if(!load_pgen(sf, chunk.size))911{912return FALSE;913}914915if(!pdtahelper(sf, IHDR_FCC, SF_IHDR_SIZE, &chunk, &size))916{917return FALSE;918}919920if(!load_ihdr(sf, chunk.size))921{922return FALSE;923}924925if(!pdtahelper(sf, IBAG_FCC, SF_BAG_SIZE, &chunk, &size))926{927return FALSE;928}929930if(!load_ibag(sf, chunk.size))931{932return FALSE;933}934935if(!pdtahelper(sf, IMOD_FCC, SF_MOD_SIZE, &chunk, &size))936{937return FALSE;938}939940if(!load_imod(sf, chunk.size))941{942return FALSE;943}944945if(!pdtahelper(sf, IGEN_FCC, SF_GEN_SIZE, &chunk, &size))946{947return FALSE;948}949950if(!load_igen(sf, chunk.size))951{952return FALSE;953}954955if(!pdtahelper(sf, SHDR_FCC, SF_SHDR_SIZE, &chunk, &size))956{957return FALSE;958}959960if(!load_shdr(sf, chunk.size))961{962return FALSE;963}964965return TRUE;966}967968/* preset header loader */969static int load_phdr(SFData *sf, unsigned int size)970{971unsigned int i;972int i2;973SFPreset *preset, *prev_preset = NULL;974unsigned short pbag_idx, prev_pbag_idx = 0;975976if(size % SF_PHDR_SIZE || size == 0)977{978FLUID_LOG(FLUID_ERR, "Preset header chunk size is invalid");979return FALSE;980}981982i = size / SF_PHDR_SIZE - 1;983984if(i == 0)985{986/* at least one preset + term record */987FLUID_LOG(FLUID_WARN, "File contains no presets");988FSKIP(sf, SF_PHDR_SIZE);989return TRUE;990}991992for(; i > 0; i--)993{994/* load all preset headers */995if((preset = FLUID_NEW(SFPreset)) == NULL)996{997FLUID_LOG(FLUID_ERR, "Out of memory");998return FALSE;999}10001001sf->preset = fluid_list_append(sf->preset, preset);1002preset->zone = NULL; /* In case of failure, fluid_sffile_close can cleanup */1003READSTR(sf, &preset->name); /* possible read failure ^ */1004READW(sf, preset->prenum);1005READW(sf, preset->bank);1006READW(sf, pbag_idx);1007FSKIP(sf, 4); /* library ignored */1008FSKIP(sf, 4); /* genre ignored */1009FSKIP(sf, 4); /* morphology ignored */10101011if(prev_preset)1012{1013/* not first preset? */1014if(pbag_idx < prev_pbag_idx)1015{1016FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");1017return FALSE;1018}10191020i2 = pbag_idx - prev_pbag_idx;10211022while(i2--)1023{1024prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);1025}1026}1027else if(pbag_idx > 0) /* 1st preset, warn if ofs >0 */1028{1029FLUID_LOG(FLUID_WARN, "%d preset zones not referenced, discarding", pbag_idx);1030}10311032prev_preset = preset; /* update preset ptr */1033prev_pbag_idx = pbag_idx;1034}10351036FSKIP(sf, 24);1037READW(sf, pbag_idx); /* Read terminal generator index */1038FSKIP(sf, 12);10391040if(pbag_idx < prev_pbag_idx)1041{1042FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");1043return FALSE;1044}10451046i2 = pbag_idx - prev_pbag_idx;10471048while(i2--)1049{1050prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);1051}10521053return TRUE;1054}10551056/* preset bag loader */1057static int load_pbag(SFData *sf, int size)1058{1059fluid_list_t *preset_list;1060fluid_list_t *zone_list;1061SFZone *z, *pz = NULL;1062unsigned short genndx, modndx;1063unsigned short pgenndx = 0, pmodndx = 0;1064unsigned short i;10651066if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */1067{1068FLUID_LOG(FLUID_ERR, "Preset bag chunk size is invalid");1069return FALSE;1070}10711072preset_list = sf->preset;10731074/* traverse through presets */1075while(preset_list)1076{1077zone_list = ((SFPreset *)(preset_list->data))->zone;10781079/* traverse preset's zones */1080while(zone_list)1081{1082if((size -= SF_BAG_SIZE) < 0)1083{1084FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");1085return FALSE;1086}10871088if((z = FLUID_NEW(SFZone)) == NULL)1089{1090FLUID_LOG(FLUID_ERR, "Out of memory");1091return FALSE;1092}10931094zone_list->data = z;1095z->gen = NULL; /* Init gen and mod before possible failure, */1096z->mod = NULL; /* to ensure proper cleanup (fluid_sffile_close) */1097READW(sf, genndx); /* possible read failure ^ */1098READW(sf, modndx);10991100if(pz)1101{1102/* if not first zone */1103if(genndx < pgenndx)1104{1105FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");1106return FALSE;1107}11081109if(modndx < pmodndx)1110{1111FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");1112return FALSE;1113}11141115i = genndx - pgenndx;11161117while(i--)1118{1119pz->gen = fluid_list_prepend(pz->gen, NULL);1120}11211122i = modndx - pmodndx;11231124while(i--)1125{1126pz->mod = fluid_list_prepend(pz->mod, NULL);1127}1128}11291130pz = z; /* update previous zone ptr */1131pgenndx = genndx; /* update previous zone gen index */1132pmodndx = modndx; /* update previous zone mod index */1133zone_list = fluid_list_next(zone_list);1134}11351136preset_list = fluid_list_next(preset_list);1137}11381139size -= SF_BAG_SIZE;11401141if(size != 0)1142{1143FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");1144return FALSE;1145}11461147READW(sf, genndx);1148READW(sf, modndx);11491150if(!pz)1151{1152if(genndx > 0)1153{1154FLUID_LOG(FLUID_WARN, "No preset generators and terminal index not 0");1155}11561157if(modndx > 0)1158{1159FLUID_LOG(FLUID_WARN, "No preset modulators and terminal index not 0");1160}11611162return TRUE;1163}11641165if(genndx < pgenndx)1166{1167FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");1168return FALSE;1169}11701171if(modndx < pmodndx)1172{1173FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");1174return FALSE;1175}11761177i = genndx - pgenndx;11781179while(i--)1180{1181pz->gen = fluid_list_prepend(pz->gen, NULL);1182}11831184i = modndx - pmodndx;11851186while(i--)1187{1188pz->mod = fluid_list_prepend(pz->mod, NULL);1189}11901191return TRUE;1192}11931194/* preset modulator loader */1195static int load_pmod(SFData *sf, int size)1196{1197fluid_list_t *preset_list;1198fluid_list_t *zone_list;1199fluid_list_t *mod_list;1200SFMod *m;12011202preset_list = sf->preset;12031204while(preset_list)1205{1206/* traverse through all presets */1207zone_list = ((SFPreset *)(preset_list->data))->zone;12081209while(zone_list)1210{1211/* traverse this preset's zones */1212mod_list = ((SFZone *)(zone_list->data))->mod;12131214while(mod_list)1215{1216/* load zone's modulators */1217if((size -= SF_MOD_SIZE) < 0)1218{1219FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");1220return FALSE;1221}12221223if((m = FLUID_NEW(SFMod)) == NULL)1224{1225FLUID_LOG(FLUID_ERR, "Out of memory");1226return FALSE;1227}12281229mod_list->data = m;1230READW(sf, m->src);1231READW(sf, m->dest);1232READW(sf, m->amount);1233READW(sf, m->amtsrc);1234READW(sf, m->trans);1235mod_list = fluid_list_next(mod_list);1236}12371238zone_list = fluid_list_next(zone_list);1239}12401241preset_list = fluid_list_next(preset_list);1242}12431244/*1245If there isn't even a terminal record1246Hmmm, the specs say there should be one, but..1247*/1248if(size == 0)1249{1250return TRUE;1251}12521253size -= SF_MOD_SIZE;12541255if(size != 0)1256{1257FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");1258return FALSE;1259}12601261FSKIP(sf, SF_MOD_SIZE); /* terminal mod */12621263return TRUE;1264}12651266/* -------------------------------------------------------------------1267* preset generator loader1268* generator (per preset) loading rules:1269* Zones with no generators or modulators shall be annihilated1270* Global zone must be 1st zone, discard additional ones (instrumentless zones)1271*1272* generator (per zone) loading rules (in order of decreasing precedence):1273* KeyRange is 1st in list (if exists), else discard1274* if a VelRange exists only preceded by a KeyRange, else discard1275* if a generator follows an instrument discard it1276* if a duplicate generator exists replace previous one1277* ------------------------------------------------------------------- */1278int load_pgen(SFData *sf, int size)1279{1280fluid_list_t *dup;1281fluid_list_t *preset_list;1282fluid_list_t *zone_list;1283fluid_list_t *gen_list;1284SFZone *zone;1285SFGen *g;1286SFPreset *preset;1287SFGenAmount genval;1288unsigned short genid;1289int level, skip, drop, discarded;12901291preset_list = sf->preset;12921293while(preset_list)1294{1295preset = fluid_list_get(preset_list);12961297/* traverse through all presets */1298discarded = FALSE;1299zone_list = preset->zone;13001301/* traverse preset's zones */1302while(zone_list)1303{1304zone = fluid_list_get(zone_list);1305level = 0;1306gen_list = zone->gen;13071308while(gen_list)1309{1310/* load zone's generators */1311dup = NULL;1312skip = FALSE;1313drop = FALSE;13141315if((size -= SF_GEN_SIZE) < 0)1316{1317FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");1318return FALSE;1319}13201321READW(sf, genid);13221323if(genid == GEN_KEYRANGE)1324{1325/* nothing precedes */1326if(level == 0)1327{1328level = 1;1329READB(sf, genval.range.lo);1330READB(sf, genval.range.hi);1331}1332else1333{1334skip = TRUE;1335}1336}1337else if(genid == GEN_VELRANGE)1338{1339/* only KeyRange precedes */1340if(level <= 1)1341{1342level = 2;1343READB(sf, genval.range.lo);1344READB(sf, genval.range.hi);1345}1346else1347{1348skip = TRUE;1349}1350}1351else if(genid == GEN_INSTRUMENT)1352{1353/* inst is last gen */1354level = 3;1355READW(sf, genval.uword);1356}1357else1358{1359level = 2;13601361if(valid_preset_genid(genid))1362{1363/* generator valid? */1364READW(sf, genval.sword);1365dup = find_gen_by_id(genid, zone->gen);1366}1367else1368{1369skip = TRUE;1370}1371}13721373if(!skip)1374{1375if(!dup)1376{1377/* if gen ! dup alloc new */1378if((g = FLUID_NEW(SFGen)) == NULL)1379{1380FLUID_LOG(FLUID_ERR, "Out of memory");1381return FALSE;1382}13831384gen_list->data = g;1385g->id = genid;1386}1387else1388{1389g = (SFGen *)(dup->data); /* ptr to orig gen */1390drop = TRUE;1391}13921393g->amount = genval;1394}1395else1396{1397/* Skip this generator */1398discarded = TRUE;1399drop = TRUE;1400FSKIPW(sf);1401}14021403if(!drop)1404{1405gen_list = fluid_list_next(gen_list); /* next gen */1406}1407else1408{1409SLADVREM(zone->gen, gen_list); /* drop place holder */1410}14111412/* GEN_INSTRUMENT should be the last generator */1413if (level == 3)1414{1415break;1416}14171418} /* generator loop */14191420/* Anything below level 3 means it's a global zone. The global zone1421* should always be the first zone in the list, so discard any1422* other global zones we encounter */1423if(level < 3 && (zone_list != preset->zone))1424{1425/* advance to next zone before deleting the current list element */1426zone_list = fluid_list_next(zone_list);14271428FLUID_LOG(FLUID_WARN, "Preset '%s': Discarding invalid global zone",1429preset->name);1430preset->zone = fluid_list_remove(preset->zone, zone);1431delete_zone(zone);14321433/* we have already advanced the zone_list pointer, so continue with next zone */1434continue;1435}14361437/* All remaining generators are invalid and should be discarded1438* (because they come after an instrument generator) */1439while(gen_list)1440{1441discarded = TRUE;14421443if((size -= SF_GEN_SIZE) < 0)1444{1445FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");1446return FALSE;1447}14481449FSKIP(sf, SF_GEN_SIZE);1450SLADVREM(zone->gen, gen_list);1451}14521453zone_list = fluid_list_next(zone_list);1454}14551456if(discarded)1457{1458FLUID_LOG(FLUID_WARN,1459"Preset '%s': Some invalid generators were discarded",1460preset->name);1461}14621463preset_list = fluid_list_next(preset_list);1464}14651466/* in case there isn't a terminal record */1467if(size == 0)1468{1469return TRUE;1470}14711472size -= SF_GEN_SIZE;14731474if(size != 0)1475{1476FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");1477return FALSE;1478}14791480FSKIP(sf, SF_GEN_SIZE); /* terminal gen */14811482return TRUE;1483}14841485/* instrument header loader */1486static int load_ihdr(SFData *sf, unsigned int size)1487{1488unsigned int i;1489int i2;1490SFInst *inst, *prev_inst = NULL; /* ptr to current & previous instrument */1491unsigned short zndx, pzndx = 0;14921493if(size % SF_IHDR_SIZE || size == 0) /* chunk size is valid? */1494{1495FLUID_LOG(FLUID_ERR, "Instrument header has invalid size");1496return FALSE;1497}14981499size = size / SF_IHDR_SIZE - 1;15001501if(size == 0)1502{1503/* at least one preset + term record */1504FLUID_LOG(FLUID_WARN, "File contains no instruments");1505FSKIP(sf, SF_IHDR_SIZE);1506return TRUE;1507}15081509for(i = 0; i < size; i++)1510{1511/* load all instrument headers */1512if((inst = FLUID_NEW(SFInst)) == NULL)1513{1514FLUID_LOG(FLUID_ERR, "Out of memory");1515return FALSE;1516}15171518sf->inst = fluid_list_append(sf->inst, inst);1519inst->zone = NULL; /* For proper cleanup if fail (fluid_sffile_close) */1520inst->idx = i;1521READSTR(sf, &inst->name); /* Possible read failure ^ */1522READW(sf, zndx);15231524if(prev_inst)1525{1526/* not first instrument? */1527if(zndx < pzndx)1528{1529FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");1530return FALSE;1531}15321533i2 = zndx - pzndx;15341535while(i2--)1536{1537prev_inst->zone = fluid_list_prepend(prev_inst->zone, NULL);1538}1539}1540else if(zndx > 0) /* 1st inst, warn if ofs >0 */1541{1542FLUID_LOG(FLUID_WARN, "%d instrument zones not referenced, discarding", zndx);1543}15441545pzndx = zndx;1546prev_inst = inst; /* update instrument ptr */1547}15481549FSKIP(sf, 20);1550READW(sf, zndx);15511552if(zndx < pzndx)1553{1554FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");1555return FALSE;1556}15571558i2 = zndx - pzndx;15591560while(i2--)1561{1562prev_inst->zone = fluid_list_prepend(prev_inst->zone, NULL);1563}15641565return TRUE;1566}15671568/* instrument bag loader */1569static int load_ibag(SFData *sf, int size)1570{1571fluid_list_t *inst_list;1572fluid_list_t *zone_list;1573SFZone *z, *pz = NULL;1574unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0;1575int i;15761577if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */1578{1579FLUID_LOG(FLUID_ERR, "Instrument bag chunk size is invalid");1580return FALSE;1581}15821583inst_list = sf->inst;15841585while(inst_list)1586{1587/* traverse through inst */1588zone_list = ((SFInst *)(inst_list->data))->zone;15891590while(zone_list)1591{1592/* load this inst's zones */1593if((size -= SF_BAG_SIZE) < 0)1594{1595FLUID_LOG(FLUID_ERR, "Instrument bag chunk size mismatch");1596return FALSE;1597}15981599if((z = FLUID_NEW(SFZone)) == NULL)1600{1601FLUID_LOG(FLUID_ERR, "Out of memory");1602return FALSE;1603}16041605zone_list->data = z;1606z->gen = NULL; /* In case of failure, */1607z->mod = NULL; /* fluid_sffile_close can clean up */1608READW(sf, genndx); /* READW = possible read failure */1609READW(sf, modndx);16101611if(pz)1612{1613/* if not first zone */1614if(genndx < pgenndx)1615{1616FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");1617return FALSE;1618}16191620if(modndx < pmodndx)1621{1622FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");1623return FALSE;1624}16251626i = genndx - pgenndx;16271628while(i--)1629{1630pz->gen = fluid_list_prepend(pz->gen, NULL);1631}16321633i = modndx - pmodndx;16341635while(i--)1636{1637pz->mod = fluid_list_prepend(pz->mod, NULL);1638}1639}16401641pz = z; /* update previous zone ptr */1642pgenndx = genndx;1643pmodndx = modndx;1644zone_list = fluid_list_next(zone_list);1645}16461647inst_list = fluid_list_next(inst_list);1648}16491650size -= SF_BAG_SIZE;16511652if(size != 0)1653{1654FLUID_LOG(FLUID_ERR, "Instrument chunk size mismatch");1655return FALSE;1656}16571658READW(sf, genndx);1659READW(sf, modndx);16601661if(!pz)1662{1663/* in case that all are no zoners */1664if(genndx > 0)1665{1666FLUID_LOG(FLUID_WARN, "No instrument generators and terminal index not 0");1667}16681669if(modndx > 0)1670{1671FLUID_LOG(FLUID_WARN, "No instrument modulators and terminal index not 0");1672}16731674return TRUE;1675}16761677if(genndx < pgenndx)1678{1679FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");1680return FALSE;1681}16821683if(modndx < pmodndx)1684{1685FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");1686return FALSE;1687}16881689i = genndx - pgenndx;16901691while(i--)1692{1693pz->gen = fluid_list_prepend(pz->gen, NULL);1694}16951696i = modndx - pmodndx;16971698while(i--)1699{1700pz->mod = fluid_list_prepend(pz->mod, NULL);1701}17021703return TRUE;1704}17051706/* instrument modulator loader */1707static int load_imod(SFData *sf, int size)1708{1709fluid_list_t *inst_list;1710fluid_list_t *zone_list;1711fluid_list_t *mod_list;1712SFMod *m;17131714inst_list = sf->inst;17151716while(inst_list)1717{1718/* traverse through all inst */1719zone_list = ((SFInst *)(inst_list->data))->zone;17201721while(zone_list)1722{1723/* traverse this inst's zones */1724mod_list = ((SFZone *)(zone_list->data))->mod;17251726while(mod_list)1727{1728/* load zone's modulators */1729if((size -= SF_MOD_SIZE) < 0)1730{1731FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");1732return FALSE;1733}17341735if((m = FLUID_NEW(SFMod)) == NULL)1736{1737FLUID_LOG(FLUID_ERR, "Out of memory");1738return FALSE;1739}17401741mod_list->data = m;1742READW(sf, m->src);1743READW(sf, m->dest);1744READW(sf, m->amount);1745READW(sf, m->amtsrc);1746READW(sf, m->trans);1747mod_list = fluid_list_next(mod_list);1748}17491750zone_list = fluid_list_next(zone_list);1751}17521753inst_list = fluid_list_next(inst_list);1754}17551756/*1757If there isn't even a terminal record1758Hmmm, the specs say there should be one, but..1759*/1760if(size == 0)1761{1762return TRUE;1763}17641765size -= SF_MOD_SIZE;17661767if(size != 0)1768{1769FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");1770return FALSE;1771}17721773FSKIP(sf, SF_MOD_SIZE); /* terminal mod */17741775return TRUE;1776}17771778/* load instrument generators (see load_pgen for loading rules) */1779int load_igen(SFData *sf, int size)1780{1781fluid_list_t *dup;1782fluid_list_t *inst_list;1783fluid_list_t *zone_list;1784fluid_list_t *gen_list;1785SFZone *zone;1786SFGen *g;1787SFInst *inst;1788SFGenAmount genval;1789unsigned short genid;1790int level, skip, drop, discarded;17911792inst_list = sf->inst;17931794/* traverse through all instruments */1795while(inst_list)1796{1797inst = fluid_list_get(inst_list);17981799discarded = FALSE;1800zone_list = inst->zone;18011802/* traverse this instrument's zones */1803while(zone_list)1804{1805zone = fluid_list_get(zone_list);18061807level = 0;1808gen_list = zone->gen;18091810while(gen_list)1811{1812/* load zone's generators */1813dup = NULL;1814skip = FALSE;1815drop = FALSE;18161817if((size -= SF_GEN_SIZE) < 0)1818{1819FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");1820return FALSE;1821}18221823READW(sf, genid);18241825if(genid == GEN_KEYRANGE)1826{1827/* nothing precedes */1828if(level == 0)1829{1830level = 1;1831READB(sf, genval.range.lo);1832READB(sf, genval.range.hi);1833}1834else1835{1836skip = TRUE;1837}1838}1839else if(genid == GEN_VELRANGE)1840{1841/* only KeyRange precedes */1842if(level <= 1)1843{1844level = 2;1845READB(sf, genval.range.lo);1846READB(sf, genval.range.hi);1847}1848else1849{1850skip = TRUE;1851}1852}1853else if(genid == GEN_SAMPLEID)1854{1855/* sample is last gen */1856level = 3;1857READW(sf, genval.uword);1858}1859else1860{1861level = 2;18621863if(valid_inst_genid(genid))1864{1865/* gen valid? */1866READW(sf, genval.sword);1867dup = find_gen_by_id(genid, zone->gen);1868}1869else1870{1871skip = TRUE;1872}1873}18741875if(!skip)1876{1877if(!dup)1878{1879/* if gen ! dup alloc new */1880if((g = FLUID_NEW(SFGen)) == NULL)1881{1882FLUID_LOG(FLUID_ERR, "Out of memory");1883return FALSE;1884}18851886gen_list->data = g;1887g->id = genid;1888}1889else1890{1891g = (SFGen *)(dup->data);1892drop = TRUE;1893}18941895g->amount = genval;1896}1897else1898{1899/* skip this generator */1900discarded = TRUE;1901drop = TRUE;1902FSKIPW(sf);1903}19041905if(!drop)1906{1907gen_list = fluid_list_next(gen_list); /* next gen */1908}1909else1910{1911SLADVREM(zone->gen, gen_list);1912}19131914/* GEN_SAMPLEID should be last generator */1915if (level == 3)1916{1917break;1918}19191920} /* generator loop */19211922/* Anything below level 3 means it's a global zone. The global zone1923* should always be the first zone in the list, so discard any1924* other global zones we encounter */1925if(level < 3 && (zone_list != inst->zone))1926{1927/* advance to next zone before deleting the current list element */1928zone_list = fluid_list_next(zone_list);19291930FLUID_LOG(FLUID_WARN, "Instrument '%s': Discarding invalid global zone",1931inst->name);1932inst->zone = fluid_list_remove(inst->zone, zone);1933delete_zone(zone);19341935/* we have already advanced the zone_list pointer, so continue with next zone */1936continue;1937}19381939/* All remaining generators must be invalid and should be discarded1940* (because they come after a sampleid generator) */1941while(gen_list)1942{1943discarded = TRUE;19441945if((size -= SF_GEN_SIZE) < 0)1946{1947FLUID_LOG(FLUID_ERR, "Instrument generator chunk size mismatch");1948return FALSE;1949}19501951FSKIP(sf, SF_GEN_SIZE);1952SLADVREM(zone->gen, gen_list);1953}19541955zone_list = fluid_list_next(zone_list); /* next zone */1956}19571958if(discarded)1959{1960FLUID_LOG(FLUID_WARN,1961"Instrument '%s': Some invalid generators were discarded",1962inst->name);1963}19641965inst_list = fluid_list_next(inst_list);1966}19671968/* for those non-terminal record cases, grr! */1969if(size == 0)1970{1971return TRUE;1972}19731974size -= SF_GEN_SIZE;19751976if(size != 0)1977{1978FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");1979return FALSE;1980}19811982FSKIP(sf, SF_GEN_SIZE); /* terminal gen */19831984return TRUE;1985}19861987/* sample header loader */1988static int load_shdr(SFData *sf, unsigned int size)1989{1990unsigned int i;1991SFSample *p;19921993if(size % SF_SHDR_SIZE || size == 0) /* size is multiple of SHDR size? */1994{1995FLUID_LOG(FLUID_ERR, "Sample header has invalid size");1996return FALSE;1997}19981999size = size / SF_SHDR_SIZE - 1;20002001if(size == 0)2002{2003/* at least one sample + term record? */2004FLUID_LOG(FLUID_WARN, "File contains no samples");2005FSKIP(sf, SF_SHDR_SIZE);2006return TRUE;2007}20082009/* load all sample headers */2010for(i = 0; i < size; i++)2011{2012if((p = FLUID_NEW(SFSample)) == NULL)2013{2014FLUID_LOG(FLUID_ERR, "Out of memory");2015return FALSE;2016}2017p->idx = i;20182019sf->sample = fluid_list_prepend(sf->sample, p);2020READSTR(sf, &p->name);2021READD(sf, p->start);2022READD(sf, p->end);2023READD(sf, p->loopstart);2024READD(sf, p->loopend);2025READD(sf, p->samplerate);2026READB(sf, p->origpitch);2027READB(sf, p->pitchadj);2028FSKIPW(sf); /* skip sample link */2029READW(sf, p->sampletype);2030}20312032FSKIP(sf, SF_SHDR_SIZE); /* skip terminal shdr */20332034return TRUE;2035}20362037void delete_preset(SFPreset *preset)2038{2039fluid_list_t *entry;2040SFZone *zone;20412042if(!preset)2043{2044return;2045}20462047entry = preset->zone;20482049while(entry)2050{2051zone = (SFZone *)fluid_list_get(entry);2052delete_zone(zone);2053entry = fluid_list_next(entry);2054}20552056delete_fluid_list(preset->zone);20572058FLUID_FREE(preset);2059}20602061void delete_inst(SFInst *inst)2062{2063fluid_list_t *entry;2064SFZone *zone;20652066if(!inst)2067{2068return;2069}20702071entry = inst->zone;20722073while(entry)2074{2075zone = (SFZone *)fluid_list_get(entry);2076delete_zone(zone);2077entry = fluid_list_next(entry);2078}20792080delete_fluid_list(inst->zone);20812082FLUID_FREE(inst);2083}208420852086/* Free all elements of a zone (Preset or Instrument) */2087void delete_zone(SFZone *zone)2088{2089fluid_list_t *entry;20902091if(!zone)2092{2093return;2094}20952096entry = zone->gen;20972098while(entry)2099{2100FLUID_FREE(fluid_list_get(entry));2101entry = fluid_list_next(entry);2102}21032104delete_fluid_list(zone->gen);21052106entry = zone->mod;21072108while(entry)2109{2110FLUID_FREE(fluid_list_get(entry));2111entry = fluid_list_next(entry);2112}21132114delete_fluid_list(zone->mod);21152116FLUID_FREE(zone);2117}21182119/* preset sort function, first by bank, then by preset # */2120static int preset_compare_func(const void *a, const void *b)2121{2122int aval, bval;21232124aval = (int)(((const SFPreset *)a)->bank) << 16 | ((const SFPreset *)a)->prenum;2125bval = (int)(((const SFPreset *)b)->bank) << 16 | ((const SFPreset *)b)->prenum;21262127return (aval - bval);2128}21292130/* Find a generator by its id in the passed in list.2131*2132* @return pointer to SFGen if found, otherwise NULL2133*/2134static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist)2135{2136/* is generator in gen list? */2137fluid_list_t *p;21382139p = genlist;21402141while(p)2142{2143if(p->data == NULL)2144{2145return NULL;2146}21472148if(gen == ((SFGen *)p->data)->id)2149{2150break;2151}21522153p = fluid_list_next(p);2154}21552156return p;2157}21582159/* check validity of instrument generator */2160static int valid_inst_genid(unsigned short genid)2161{2162size_t i;21632164/* OVERRIDEROOTKEY is the last official generator, everything2165* following it are generators internal to FluidSynth and will2166* never appear in a SoundFont file. */2167if(genid > GEN_OVERRIDEROOTKEY)2168{2169return FALSE;2170}21712172for(i = 0; i < FLUID_N_ELEMENTS(invalid_inst_gen); i++)2173{2174if (invalid_inst_gen[i] == genid)2175{2176return FALSE;2177}2178}21792180return TRUE;2181}21822183/* check validity of preset generator */2184static int valid_preset_genid(unsigned short genid)2185{2186size_t i;21872188if(!valid_inst_genid(genid))2189{2190return FALSE;2191}21922193for(i = 0; i < FLUID_N_ELEMENTS(invalid_preset_gen); i++)2194{2195if (invalid_preset_gen[i] == genid)2196{2197return FALSE;2198}2199}22002201return TRUE;2202}220322042205static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24)2206{2207short *loaded_data = NULL;2208char *loaded_data24 = NULL;2209unsigned int num_samples;22102211fluid_return_val_if_fail((end + 1) > start , -1);22122213num_samples = (end + 1) - start;22142215if((start * sizeof(short) > sf->samplesize) || (end * sizeof(short) > sf->samplesize))2216{2217FLUID_LOG(FLUID_ERR, "Sample offsets exceed sample data chunk");2218goto error_exit;2219}22202221/* Load 16-bit sample data */2222if(sf->fcbs->fseek(sf->sffd, sf->samplepos + (start * sizeof(short)), SEEK_SET) == FLUID_FAILED)2223{2224FLUID_LOG(FLUID_ERR, "Failed to seek to sample position");2225goto error_exit;2226}22272228loaded_data = FLUID_ARRAY(short, num_samples);22292230if(loaded_data == NULL)2231{2232FLUID_LOG(FLUID_ERR, "Out of memory");2233goto error_exit;2234}22352236if(sf->fcbs->fread(loaded_data, num_samples * sizeof(short), sf->sffd) == FLUID_FAILED)2237{2238#if FLUID_VERSION_CHECK(FLUIDSYNTH_VERSION_MAJOR, FLUIDSYNTH_VERSION_MINOR, FLUIDSYNTH_VERSION_MICRO) < FLUID_VERSION_CHECK(2,2,0)2239if((int)(num_samples * sizeof(short)) < 0)2240{2241FLUID_LOG(FLUID_INFO,2242"This SoundFont seems to be bigger than 2GB, which is not supported in this version of fluidsynth. "2243"You need to use at least fluidsynth 2.2.0");2244}2245#endif2246FLUID_LOG(FLUID_ERR, "Failed to read sample data");2247goto error_exit;2248}22492250/* If this machine is big endian, byte swap the 16 bit samples */2251if(FLUID_IS_BIG_ENDIAN)2252{2253unsigned int i;22542255for(i = 0; i < num_samples; i++)2256{2257loaded_data[i] = FLUID_LE16TOH(loaded_data[i]);2258}2259}22602261*data = loaded_data;22622263/* Optionally load additional 8 bit sample data for 24-bit support. Any failures while loading2264* the 24-bit sample data will be logged as errors but won't prevent the sample reading to2265* fail, as sound output is still possible with the 16-bit sample data. */2266if(sf->sample24pos)2267{2268if((start > sf->sample24size) || (end > sf->sample24size))2269{2270FLUID_LOG(FLUID_ERR, "Sample offsets exceed 24-bit sample data chunk");2271goto error24_exit;2272}22732274if(sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED)2275{2276FLUID_LOG(FLUID_ERR, "Failed to seek position for 24-bit sample data in data file");2277goto error24_exit;2278}22792280loaded_data24 = FLUID_ARRAY(char, num_samples);22812282if(loaded_data24 == NULL)2283{2284FLUID_LOG(FLUID_ERR, "Out of memory reading 24-bit sample data");2285goto error24_exit;2286}22872288if(sf->fcbs->fread(loaded_data24, num_samples, sf->sffd) == FLUID_FAILED)2289{2290FLUID_LOG(FLUID_ERR, "Failed to read 24-bit sample data");2291goto error24_exit;2292}2293}22942295*data24 = loaded_data24;22962297return num_samples;22982299error24_exit:2300FLUID_LOG(FLUID_WARN, "Ignoring 24-bit sample data, sound quality might suffer");2301FLUID_FREE(loaded_data24);2302*data24 = NULL;2303return num_samples;23042305error_exit:2306FLUID_FREE(loaded_data);2307FLUID_FREE(loaded_data24);2308return -1;2309}231023112312/* Ogg Vorbis loading and decompression */2313#if LIBSNDFILE_SUPPORT23142315/* Virtual file access routines to allow loading individually compressed2316* samples from the Soundfont sample data chunk using the file callbacks2317* passing in during opening of the file */2318typedef struct _sfvio_data_t2319{2320SFData *sffile;2321sf_count_t start; /* start byte offset of compressed data */2322sf_count_t end; /* end byte offset of compressed data */2323sf_count_t offset; /* current virtual file offset from start byte offset */23242325} sfvio_data_t;23262327static sf_count_t sfvio_get_filelen(void *user_data)2328{2329sfvio_data_t *data = user_data;23302331return (data->end + 1) - data->start;2332}23332334static sf_count_t sfvio_seek(sf_count_t offset, int whence, void *user_data)2335{2336sfvio_data_t *data = user_data;2337SFData *sf = data->sffile;2338sf_count_t new_offset;23392340switch(whence)2341{2342case SEEK_SET:2343new_offset = offset;2344break;23452346case SEEK_CUR:2347new_offset = data->offset + offset;2348break;23492350case SEEK_END:2351new_offset = sfvio_get_filelen(user_data) + offset;2352break;23532354default:2355goto fail; /* proper error handling not possible?? */2356}23572358new_offset += data->start;2359fluid_rec_mutex_lock(sf->mtx);2360if (data->start <= new_offset && new_offset <= data->end &&2361sf->fcbs->fseek(sf->sffd, new_offset, SEEK_SET) != FLUID_FAILED)2362{2363data->offset = new_offset - data->start;2364}2365fluid_rec_mutex_unlock(sf->mtx);23662367fail:2368return data->offset;2369}23702371static sf_count_t sfvio_read(void *ptr, sf_count_t count, void *user_data)2372{2373sfvio_data_t *data = user_data;2374SFData *sf = data->sffile;2375sf_count_t remain;23762377remain = sfvio_get_filelen(user_data) - data->offset;23782379if(count > remain)2380{2381count = remain;2382}23832384if(count == 0)2385{2386return count;2387}23882389fluid_rec_mutex_lock(sf->mtx);2390if (sf->fcbs->fseek(sf->sffd, data->start + data->offset, SEEK_SET) == FLUID_FAILED)2391{2392FLUID_LOG(FLUID_ERR, "This should never happen: fseek failed in sfvoid_read()");2393count = 0;2394}2395else2396{2397if (sf->fcbs->fread(ptr, count, sf->sffd) == FLUID_FAILED)2398{2399FLUID_LOG(FLUID_ERR, "Failed to read compressed sample data");2400count = 0;2401}2402}2403fluid_rec_mutex_unlock(sf->mtx);24042405data->offset += count;24062407return count;2408}24092410static sf_count_t sfvio_tell(void *user_data)2411{2412sfvio_data_t *data = user_data;24132414return data->offset;2415}24162417/**2418* Read Ogg Vorbis compressed data from the Soundfont and decompress it, returning the number of samples2419* in the decompressed WAV. Only 16-bit mono samples are supported.2420*2421* Note that this function takes byte indices for start and end source data. The sample headers in SF32422* files use byte indices, so those pointers can be passed directly to this function.2423*2424* This function uses a virtual file structure in order to read the Ogg Vorbis2425* data from arbitrary locations in the source file.2426*/2427static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)2428{2429SNDFILE *sndfile;2430SF_INFO sfinfo;2431SF_VIRTUAL_IO sfvio =2432{2433sfvio_get_filelen,2434sfvio_seek,2435sfvio_read,2436NULL,2437sfvio_tell2438};2439sfvio_data_t sfdata;2440short *wav_data = NULL;24412442if((start_byte > sf->samplesize) || (end_byte > sf->samplesize))2443{2444FLUID_LOG(FLUID_ERR, "Ogg Vorbis data offsets exceed sample data chunk");2445return -1;2446}24472448// Initialize file position indicator and SF_INFO structure2449sfdata.sffile = sf;2450sfdata.start = sf->samplepos + start_byte;2451sfdata.end = sf->samplepos + end_byte;2452sfdata.offset = -1;24532454/* Seek to sfdata.start, the beginning of Ogg Vorbis data in Soundfont */2455sfvio_seek(0, SEEK_SET, &sfdata);2456if (sfdata.offset != 0)2457{2458FLUID_LOG(FLUID_ERR, "Failed to seek to compressed sample position");2459return -1;2460}24612462FLUID_MEMSET(&sfinfo, 0, sizeof(sfinfo));24632464// Open sample as a virtual file2465sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, &sfdata);24662467if(!sndfile)2468{2469FLUID_LOG(FLUID_ERR, "sf_open_virtual(): %s", sf_strerror(sndfile));2470return -1;2471}24722473// Empty sample2474if(sfinfo.frames <= 0 || sfinfo.channels <= 0)2475{2476FLUID_LOG(FLUID_DBG, "Empty decompressed sample");2477*data = NULL;2478sf_close(sndfile);2479return 0;2480}24812482// Mono sample2483if(sfinfo.channels != 1)2484{2485FLUID_LOG(FLUID_DBG, "Unsupported channel count %d in ogg sample", sfinfo.channels);2486goto error_exit;2487}24882489if((sfinfo.format & SF_FORMAT_OGG) == 0)2490{2491FLUID_LOG(FLUID_WARN, "OGG sample is not OGG compressed, this is not officially supported");2492}24932494wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels);24952496if(!wav_data)2497{2498FLUID_LOG(FLUID_ERR, "Out of memory");2499goto error_exit;2500}25012502// Avoid clipping for loud samples, see2503// https://github.com/FluidSynth/fluidsynth/issues/13802504// and2505// https://github.com/libsndfile/libsndfile/issues/1942506sf_command(sndfile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);25072508/* Automatically decompresses the Ogg Vorbis data to 16-bit PCM */2509if(sf_readf_short(sndfile, wav_data, sfinfo.frames) < sfinfo.frames)2510{2511FLUID_LOG(FLUID_DBG, "Decompression failed!");2512FLUID_LOG(FLUID_ERR, "sf_readf_short(): %s", sf_strerror(sndfile));2513goto error_exit;2514}25152516sf_close(sndfile);25172518*data = wav_data;25192520return sfinfo.frames;25212522error_exit:2523FLUID_FREE(wav_data);2524sf_close(sndfile);2525return -1;2526}2527#else2528static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)2529{2530return -1;2531}2532#endif253325342535