diff options
Diffstat (limited to 'libs/fluidsynth/src/fluid_sffile.c')
-rw-r--r-- | libs/fluidsynth/src/fluid_sffile.c | 275 |
1 files changed, 162 insertions, 113 deletions
diff --git a/libs/fluidsynth/src/fluid_sffile.c b/libs/fluidsynth/src/fluid_sffile.c index 40055e8189..302eea72a7 100644 --- a/libs/fluidsynth/src/fluid_sffile.c +++ b/libs/fluidsynth/src/fluid_sffile.c @@ -34,75 +34,79 @@ Borrowed from Smurf SoundFont Editor by Josh Green =================================================================*/ -/* - functions for loading data from sfont files, with appropriate byte swapping - on big endian machines. Sfont IDs are not swapped because the ID read is - equivalent to the matching ID list in memory regardless of LE/BE machine -*/ - -/* sf file chunk IDs */ -enum -{ - UNKN_ID, - RIFF_ID, - LIST_ID, - SFBK_ID, - INFO_ID, - SDTA_ID, - PDTA_ID, /* info/sample/preset */ - - IFIL_ID, - ISNG_ID, - INAM_ID, - IROM_ID, /* info ids (1st byte of info strings) */ - IVER_ID, - ICRD_ID, - IENG_ID, - IPRD_ID, /* more info ids */ - ICOP_ID, - ICMT_ID, - ISFT_ID, /* and yet more info ids */ - - SNAM_ID, - SMPL_ID, /* sample ids */ - PHDR_ID, - PBAG_ID, - PMOD_ID, - PGEN_ID, /* preset ids */ - IHDR_ID, - IBAG_ID, - IMOD_ID, - IGEN_ID, /* instrument ids */ - SHDR_ID, /* sample info */ - SM24_ID -}; +/* FOURCC definitions */ +#define RIFF_FCC FLUID_FOURCC('R','I','F','F') +#define LIST_FCC FLUID_FOURCC('L','I','S','T') +#define SFBK_FCC FLUID_FOURCC('s','f','b','k') +#define INFO_FCC FLUID_FOURCC('I','N','F','O') +#define SDTA_FCC FLUID_FOURCC('s','d','t','a') +#define PDTA_FCC FLUID_FOURCC('p','d','t','a') /* info/sample/preset */ + +#define IFIL_FCC FLUID_FOURCC('i','f','i','l') +#define ISNG_FCC FLUID_FOURCC('i','s','n','g') +#define INAM_FCC FLUID_FOURCC('I','N','A','M') +#define IROM_FCC FLUID_FOURCC('i','r','o','m') /* info ids (1st byte of info strings) */ +#define IVER_FCC FLUID_FOURCC('i','v','e','r') +#define ICRD_FCC FLUID_FOURCC('I','C','R','D') +#define IENG_FCC FLUID_FOURCC('I','E','N','G') +#define IPRD_FCC FLUID_FOURCC('I','P','R','D') /* more info ids */ +#define ICOP_FCC FLUID_FOURCC('I','C','O','P') +#define ICMT_FCC FLUID_FOURCC('I','C','M','T') +#define ISFT_FCC FLUID_FOURCC('I','S','F','T') /* and yet more info ids */ + +#define SNAM_FCC FLUID_FOURCC('s','n','a','m') +#define SMPL_FCC FLUID_FOURCC('s','m','p','l') /* sample ids */ +#define PHDR_FCC FLUID_FOURCC('p','h','d','r') +#define PBAG_FCC FLUID_FOURCC('p','b','a','g') +#define PMOD_FCC FLUID_FOURCC('p','m','o','d') +#define PGEN_FCC FLUID_FOURCC('p','g','e','n') /* preset ids */ +#define IHDR_FCC FLUID_FOURCC('i','n','s','t') +#define IBAG_FCC FLUID_FOURCC('i','b','a','g') +#define IMOD_FCC FLUID_FOURCC('i','m','o','d') +#define IGEN_FCC FLUID_FOURCC('i','g','e','n') /* instrument ids */ +#define SHDR_FCC FLUID_FOURCC('s','h','d','r') /* sample info */ +#define SM24_FCC FLUID_FOURCC('s','m','2','4') + +/* Set when the FCC code is unknown */ +#define UNKN_ID FLUID_N_ELEMENTS(idlist) /* - * This declares a char array containing the SF2 chunk identifiers. This - * array is being accessed like an uint32 below to simplify id comparison. - * To make sure it is suitably aligned for uint32 access, we must wrap it - * inside a union along with a uint32 telling the compiler to align it - * for integer access and avoiding undefined behaviour. - * This basically is the C89 equivalent to what is written in C11 as: - * alignas(uint32_t) static const char idlist[] = {}; - * - * See: EXP36-C. Do not cast pointers into more strictly aligned pointer - * types - SEI CERT C Coding Standard + * This declares a uint32_t array containing the SF2 chunk identifiers. */ -static const union fluid_idlist +static const uint32_t idlist[] = { - /* - * Cannot be char c[ ], because in C89, arrays wraped in unions - * must have a fixed size. Otherwise the size of the union would depend - * on the initialization of its first member, which results in - * different sizes for different instances of the same union type. - */ - char c[116]; - uint32_t i; -} idlist = {"RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD" - "ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdrsm24" - }; - + RIFF_FCC, + LIST_FCC, + SFBK_FCC, + INFO_FCC, + SDTA_FCC, + PDTA_FCC, + + IFIL_FCC, + ISNG_FCC, + INAM_FCC, + IROM_FCC, + IVER_FCC, + ICRD_FCC, + IENG_FCC, + IPRD_FCC, + ICOP_FCC, + ICMT_FCC, + ISFT_FCC, + + SNAM_FCC, + SMPL_FCC, + PHDR_FCC, + PBAG_FCC, + PMOD_FCC, + PGEN_FCC, + IHDR_FCC, + IBAG_FCC, + IMOD_FCC, + IGEN_FCC, + SHDR_FCC, + SM24_FCC +}; /* generator types */ typedef enum @@ -205,8 +209,6 @@ static const unsigned short invalid_preset_gen[] = }; -#define CHNKIDSTR(id) &idlist.c[(id - 1) * 4] - /* sfont file chunk sizes */ #define SF_PHDR_SIZE (38) #define SF_BAG_SIZE (4) @@ -322,6 +324,56 @@ static void delete_zone(SFZone *zone); static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data); static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24); +/** + * Check if a file is a SoundFont file. + * @param filename Path to the file to check + * @return TRUE if it could be a SoundFont, FALSE otherwise + * + * @note The current implementation only checks for the "RIFF" and "sfbk" headers in + * the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files. + */ +int fluid_is_soundfont(const char *filename) +{ + FILE *fp = FLUID_FOPEN(filename, "rb"); + uint32_t fcc; + int retcode = FALSE; + + do + { + if(fp == NULL) + { + return retcode; + } + + if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1) + { + break; + } + + if(fcc != RIFF_FCC) + { + break; + } + + if(FLUID_FSEEK(fp, 4, SEEK_CUR)) + { + break; + } + + if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1) + { + break; + } + + retcode = (fcc == SFBK_FCC); + } + while(0); + + FLUID_FCLOSE(fp); + + return retcode; +} + /* * Open a SoundFont file and parse it's contents into a SFData structure. * @@ -511,17 +563,17 @@ void fluid_sffile_close(SFData *sf) static int chunkid(uint32_t id) { unsigned int i; - const uint32_t *p = &idlist.i; - for(i = 0; i < sizeof(idlist) / sizeof(idlist.i); i++, p += 1) + for(i = 0; i < FLUID_N_ELEMENTS(idlist); i++) { - if(*p == id) + if(idlist[i] == id) { - return (i + 1); + break; } } - return UNKN_ID; + /* Return chunk id or UNKN_ID if not found */ + return i; } static int load_header(SFData *sf) @@ -530,7 +582,7 @@ static int load_header(SFData *sf) READCHUNK(sf, &chunk); /* load RIFF chunk */ - if(chunkid(chunk.id) != RIFF_ID) + if(chunk.id != RIFF_FCC) { /* error if not RIFF */ FLUID_LOG(FLUID_ERR, "Not a RIFF file"); @@ -539,7 +591,7 @@ static int load_header(SFData *sf) READID(sf, &chunk.id); /* load file ID */ - if(chunkid(chunk.id) != SFBK_ID) + if(chunk.id != SFBK_FCC) { /* error if not SFBK_ID */ FLUID_LOG(FLUID_ERR, "Not a SoundFont file"); @@ -558,7 +610,7 @@ static int load_header(SFData *sf) return FALSE; } - if(chunkid(chunk.id) != INFO_ID) + if(chunk.id != INFO_FCC) { FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting INFO chunk"); return FALSE; @@ -575,7 +627,7 @@ static int load_header(SFData *sf) return FALSE; } - if(chunkid(chunk.id) != SDTA_ID) + if(chunk.id != SDTA_FCC) { FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting SAMPLE chunk"); return FALSE; @@ -592,7 +644,7 @@ static int load_header(SFData *sf) return FALSE; } - if(chunkid(chunk.id) != PDTA_ID) + if(chunk.id != PDTA_FCC) { FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting HYDRA chunk"); return FALSE; @@ -637,7 +689,7 @@ static int read_listchunk(SFData *sf, SFChunk *chunk) { READCHUNK(sf, chunk); /* read list chunk */ - if(chunkid(chunk->id) != LIST_ID) /* error if ! list chunk */ + if(chunk->id != LIST_FCC) /* error if ! list chunk */ { FLUID_LOG(FLUID_ERR, "Invalid chunk id in level 0 parse"); return FALSE; @@ -651,8 +703,11 @@ static int read_listchunk(SFData *sf, SFChunk *chunk) static int process_info(SFData *sf, int size) { SFChunk chunk; - unsigned char id; - char *item; + union + { + char *chr; + uint32_t *fcc; + } item; unsigned short ver; while(size > 0) @@ -660,9 +715,7 @@ static int process_info(SFData *sf, int size) READCHUNK(sf, &chunk); size -= 8; - id = chunkid(chunk.id); - - if(id == IFIL_ID) + if(chunk.id == IFIL_FCC) { /* sound font version chunk? */ if(chunk.size != 4) @@ -703,7 +756,7 @@ static int process_info(SFData *sf, int size) return FALSE; } } - else if(id == IVER_ID) + else if(chunk.id == IVER_FCC) { /* ROM version chunk? */ if(chunk.size != 4) @@ -717,34 +770,35 @@ static int process_info(SFData *sf, int size) READW(sf, ver); sf->romver.minor = ver; } - else if(id != UNKN_ID) + else if(chunkid(chunk.id) != UNKN_ID) { - if((id != ICMT_ID && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2)) + if((chunk.id != ICMT_FCC && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2)) { FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes", &chunk.id, chunk.size); return FALSE; } - /* alloc for chunk id and da chunk */ - if(!(item = FLUID_MALLOC(chunk.size + 1))) + /* alloc for chunk fcc and da chunk */ + if(!(item.fcc = FLUID_MALLOC(chunk.size + sizeof(uint32_t) + 1))) { FLUID_LOG(FLUID_ERR, "Out of memory"); return FALSE; } /* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */ - sf->info = fluid_list_append(sf->info, item); + sf->info = fluid_list_append(sf->info, item.fcc); - *(unsigned char *)item = id; + /* save chunk fcc and update pointer to data value */ + *item.fcc++ = chunk.id; - if(sf->fcbs->fread(&item[1], chunk.size, sf->sffd) == FLUID_FAILED) + if(sf->fcbs->fread(item.chr, chunk.size, sf->sffd) == FLUID_FAILED) { return FALSE; } - /* force terminate info item (don't forget uint8 info ID) */ - *(item + chunk.size) = '\0'; + /* force terminate info item */ + item.chr[chunk.size] = '\0'; } else { @@ -777,7 +831,7 @@ static int process_sdta(SFData *sf, unsigned int size) READCHUNK(sf, &chunk); size -= 8; - if(chunkid(chunk.id) != SMPL_ID) + if(chunk.id != SMPL_FCC) { FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead"); return FALSE; @@ -810,7 +864,7 @@ static int process_sdta(SFData *sf, unsigned int size) READCHUNK(sf, &chunk); size -= 8; - if(chunkid(chunk.id) == SM24_ID) + if(chunk.id == SM24_FCC) { int sm24size, sdtahalfsize; @@ -850,29 +904,24 @@ ret: static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size) { - unsigned int id; - const char *expstr; - - expstr = CHNKIDSTR(expid); /* in case we need it */ - READCHUNK(sf, chunk); *size -= 8; - if((id = chunkid(chunk->id)) != expid) + if(chunk->id != expid) { - FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", expstr); + FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", &expid); return FALSE; } if(chunk->size % reclen) /* valid chunk size? */ { - FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", expstr, reclen); + FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", &expid, reclen); return FALSE; } if((*size -= chunk->size) < 0) { - FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", expstr); + FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", &expid); return FALSE; } @@ -883,7 +932,7 @@ static int process_pdta(SFData *sf, int size) { SFChunk chunk; - if(!pdtahelper(sf, PHDR_ID, SF_PHDR_SIZE, &chunk, &size)) + if(!pdtahelper(sf, PHDR_FCC, SF_PHDR_SIZE, &chunk, &size)) { return FALSE; } @@ -893,7 +942,7 @@ static int process_pdta(SFData *sf, int size) return FALSE; } - if(!pdtahelper(sf, PBAG_ID, SF_BAG_SIZE, &chunk, &size)) + if(!pdtahelper(sf, PBAG_FCC, SF_BAG_SIZE, &chunk, &size)) { return FALSE; } @@ -903,7 +952,7 @@ static int process_pdta(SFData *sf, int size) return FALSE; } - if(!pdtahelper(sf, PMOD_ID, SF_MOD_SIZE, &chunk, &size)) + if(!pdtahelper(sf, PMOD_FCC, SF_MOD_SIZE, &chunk, &size)) { return FALSE; } @@ -913,7 +962,7 @@ static int process_pdta(SFData *sf, int size) return FALSE; } - if(!pdtahelper(sf, PGEN_ID, SF_GEN_SIZE, &chunk, &size)) + if(!pdtahelper(sf, PGEN_FCC, SF_GEN_SIZE, &chunk, &size)) { return FALSE; } @@ -923,7 +972,7 @@ static int process_pdta(SFData *sf, int size) return FALSE; } - if(!pdtahelper(sf, IHDR_ID, SF_IHDR_SIZE, &chunk, &size)) + if(!pdtahelper(sf, IHDR_FCC, SF_IHDR_SIZE, &chunk, &size)) { return FALSE; } @@ -933,7 +982,7 @@ static int process_pdta(SFData *sf, int size) return FALSE; } - if(!pdtahelper(sf, IBAG_ID, SF_BAG_SIZE, &chunk, &size)) + if(!pdtahelper(sf, IBAG_FCC, SF_BAG_SIZE, &chunk, &size)) { return FALSE; } @@ -943,7 +992,7 @@ static int process_pdta(SFData *sf, int size) return FALSE; } - if(!pdtahelper(sf, IMOD_ID, SF_MOD_SIZE, &chunk, &size)) + if(!pdtahelper(sf, IMOD_FCC, SF_MOD_SIZE, &chunk, &size)) { return FALSE; } @@ -953,7 +1002,7 @@ static int process_pdta(SFData *sf, int size) return FALSE; } - if(!pdtahelper(sf, IGEN_ID, SF_GEN_SIZE, &chunk, &size)) + if(!pdtahelper(sf, IGEN_FCC, SF_GEN_SIZE, &chunk, &size)) { return FALSE; } @@ -963,7 +1012,7 @@ static int process_pdta(SFData *sf, int size) return FALSE; } - if(!pdtahelper(sf, SHDR_ID, SF_SHDR_SIZE, &chunk, &size)) + if(!pdtahelper(sf, SHDR_FCC, SF_SHDR_SIZE, &chunk, &size)) { return FALSE; } |