1 /* FluidSynth - A Software Synthesizer
3 * Copyright (C) 2003 Peter Hanappe and others.
5 * SoundFont file loading code borrowed from Smurf SoundFont Editor
6 * Copyright (C) 1999-2001 Josh Green
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include "fluid_sffile.h"
26 #include "fluid_sfont.h"
27 #include "fluid_sys.h"
29 #if LIBSNDFILE_SUPPORT
33 /*=================================sfload.c========================
34 Borrowed from Smurf SoundFont Editor by Josh Green
35 =================================================================*/
37 /* FOURCC definitions */
38 #define RIFF_FCC FLUID_FOURCC('R','I','F','F')
39 #define LIST_FCC FLUID_FOURCC('L','I','S','T')
40 #define SFBK_FCC FLUID_FOURCC('s','f','b','k')
41 #define INFO_FCC FLUID_FOURCC('I','N','F','O')
42 #define SDTA_FCC FLUID_FOURCC('s','d','t','a')
43 #define PDTA_FCC FLUID_FOURCC('p','d','t','a') /* info/sample/preset */
45 #define IFIL_FCC FLUID_FOURCC('i','f','i','l')
46 #define ISNG_FCC FLUID_FOURCC('i','s','n','g')
47 #define INAM_FCC FLUID_FOURCC('I','N','A','M')
48 #define IROM_FCC FLUID_FOURCC('i','r','o','m') /* info ids (1st byte of info strings) */
49 #define IVER_FCC FLUID_FOURCC('i','v','e','r')
50 #define ICRD_FCC FLUID_FOURCC('I','C','R','D')
51 #define IENG_FCC FLUID_FOURCC('I','E','N','G')
52 #define IPRD_FCC FLUID_FOURCC('I','P','R','D') /* more info ids */
53 #define ICOP_FCC FLUID_FOURCC('I','C','O','P')
54 #define ICMT_FCC FLUID_FOURCC('I','C','M','T')
55 #define ISFT_FCC FLUID_FOURCC('I','S','F','T') /* and yet more info ids */
57 #define SNAM_FCC FLUID_FOURCC('s','n','a','m')
58 #define SMPL_FCC FLUID_FOURCC('s','m','p','l') /* sample ids */
59 #define PHDR_FCC FLUID_FOURCC('p','h','d','r')
60 #define PBAG_FCC FLUID_FOURCC('p','b','a','g')
61 #define PMOD_FCC FLUID_FOURCC('p','m','o','d')
62 #define PGEN_FCC FLUID_FOURCC('p','g','e','n') /* preset ids */
63 #define IHDR_FCC FLUID_FOURCC('i','n','s','t')
64 #define IBAG_FCC FLUID_FOURCC('i','b','a','g')
65 #define IMOD_FCC FLUID_FOURCC('i','m','o','d')
66 #define IGEN_FCC FLUID_FOURCC('i','g','e','n') /* instrument ids */
67 #define SHDR_FCC FLUID_FOURCC('s','h','d','r') /* sample info */
68 #define SM24_FCC FLUID_FOURCC('s','m','2','4')
70 /* Set when the FCC code is unknown */
71 #define UNKN_ID FLUID_N_ELEMENTS(idlist)
74 * This declares a uint32_t array containing the SF2 chunk identifiers.
76 static const uint32_t idlist[] =
111 /* generator types */
116 Gen_StartLoopAddrOfs,
118 Gen_StartAddrCoarseOfs,
126 Gen_EndAddrCoarseOfs,
159 Gen_StartLoopAddrCoarseOfs,
164 Gen_EndLoopAddrCoarseOfs,
176 #define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
177 #define Gen_Count Gen_Dummy /* count of generators */
178 #define GenArrSize sizeof(SFGenAmount) * Gen_Count /* gen array size */
181 static const unsigned short invalid_inst_gen[] =
193 static const unsigned short invalid_preset_gen[] =
197 Gen_StartLoopAddrOfs,
199 Gen_StartAddrCoarseOfs,
200 Gen_EndAddrCoarseOfs,
201 Gen_StartLoopAddrCoarseOfs,
204 Gen_EndLoopAddrCoarseOfs,
212 /* sfont file chunk sizes */
213 #define SF_PHDR_SIZE (38)
214 #define SF_BAG_SIZE (4)
215 #define SF_MOD_SIZE (10)
216 #define SF_GEN_SIZE (4)
217 #define SF_IHDR_SIZE (22)
218 #define SF_SHDR_SIZE (46)
221 #define READCHUNK(sf, var) \
224 if (sf->fcbs->fread(var, 8, sf->sffd) == FLUID_FAILED) \
226 ((SFChunk *)(var))->size = FLUID_LE32TOH(((SFChunk *)(var))->size); \
229 #define READD(sf, var) \
233 if (sf->fcbs->fread(&_temp, 4, sf->sffd) == FLUID_FAILED) \
235 var = FLUID_LE32TOH(_temp); \
238 #define READW(sf, var) \
242 if (sf->fcbs->fread(&_temp, 2, sf->sffd) == FLUID_FAILED) \
244 var = FLUID_LE16TOH(_temp); \
247 #define READID(sf, var) \
250 if (sf->fcbs->fread(var, 4, sf->sffd) == FLUID_FAILED) \
254 #define READSTR(sf, var) \
257 if (sf->fcbs->fread(var, 20, sf->sffd) == FLUID_FAILED) \
262 #define READB(sf, var) \
265 if (sf->fcbs->fread(&var, 1, sf->sffd) == FLUID_FAILED) \
269 #define FSKIP(sf, size) \
272 if (sf->fcbs->fseek(sf->sffd, size, SEEK_CUR) == FLUID_FAILED) \
279 if (sf->fcbs->fseek(sf->sffd, 2, SEEK_CUR) == FLUID_FAILED) \
283 /* removes and advances a fluid_list_t pointer */
284 #define SLADVREM(list, item) \
287 fluid_list_t *_temp = item; \
288 item = fluid_list_next(item); \
289 list = fluid_list_remove_link(list, _temp); \
290 delete1_fluid_list(_temp); \
294 static int load_header(SFData *sf);
295 static int load_body(SFData *sf);
296 static int process_info(SFData *sf, int size);
297 static int process_sdta(SFData *sf, unsigned int size);
298 static int process_pdta(SFData *sf, int size);
299 static int load_phdr(SFData *sf, int size);
300 static int load_pbag(SFData *sf, int size);
301 static int load_pmod(SFData *sf, int size);
302 static int load_pgen(SFData *sf, int size);
303 static int load_ihdr(SFData *sf, int size);
304 static int load_ibag(SFData *sf, int size);
305 static int load_imod(SFData *sf, int size);
306 static int load_igen(SFData *sf, int size);
307 static int load_shdr(SFData *sf, unsigned int size);
308 static int fixup_pgen(SFData *sf);
309 static int fixup_igen(SFData *sf);
311 static int chunkid(uint32_t id);
312 static int read_listchunk(SFData *sf, SFChunk *chunk);
313 static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size);
314 static int preset_compare_func(void *a, void *b);
315 static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist);
316 static int valid_inst_genid(unsigned short genid);
317 static int valid_preset_genid(unsigned short genid);
320 static void delete_preset(SFPreset *preset);
321 static void delete_inst(SFInst *inst);
322 static void delete_zone(SFZone *zone);
324 static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data);
325 static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24);
328 * Check if a file is a SoundFont file.
329 * @param filename Path to the file to check
330 * @return TRUE if it could be a SoundFont, FALSE otherwise
332 * @note The current implementation only checks for the "RIFF" and "sfbk" headers in
333 * the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
335 int fluid_is_soundfont(const char *filename)
337 FILE *fp = FLUID_FOPEN(filename, "rb");
348 if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)
358 if(FLUID_FSEEK(fp, 4, SEEK_CUR))
363 if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1)
368 retcode = (fcc == SFBK_FCC);
378 * Open a SoundFont file and parse it's contents into a SFData structure.
380 * @param fname filename
381 * @param fcbs file callback structure
382 * @return the partially parsed SoundFont as SFData structure or NULL on error
384 SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs)
389 if(!(sf = FLUID_NEW(SFData)))
391 FLUID_LOG(FLUID_ERR, "Out of memory");
395 FLUID_MEMSET(sf, 0, sizeof(SFData));
399 if((sf->sffd = fcbs->fopen(fname)) == NULL)
401 FLUID_LOG(FLUID_ERR, "Unable to open file '%s'", fname);
405 sf->fname = FLUID_STRDUP(fname);
407 if(sf->fname == NULL)
409 FLUID_LOG(FLUID_ERR, "Out of memory");
413 /* get size of file by seeking to end */
414 if(fcbs->fseek(sf->sffd, 0L, SEEK_END) == FLUID_FAILED)
416 FLUID_LOG(FLUID_ERR, "Seek to end of file failed");
420 if((fsize = fcbs->ftell(sf->sffd)) == FLUID_FAILED)
422 FLUID_LOG(FLUID_ERR, "Get end of file position failed");
426 sf->filesize = fsize;
428 if(fcbs->fseek(sf->sffd, 0, SEEK_SET) == FLUID_FAILED)
430 FLUID_LOG(FLUID_ERR, "Rewind to start of file failed");
442 fluid_sffile_close(sf);
447 * Parse all preset information from the soundfont
449 * @return FLUID_OK on success, otherwise FLUID_FAILED
451 int fluid_sffile_parse_presets(SFData *sf)
461 /* Load sample data from the soundfont file
463 * This function will always return the sample data in WAV format. If the sample_type specifies an
464 * Ogg Vorbis compressed sample, it will be decompressed automatically before returning.
466 * @param sf SFData instance
467 * @param sample_start index of first sample point in Soundfont sample chunk
468 * @param sample_end index of last sample point in Soundfont sample chunk
469 * @param sample_type type of the sample in Soundfont
470 * @param data pointer to sample data pointer, will point to loaded sample data on success
471 * @param data24 pointer to 24-bit sample data pointer if 24-bit data present, will point to loaded
472 * 24-bit sample data on success or NULL if no 24-bit data is present in file
474 * @return The number of sample words in returned buffers or -1 on failure
476 int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,
477 int sample_type, short **data, char **data24)
481 if(sample_type & FLUID_SAMPLETYPE_OGG_VORBIS)
483 num_samples = fluid_sffile_read_vorbis(sf, sample_start, sample_end, data);
487 num_samples = fluid_sffile_read_wav(sf, sample_start, sample_end, data, data24);
494 * Close a SoundFont file and free the SFData structure.
496 * @param sf pointer to SFData structure
497 * @param fcbs file callback structure
499 void fluid_sffile_close(SFData *sf)
507 sf->fcbs->fclose(sf->sffd);
510 FLUID_FREE(sf->fname);
516 FLUID_FREE(fluid_list_get(entry));
517 entry = fluid_list_next(entry);
520 delete_fluid_list(sf->info);
526 preset = (SFPreset *)fluid_list_get(entry);
527 delete_preset(preset);
528 entry = fluid_list_next(entry);
531 delete_fluid_list(sf->preset);
537 inst = (SFInst *)fluid_list_get(entry);
539 entry = fluid_list_next(entry);
542 delete_fluid_list(sf->inst);
548 FLUID_FREE(fluid_list_get(entry));
549 entry = fluid_list_next(entry);
552 delete_fluid_list(sf->sample);
562 /* sound font file load functions */
563 static int chunkid(uint32_t id)
567 for(i = 0; i < FLUID_N_ELEMENTS(idlist); i++)
575 /* Return chunk id or UNKN_ID if not found */
579 static int load_header(SFData *sf)
583 READCHUNK(sf, &chunk); /* load RIFF chunk */
585 if(chunk.id != RIFF_FCC)
587 /* error if not RIFF */
588 FLUID_LOG(FLUID_ERR, "Not a RIFF file");
592 READID(sf, &chunk.id); /* load file ID */
594 if(chunk.id != SFBK_FCC)
596 /* error if not SFBK_ID */
597 FLUID_LOG(FLUID_ERR, "Not a SoundFont file");
601 if(chunk.size != sf->filesize - 8)
603 FLUID_LOG(FLUID_ERR, "SoundFont file size mismatch");
607 /* Process INFO block */
608 if(!read_listchunk(sf, &chunk))
613 if(chunk.id != INFO_FCC)
615 FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting INFO chunk");
619 if(!process_info(sf, chunk.size))
624 /* Process sample chunk */
625 if(!read_listchunk(sf, &chunk))
630 if(chunk.id != SDTA_FCC)
632 FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting SAMPLE chunk");
636 if(!process_sdta(sf, chunk.size))
641 /* process HYDRA chunk */
642 if(!read_listchunk(sf, &chunk))
647 if(chunk.id != PDTA_FCC)
649 FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting HYDRA chunk");
653 sf->hydrapos = sf->fcbs->ftell(sf->sffd);
654 sf->hydrasize = chunk.size;
659 static int load_body(SFData *sf)
661 if(sf->fcbs->fseek(sf->sffd, sf->hydrapos, SEEK_SET) == FLUID_FAILED)
663 FLUID_LOG(FLUID_ERR, "Failed to seek to HYDRA position");
667 if(!process_pdta(sf, sf->hydrasize))
682 /* sort preset list by bank, preset # */
683 sf->preset = fluid_list_sort(sf->preset, (fluid_compare_func_t)preset_compare_func);
688 static int read_listchunk(SFData *sf, SFChunk *chunk)
690 READCHUNK(sf, chunk); /* read list chunk */
692 if(chunk->id != LIST_FCC) /* error if ! list chunk */
694 FLUID_LOG(FLUID_ERR, "Invalid chunk id in level 0 parse");
698 READID(sf, &chunk->id); /* read id string */
703 static int process_info(SFData *sf, int size)
715 READCHUNK(sf, &chunk);
718 if(chunk.id == IFIL_FCC)
720 /* sound font version chunk? */
723 FLUID_LOG(FLUID_ERR, "Sound font version info chunk has invalid size");
728 sf->version.major = ver;
730 sf->version.minor = ver;
732 if(sf->version.major < 2)
734 FLUID_LOG(FLUID_ERR, "Sound font version is %d.%d which is not"
735 " supported, convert to version 2.0x",
736 sf->version.major, sf->version.minor);
740 if(sf->version.major == 3)
742 #if !LIBSNDFILE_SUPPORT
743 FLUID_LOG(FLUID_WARN,
744 "Sound font version is %d.%d but fluidsynth was compiled without"
745 " support for (v3.x)",
746 sf->version.major, sf->version.minor);
750 else if(sf->version.major > 2)
752 FLUID_LOG(FLUID_WARN,
753 "Sound font version is %d.%d which is newer than"
754 " what this version of fluidsynth was designed for (v2.0x)",
755 sf->version.major, sf->version.minor);
759 else if(chunk.id == IVER_FCC)
761 /* ROM version chunk? */
764 FLUID_LOG(FLUID_ERR, "ROM version info chunk has invalid size");
769 sf->romver.major = ver;
771 sf->romver.minor = ver;
773 else if(chunkid(chunk.id) != UNKN_ID)
775 if((chunk.id != ICMT_FCC && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))
777 FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes",
778 &chunk.id, chunk.size);
782 /* alloc for chunk fcc and da chunk */
783 if(!(item.fcc = FLUID_MALLOC(chunk.size + sizeof(uint32_t) + 1)))
785 FLUID_LOG(FLUID_ERR, "Out of memory");
789 /* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */
790 sf->info = fluid_list_append(sf->info, item.fcc);
792 /* save chunk fcc and update pointer to data value */
793 *item.fcc++ = chunk.id;
795 if(sf->fcbs->fread(item.chr, chunk.size, sf->sffd) == FLUID_FAILED)
800 /* force terminate info item */
801 item.chr[chunk.size] = '\0';
805 FLUID_LOG(FLUID_ERR, "Invalid chunk id in INFO chunk");
814 FLUID_LOG(FLUID_ERR, "INFO chunk size mismatch");
821 static int process_sdta(SFData *sf, unsigned int size)
827 return TRUE; /* no sample data? */
831 READCHUNK(sf, &chunk);
834 if(chunk.id != SMPL_FCC)
836 FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead");
840 /* SDTA chunk may also contain sm24 chunk for 24 bit samples
841 * (not yet supported), only an error if SMPL chunk size is
842 * greater than SDTA. */
843 if(chunk.size > size)
845 FLUID_LOG(FLUID_ERR, "SDTA chunk size mismatch");
849 /* sample data follows */
850 sf->samplepos = sf->fcbs->ftell(sf->sffd);
852 /* used to check validity of sample headers */
853 sf->samplesize = chunk.size;
855 FSKIP(sf, chunk.size);
858 if(sf->version.major >= 2 && sf->version.minor >= 4)
860 /* any chance to find another chunk here? */
864 READCHUNK(sf, &chunk);
867 if(chunk.id == SM24_FCC)
869 int sm24size, sdtahalfsize;
871 FLUID_LOG(FLUID_DBG, "Found SM24 chunk");
873 if(chunk.size > size)
875 FLUID_LOG(FLUID_WARN, "SM24 exeeds SDTA chunk, ignoring SM24");
876 goto ret; // no error
879 sdtahalfsize = sf->samplesize / 2;
880 /* + 1 byte in the case that half the size of smpl chunk is an odd value */
881 sdtahalfsize += sdtahalfsize % 2;
882 sm24size = chunk.size;
884 if(sdtahalfsize != sm24size)
886 FLUID_LOG(FLUID_WARN, "SM24 not equal to half the size of SMPL chunk (0x%X != "
887 "0x%X), ignoring SM24",
888 sm24size, sdtahalfsize);
889 goto ret; // no error
892 /* sample data24 follows */
893 sf->sample24pos = sf->fcbs->ftell(sf->sffd);
894 sf->sample24size = sm24size;
905 static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size)
907 READCHUNK(sf, chunk);
910 if(chunk->id != expid)
912 FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", &expid);
916 if(chunk->size % reclen) /* valid chunk size? */
918 FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", &expid, reclen);
922 if((*size -= chunk->size) < 0)
924 FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", &expid);
931 static int process_pdta(SFData *sf, int size)
935 if(!pdtahelper(sf, PHDR_FCC, SF_PHDR_SIZE, &chunk, &size))
940 if(!load_phdr(sf, chunk.size))
945 if(!pdtahelper(sf, PBAG_FCC, SF_BAG_SIZE, &chunk, &size))
950 if(!load_pbag(sf, chunk.size))
955 if(!pdtahelper(sf, PMOD_FCC, SF_MOD_SIZE, &chunk, &size))
960 if(!load_pmod(sf, chunk.size))
965 if(!pdtahelper(sf, PGEN_FCC, SF_GEN_SIZE, &chunk, &size))
970 if(!load_pgen(sf, chunk.size))
975 if(!pdtahelper(sf, IHDR_FCC, SF_IHDR_SIZE, &chunk, &size))
980 if(!load_ihdr(sf, chunk.size))
985 if(!pdtahelper(sf, IBAG_FCC, SF_BAG_SIZE, &chunk, &size))
990 if(!load_ibag(sf, chunk.size))
995 if(!pdtahelper(sf, IMOD_FCC, SF_MOD_SIZE, &chunk, &size))
1000 if(!load_imod(sf, chunk.size))
1005 if(!pdtahelper(sf, IGEN_FCC, SF_GEN_SIZE, &chunk, &size))
1010 if(!load_igen(sf, chunk.size))
1015 if(!pdtahelper(sf, SHDR_FCC, SF_SHDR_SIZE, &chunk, &size))
1020 if(!load_shdr(sf, chunk.size))
1028 /* preset header loader */
1029 static int load_phdr(SFData *sf, int size)
1032 SFPreset *preset, *prev_preset = NULL;
1033 unsigned short pbag_idx, prev_pbag_idx = 0;
1035 if(size % SF_PHDR_SIZE || size == 0)
1037 FLUID_LOG(FLUID_ERR, "Preset header chunk size is invalid");
1041 i = size / SF_PHDR_SIZE - 1;
1045 /* at least one preset + term record */
1046 FLUID_LOG(FLUID_WARN, "File contains no presets");
1047 FSKIP(sf, SF_PHDR_SIZE);
1053 /* load all preset headers */
1054 if((preset = FLUID_NEW(SFPreset)) == NULL)
1056 FLUID_LOG(FLUID_ERR, "Out of memory");
1060 sf->preset = fluid_list_append(sf->preset, preset);
1061 preset->zone = NULL; /* In case of failure, fluid_sffile_close can cleanup */
1062 READSTR(sf, &preset->name); /* possible read failure ^ */
1063 READW(sf, preset->prenum);
1064 READW(sf, preset->bank);
1065 READW(sf, pbag_idx);
1066 READD(sf, preset->libr);
1067 READD(sf, preset->genre);
1068 READD(sf, preset->morph);
1072 /* not first preset? */
1073 if(pbag_idx < prev_pbag_idx)
1075 FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");
1079 i2 = pbag_idx - prev_pbag_idx;
1083 prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);
1086 else if(pbag_idx > 0) /* 1st preset, warn if ofs >0 */
1088 FLUID_LOG(FLUID_WARN, "%d preset zones not referenced, discarding", pbag_idx);
1091 prev_preset = preset; /* update preset ptr */
1092 prev_pbag_idx = pbag_idx;
1096 READW(sf, pbag_idx); /* Read terminal generator index */
1099 if(pbag_idx < prev_pbag_idx)
1101 FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");
1105 i2 = pbag_idx - prev_pbag_idx;
1109 prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);
1115 /* preset bag loader */
1116 static int load_pbag(SFData *sf, int size)
1118 fluid_list_t *p, *p2;
1119 SFZone *z, *pz = NULL;
1120 unsigned short genndx, modndx;
1121 unsigned short pgenndx = 0, pmodndx = 0;
1124 if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */
1126 FLUID_LOG(FLUID_ERR, "Preset bag chunk size is invalid");
1134 /* traverse through presets */
1135 p2 = ((SFPreset *)(p->data))->zone;
1139 /* traverse preset's zones */
1140 if((size -= SF_BAG_SIZE) < 0)
1142 FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");
1146 if((z = FLUID_NEW(SFZone)) == NULL)
1148 FLUID_LOG(FLUID_ERR, "Out of memory");
1153 z->gen = NULL; /* Init gen and mod before possible failure, */
1154 z->mod = NULL; /* to ensure proper cleanup (fluid_sffile_close) */
1155 READW(sf, genndx); /* possible read failure ^ */
1161 /* if not first zone */
1162 if(genndx < pgenndx)
1164 FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");
1168 if(modndx < pmodndx)
1170 FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");
1174 i = genndx - pgenndx;
1178 pz->gen = fluid_list_prepend(pz->gen, NULL);
1181 i = modndx - pmodndx;
1185 pz->mod = fluid_list_prepend(pz->mod, NULL);
1189 pz = z; /* update previous zone ptr */
1190 pgenndx = genndx; /* update previous zone gen index */
1191 pmodndx = modndx; /* update previous zone mod index */
1192 p2 = fluid_list_next(p2);
1195 p = fluid_list_next(p);
1198 size -= SF_BAG_SIZE;
1202 FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");
1213 FLUID_LOG(FLUID_WARN, "No preset generators and terminal index not 0");
1218 FLUID_LOG(FLUID_WARN, "No preset modulators and terminal index not 0");
1224 if(genndx < pgenndx)
1226 FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");
1230 if(modndx < pmodndx)
1232 FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");
1236 i = genndx - pgenndx;
1240 pz->gen = fluid_list_prepend(pz->gen, NULL);
1243 i = modndx - pmodndx;
1247 pz->mod = fluid_list_prepend(pz->mod, NULL);
1253 /* preset modulator loader */
1254 static int load_pmod(SFData *sf, int size)
1256 fluid_list_t *p, *p2, *p3;
1263 /* traverse through all presets */
1264 p2 = ((SFPreset *)(p->data))->zone;
1268 /* traverse this preset's zones */
1269 p3 = ((SFZone *)(p2->data))->mod;
1273 /* load zone's modulators */
1274 if((size -= SF_MOD_SIZE) < 0)
1276 FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");
1280 if((m = FLUID_NEW(SFMod)) == NULL)
1282 FLUID_LOG(FLUID_ERR, "Out of memory");
1289 READW(sf, m->amount);
1290 READW(sf, m->amtsrc);
1291 READW(sf, m->trans);
1292 p3 = fluid_list_next(p3);
1295 p2 = fluid_list_next(p2);
1298 p = fluid_list_next(p);
1302 If there isn't even a terminal record
1303 Hmmm, the specs say there should be one, but..
1310 size -= SF_MOD_SIZE;
1314 FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");
1318 FSKIP(sf, SF_MOD_SIZE); /* terminal mod */
1323 /* -------------------------------------------------------------------
1324 * preset generator loader
1325 * generator (per preset) loading rules:
1326 * Zones with no generators or modulators shall be annihilated
1327 * Global zone must be 1st zone, discard additional ones (instrumentless zones)
1329 * generator (per zone) loading rules (in order of decreasing precedence):
1330 * KeyRange is 1st in list (if exists), else discard
1331 * if a VelRange exists only preceded by a KeyRange, else discard
1332 * if a generator follows an instrument discard it
1333 * if a duplicate generator exists replace previous one
1334 * ------------------------------------------------------------------- */
1335 static int load_pgen(SFData *sf, int size)
1337 fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
1341 unsigned short genid;
1342 int level, skip, drop, gzone, discarded;
1348 /* traverse through all presets */
1351 p2 = ((SFPreset *)(p->data))->zone;
1360 /* traverse preset's zones */
1362 z = (SFZone *)(p2->data);
1367 /* load zone's generators */
1372 if((size -= SF_GEN_SIZE) < 0)
1374 FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
1380 if(genid == Gen_KeyRange)
1382 /* nothing precedes */
1386 READB(sf, genval.range.lo);
1387 READB(sf, genval.range.hi);
1394 else if(genid == Gen_VelRange)
1396 /* only KeyRange precedes */
1400 READB(sf, genval.range.lo);
1401 READB(sf, genval.range.hi);
1408 else if(genid == Gen_Instrument)
1410 /* inst is last gen */
1412 READW(sf, genval.uword);
1413 ((SFZone *)(p2->data))->instsamp = FLUID_INT_TO_POINTER(genval.uword + 1);
1414 break; /* break out of generator loop */
1420 if(valid_preset_genid(genid))
1422 /* generator valid? */
1423 READW(sf, genval.sword);
1424 dup = find_gen_by_id(genid, z->gen);
1436 /* if gen ! dup alloc new */
1437 if((g = FLUID_NEW(SFGen)) == NULL)
1439 FLUID_LOG(FLUID_ERR, "Out of memory");
1448 g = (SFGen *)(dup->data); /* ptr to orig gen */
1456 /* Skip this generator */
1464 p3 = fluid_list_next(p3); /* next gen */
1468 SLADVREM(z->gen, p3); /* drop place holder */
1471 } /* generator loop */
1475 SLADVREM(z->gen, p3); /* zone has inst? */
1479 /* congratulations its a global zone */
1482 /* Prior global zones? */
1485 /* if global zone is not 1st zone, relocate */
1488 void *save = p2->data;
1489 FLUID_LOG(FLUID_WARN, "Preset '%s': Global zone is not first zone",
1490 ((SFPreset *)(p->data))->name);
1492 *hz = fluid_list_prepend(*hz, save);
1498 /* previous global zone exists, discard */
1499 FLUID_LOG(FLUID_WARN, "Preset '%s': Discarding invalid global zone",
1500 ((SFPreset *)(p->data))->name);
1501 *hz = fluid_list_remove(*hz, p2->data);
1502 delete_zone((SFZone *)fluid_list_get(p2));
1508 /* Kill any zones following an instrument */
1511 if((size -= SF_GEN_SIZE) < 0)
1513 FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
1517 FSKIP(sf, SF_GEN_SIZE);
1518 SLADVREM(z->gen, p3);
1521 p2 = fluid_list_next(p2); /* next zone */
1526 FLUID_LOG(FLUID_WARN,
1527 "Preset '%s': Some invalid generators were discarded",
1528 ((SFPreset *)(p->data))->name);
1531 p = fluid_list_next(p);
1534 /* in case there isn't a terminal record */
1540 size -= SF_GEN_SIZE;
1544 FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
1548 FSKIP(sf, SF_GEN_SIZE); /* terminal gen */
1553 /* instrument header loader */
1554 static int load_ihdr(SFData *sf, int size)
1557 SFInst *p, *pr = NULL; /* ptr to current & previous instrument */
1558 unsigned short zndx, pzndx = 0;
1560 if(size % SF_IHDR_SIZE || size == 0) /* chunk size is valid? */
1562 FLUID_LOG(FLUID_ERR, "Instrument header has invalid size");
1566 size = size / SF_IHDR_SIZE - 1;
1570 /* at least one preset + term record */
1571 FLUID_LOG(FLUID_WARN, "File contains no instruments");
1572 FSKIP(sf, SF_IHDR_SIZE);
1576 for(i = 0; i < size; i++)
1578 /* load all instrument headers */
1579 if((p = FLUID_NEW(SFInst)) == NULL)
1581 FLUID_LOG(FLUID_ERR, "Out of memory");
1585 sf->inst = fluid_list_append(sf->inst, p);
1586 p->zone = NULL; /* For proper cleanup if fail (fluid_sffile_close) */
1588 READSTR(sf, &p->name); /* Possible read failure ^ */
1593 /* not first instrument? */
1596 FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");
1604 pr->zone = fluid_list_prepend(pr->zone, NULL);
1607 else if(zndx > 0) /* 1st inst, warn if ofs >0 */
1609 FLUID_LOG(FLUID_WARN, "%d instrument zones not referenced, discarding", zndx);
1613 pr = p; /* update instrument ptr */
1621 FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");
1629 pr->zone = fluid_list_prepend(pr->zone, NULL);
1635 /* instrument bag loader */
1636 static int load_ibag(SFData *sf, int size)
1638 fluid_list_t *p, *p2;
1639 SFZone *z, *pz = NULL;
1640 unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0;
1643 if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */
1645 FLUID_LOG(FLUID_ERR, "Instrument bag chunk size is invalid");
1653 /* traverse through inst */
1654 p2 = ((SFInst *)(p->data))->zone;
1658 /* load this inst's zones */
1659 if((size -= SF_BAG_SIZE) < 0)
1661 FLUID_LOG(FLUID_ERR, "Instrument bag chunk size mismatch");
1665 if((z = FLUID_NEW(SFZone)) == NULL)
1667 FLUID_LOG(FLUID_ERR, "Out of memory");
1672 z->gen = NULL; /* In case of failure, */
1673 z->mod = NULL; /* fluid_sffile_close can clean up */
1674 READW(sf, genndx); /* READW = possible read failure */
1680 /* if not first zone */
1681 if(genndx < pgenndx)
1683 FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");
1687 if(modndx < pmodndx)
1689 FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");
1693 i = genndx - pgenndx;
1697 pz->gen = fluid_list_prepend(pz->gen, NULL);
1700 i = modndx - pmodndx;
1704 pz->mod = fluid_list_prepend(pz->mod, NULL);
1708 pz = z; /* update previous zone ptr */
1711 p2 = fluid_list_next(p2);
1714 p = fluid_list_next(p);
1717 size -= SF_BAG_SIZE;
1721 FLUID_LOG(FLUID_ERR, "Instrument chunk size mismatch");
1730 /* in case that all are no zoners */
1733 FLUID_LOG(FLUID_WARN, "No instrument generators and terminal index not 0");
1738 FLUID_LOG(FLUID_WARN, "No instrument modulators and terminal index not 0");
1744 if(genndx < pgenndx)
1746 FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");
1750 if(modndx < pmodndx)
1752 FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");
1756 i = genndx - pgenndx;
1760 pz->gen = fluid_list_prepend(pz->gen, NULL);
1763 i = modndx - pmodndx;
1767 pz->mod = fluid_list_prepend(pz->mod, NULL);
1773 /* instrument modulator loader */
1774 static int load_imod(SFData *sf, int size)
1776 fluid_list_t *p, *p2, *p3;
1783 /* traverse through all inst */
1784 p2 = ((SFInst *)(p->data))->zone;
1788 /* traverse this inst's zones */
1789 p3 = ((SFZone *)(p2->data))->mod;
1793 /* load zone's modulators */
1794 if((size -= SF_MOD_SIZE) < 0)
1796 FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");
1800 if((m = FLUID_NEW(SFMod)) == NULL)
1802 FLUID_LOG(FLUID_ERR, "Out of memory");
1809 READW(sf, m->amount);
1810 READW(sf, m->amtsrc);
1811 READW(sf, m->trans);
1812 p3 = fluid_list_next(p3);
1815 p2 = fluid_list_next(p2);
1818 p = fluid_list_next(p);
1822 If there isn't even a terminal record
1823 Hmmm, the specs say there should be one, but..
1830 size -= SF_MOD_SIZE;
1834 FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");
1838 FSKIP(sf, SF_MOD_SIZE); /* terminal mod */
1843 /* load instrument generators (see load_pgen for loading rules) */
1844 static int load_igen(SFData *sf, int size)
1846 fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
1850 unsigned short genid;
1851 int level, skip, drop, gzone, discarded;
1857 /* traverse through all instruments */
1860 p2 = ((SFInst *)(p->data))->zone;
1869 /* traverse this instrument's zones */
1871 z = (SFZone *)(p2->data);
1876 /* load zone's generators */
1881 if((size -= SF_GEN_SIZE) < 0)
1883 FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");
1889 if(genid == Gen_KeyRange)
1891 /* nothing precedes */
1895 READB(sf, genval.range.lo);
1896 READB(sf, genval.range.hi);
1903 else if(genid == Gen_VelRange)
1905 /* only KeyRange precedes */
1909 READB(sf, genval.range.lo);
1910 READB(sf, genval.range.hi);
1917 else if(genid == Gen_SampleId)
1919 /* sample is last gen */
1921 READW(sf, genval.uword);
1922 ((SFZone *)(p2->data))->instsamp = FLUID_INT_TO_POINTER(genval.uword + 1);
1923 break; /* break out of generator loop */
1929 if(valid_inst_genid(genid))
1932 READW(sf, genval.sword);
1933 dup = find_gen_by_id(genid, z->gen);
1945 /* if gen ! dup alloc new */
1946 if((g = FLUID_NEW(SFGen)) == NULL)
1948 FLUID_LOG(FLUID_ERR, "Out of memory");
1957 g = (SFGen *)(dup->data);
1965 /* skip this generator */
1973 p3 = fluid_list_next(p3); /* next gen */
1977 SLADVREM(z->gen, p3);
1980 } /* generator loop */
1984 SLADVREM(z->gen, p3); /* zone has sample? */
1988 /* its a global zone */
1993 /* if global zone is not 1st zone, relocate */
1996 void *save = p2->data;
1997 FLUID_LOG(FLUID_WARN, "Instrument '%s': Global zone is not first zone",
1998 ((SFPreset *)(p->data))->name);
2000 *hz = fluid_list_prepend(*hz, save);
2006 /* previous global zone exists, discard */
2007 FLUID_LOG(FLUID_WARN, "Instrument '%s': Discarding invalid global zone",
2008 ((SFInst *)(p->data))->name);
2009 *hz = fluid_list_remove(*hz, p2->data);
2010 delete_zone((SFZone *)fluid_list_get(p2));
2016 /* Kill any zones following a sample */
2019 if((size -= SF_GEN_SIZE) < 0)
2021 FLUID_LOG(FLUID_ERR, "Instrument generator chunk size mismatch");
2025 FSKIP(sf, SF_GEN_SIZE);
2026 SLADVREM(z->gen, p3);
2029 p2 = fluid_list_next(p2); /* next zone */
2034 FLUID_LOG(FLUID_WARN,
2035 "Instrument '%s': Some invalid generators were discarded",
2036 ((SFInst *)(p->data))->name);
2039 p = fluid_list_next(p);
2042 /* for those non-terminal record cases, grr! */
2048 size -= SF_GEN_SIZE;
2052 FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");
2056 FSKIP(sf, SF_GEN_SIZE); /* terminal gen */
2061 /* sample header loader */
2062 static int load_shdr(SFData *sf, unsigned int size)
2067 if(size % SF_SHDR_SIZE || size == 0) /* size is multiple of SHDR size? */
2069 FLUID_LOG(FLUID_ERR, "Sample header has invalid size");
2073 size = size / SF_SHDR_SIZE - 1;
2077 /* at least one sample + term record? */
2078 FLUID_LOG(FLUID_WARN, "File contains no samples");
2079 FSKIP(sf, SF_SHDR_SIZE);
2083 /* load all sample headers */
2084 for(i = 0; i < size; i++)
2086 if((p = FLUID_NEW(SFSample)) == NULL)
2088 FLUID_LOG(FLUID_ERR, "Out of memory");
2092 sf->sample = fluid_list_append(sf->sample, p);
2093 READSTR(sf, &p->name);
2094 READD(sf, p->start);
2096 READD(sf, p->loopstart);
2097 READD(sf, p->loopend);
2098 READD(sf, p->samplerate);
2099 READB(sf, p->origpitch);
2100 READB(sf, p->pitchadj);
2101 FSKIPW(sf); /* skip sample link */
2102 READW(sf, p->sampletype);
2106 FSKIP(sf, SF_SHDR_SIZE); /* skip terminal shdr */
2111 /* "fixup" (inst # -> inst ptr) instrument references in preset list */
2112 static int fixup_pgen(SFData *sf)
2114 fluid_list_t *p, *p2, *p3;
2122 p2 = ((SFPreset *)(p->data))->zone;
2126 /* traverse this preset's zones */
2127 z = (SFZone *)(p2->data);
2129 if((i = FLUID_POINTER_TO_INT(z->instsamp)))
2131 /* load instrument # */
2132 p3 = fluid_list_nth(sf->inst, i - 1);
2136 FLUID_LOG(FLUID_ERR, "Preset %03d %03d: Invalid instrument reference",
2137 ((SFPreset *)(p->data))->bank, ((SFPreset *)(p->data))->prenum);
2148 p2 = fluid_list_next(p2);
2151 p = fluid_list_next(p);
2157 /* "fixup" (sample # -> sample ptr) sample references in instrument list */
2158 static int fixup_igen(SFData *sf)
2160 fluid_list_t *p, *p2, *p3;
2168 p2 = ((SFInst *)(p->data))->zone;
2172 /* traverse instrument's zones */
2173 z = (SFZone *)(p2->data);
2175 if((i = FLUID_POINTER_TO_INT(z->instsamp)))
2178 p3 = fluid_list_nth(sf->sample, i - 1);
2182 FLUID_LOG(FLUID_ERR, "Instrument '%s': Invalid sample reference",
2183 ((SFInst *)(p->data))->name);
2190 p2 = fluid_list_next(p2);
2193 p = fluid_list_next(p);
2199 static void delete_preset(SFPreset *preset)
2201 fluid_list_t *entry;
2209 entry = preset->zone;
2213 zone = (SFZone *)fluid_list_get(entry);
2215 entry = fluid_list_next(entry);
2218 delete_fluid_list(preset->zone);
2223 static void delete_inst(SFInst *inst)
2225 fluid_list_t *entry;
2237 zone = (SFZone *)fluid_list_get(entry);
2239 entry = fluid_list_next(entry);
2242 delete_fluid_list(inst->zone);
2248 /* Free all elements of a zone (Preset or Instrument) */
2249 static void delete_zone(SFZone *zone)
2251 fluid_list_t *entry;
2262 FLUID_FREE(fluid_list_get(entry));
2263 entry = fluid_list_next(entry);
2266 delete_fluid_list(zone->gen);
2272 FLUID_FREE(fluid_list_get(entry));
2273 entry = fluid_list_next(entry);
2276 delete_fluid_list(zone->mod);
2281 /* preset sort function, first by bank, then by preset # */
2282 static int preset_compare_func(void *a, void *b)
2286 aval = (int)(((SFPreset *)a)->bank) << 16 | ((SFPreset *)a)->prenum;
2287 bval = (int)(((SFPreset *)b)->bank) << 16 | ((SFPreset *)b)->prenum;
2289 return (aval - bval);
2292 /* Find a generator by its id in the passed in list.
2294 * @return pointer to SFGen if found, otherwise NULL
2296 static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist)
2298 /* is generator in gen list? */
2310 if(gen == ((SFGen *)p->data)->id)
2315 p = fluid_list_next(p);
2321 /* check validity of instrument generator */
2322 static int valid_inst_genid(unsigned short genid)
2326 if(genid > Gen_MaxValid)
2331 while(invalid_inst_gen[i] && invalid_inst_gen[i] != genid)
2336 return (invalid_inst_gen[i] == 0);
2339 /* check validity of preset generator */
2340 static int valid_preset_genid(unsigned short genid)
2344 if(!valid_inst_genid(genid))
2349 while(invalid_preset_gen[i] && invalid_preset_gen[i] != genid)
2354 return (invalid_preset_gen[i] == 0);
2358 static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24)
2360 short *loaded_data = NULL;
2361 char *loaded_data24 = NULL;
2363 int num_samples = (end + 1) - start;
2364 fluid_return_val_if_fail(num_samples > 0, -1);
2366 if((start * sizeof(short) > sf->samplesize) || (end * sizeof(short) > sf->samplesize))
2368 FLUID_LOG(FLUID_ERR, "Sample offsets exceed sample data chunk");
2372 /* Load 16-bit sample data */
2373 if(sf->fcbs->fseek(sf->sffd, sf->samplepos + (start * sizeof(short)), SEEK_SET) == FLUID_FAILED)
2375 FLUID_LOG(FLUID_ERR, "Failed to seek to sample position");
2379 loaded_data = FLUID_ARRAY(short, num_samples);
2381 if(loaded_data == NULL)
2383 FLUID_LOG(FLUID_ERR, "Out of memory");
2387 if(sf->fcbs->fread(loaded_data, num_samples * sizeof(short), sf->sffd) == FLUID_FAILED)
2389 FLUID_LOG(FLUID_ERR, "Failed to read sample data");
2393 /* If this machine is big endian, byte swap the 16 bit samples */
2394 if(FLUID_IS_BIG_ENDIAN)
2398 for(i = 0; i < num_samples; i++)
2400 loaded_data[i] = FLUID_LE16TOH(loaded_data[i]);
2404 *data = loaded_data;
2406 /* Optionally load additional 8 bit sample data for 24-bit support. Any failures while loading
2407 * the 24-bit sample data will be logged as errors but won't prevent the sample reading to
2408 * fail, as sound output is still possible with the 16-bit sample data. */
2411 if((start > sf->sample24size) || (end > sf->sample24size))
2413 FLUID_LOG(FLUID_ERR, "Sample offsets exceed 24-bit sample data chunk");
2417 if(sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED)
2419 FLUID_LOG(FLUID_ERR, "Failed to seek position for 24-bit sample data in data file");
2423 loaded_data24 = FLUID_ARRAY(char, num_samples);
2425 if(loaded_data24 == NULL)
2427 FLUID_LOG(FLUID_ERR, "Out of memory reading 24-bit sample data");
2431 if(sf->fcbs->fread(loaded_data24, num_samples, sf->sffd) == FLUID_FAILED)
2433 FLUID_LOG(FLUID_ERR, "Failed to read 24-bit sample data");
2438 *data24 = loaded_data24;
2443 FLUID_LOG(FLUID_WARN, "Ignoring 24-bit sample data, sound quality might suffer");
2444 FLUID_FREE(loaded_data24);
2449 FLUID_FREE(loaded_data);
2450 FLUID_FREE(loaded_data24);
2455 /* Ogg Vorbis loading and decompression */
2456 #if LIBSNDFILE_SUPPORT
2458 /* Virtual file access rountines to allow loading individually compressed
2459 * samples from the Soundfont sample data chunk using the file callbacks
2460 * passing in during opening of the file */
2461 typedef struct _sfvio_data_t
2464 sf_count_t start; /* start byte offset of compressed data */
2465 sf_count_t end; /* end byte offset of compressed data */
2466 sf_count_t offset; /* current virtual file offset from start byte offset */
2470 static sf_count_t sfvio_get_filelen(void *user_data)
2472 sfvio_data_t *data = user_data;
2474 return (data->end + 1) - data->start;
2477 static sf_count_t sfvio_seek(sf_count_t offset, int whence, void *user_data)
2479 sfvio_data_t *data = user_data;
2480 SFData *sf = data->sffile;
2481 sf_count_t new_offset;
2486 new_offset = offset;
2490 new_offset = data->offset + offset;
2494 new_offset = sfvio_get_filelen(user_data) + offset;
2498 goto fail; /* proper error handling not possible?? */
2501 if(sf->fcbs->fseek(sf->sffd, sf->samplepos + data->start + new_offset, SEEK_SET) != FLUID_FAILED)
2503 data->offset = new_offset;
2507 return data->offset;
2510 static sf_count_t sfvio_read(void *ptr, sf_count_t count, void *user_data)
2512 sfvio_data_t *data = user_data;
2513 SFData *sf = data->sffile;
2516 remain = sfvio_get_filelen(user_data) - data->offset;
2528 if(sf->fcbs->fread(ptr, count, sf->sffd) == FLUID_FAILED)
2530 FLUID_LOG(FLUID_ERR, "Failed to read compressed sample data");
2534 data->offset += count;
2539 static sf_count_t sfvio_tell(void *user_data)
2541 sfvio_data_t *data = user_data;
2543 return data->offset;
2547 * Read Ogg Vorbis compressed data from the Soundfont and decompress it, returning the number of samples
2548 * in the decompressed WAV. Only 16-bit mono samples are supported.
2550 * Note that this function takes byte indices for start and end source data. The sample headers in SF3
2551 * files use byte indices, so those pointers can be passed directly to this function.
2553 * This function uses a virtual file structure in order to read the Ogg Vorbis
2554 * data from arbitrary locations in the source file.
2556 static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)
2560 SF_VIRTUAL_IO sfvio =
2568 sfvio_data_t sfdata;
2569 short *wav_data = NULL;
2571 if((start_byte > sf->samplesize) || (end_byte > sf->samplesize))
2573 FLUID_LOG(FLUID_ERR, "Ogg Vorbis data offsets exceed sample data chunk");
2577 // Initialize file position indicator and SF_INFO structure
2579 sfdata.start = start_byte;
2580 sfdata.end = end_byte;
2583 memset(&sfinfo, 0, sizeof(sfinfo));
2585 /* Seek to beginning of Ogg Vorbis data in Soundfont */
2586 if(sf->fcbs->fseek(sf->sffd, sf->samplepos + start_byte, SEEK_SET) == FLUID_FAILED)
2588 FLUID_LOG(FLUID_ERR, "Failed to seek to compressd sample position");
2592 // Open sample as a virtual file
2593 sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, &sfdata);
2597 FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
2602 if(!sfinfo.frames || !sfinfo.channels)
2604 FLUID_LOG(FLUID_DBG, "Empty decompressed sample");
2610 /* FIXME: ensure that the decompressed WAV data is 16-bit mono? */
2612 wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels);
2616 FLUID_LOG(FLUID_ERR, "Out of memory");
2620 /* Automatically decompresses the Ogg Vorbis data to 16-bit WAV */
2621 if(sf_readf_short(sndfile, wav_data, sfinfo.frames) < sfinfo.frames)
2623 FLUID_LOG(FLUID_DBG, "Decompression failed!");
2624 FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
2632 return sfinfo.frames;
2635 FLUID_FREE(wav_data);
2640 static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)