summaryrefslogtreecommitdiff
path: root/libs/fluidsynth/src/fluid_sffile.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/fluidsynth/src/fluid_sffile.c')
-rw-r--r--libs/fluidsynth/src/fluid_sffile.c275
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;
}