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 =================================================================*/
38 functions for loading data from sfont files, with appropriate byte swapping
39 on big endian machines. Sfont IDs are not swapped because the ID read is
40 equivalent to the matching ID list in memory regardless of LE/BE machine
43 /* sf file chunk IDs */
52 PDTA_ID, /* info/sample/preset */
57 IROM_ID, /* info ids (1st byte of info strings) */
61 IPRD_ID, /* more info ids */
64 ISFT_ID, /* and yet more info ids */
67 SMPL_ID, /* sample ids */
71 PGEN_ID, /* preset ids */
75 IGEN_ID, /* instrument ids */
76 SHDR_ID, /* sample info */
81 * This declares a char array containing the SF2 chunk identifiers. This
82 * array is being accessed like an uint32 below to simplify id comparison.
83 * To make sure it is suitably aligned for uint32 access, we must wrap it
84 * inside a union along with a uint32 telling the compiler to align it
85 * for integer access and avoiding undefined behaviour.
86 * This basically is the C89 equivalent to what is written in C11 as:
87 * alignas(uint32_t) static const char idlist[] = {};
89 * See: EXP36-C. Do not cast pointers into more strictly aligned pointer
90 * types - SEI CERT C Coding Standard
92 static const union fluid_idlist
95 * Cannot be char c[ ], because in C89, arrays wraped in unions
96 * must have a fixed size. Otherwise the size of the union would depend
97 * on the initialization of its first member, which results in
98 * different sizes for different instances of the same union type.
102 } idlist = {"RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD"
103 "ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdrsm24"
107 /* generator types */
112 Gen_StartLoopAddrOfs,
114 Gen_StartAddrCoarseOfs,
122 Gen_EndAddrCoarseOfs,
155 Gen_StartLoopAddrCoarseOfs,
160 Gen_EndLoopAddrCoarseOfs,
172 #define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
173 #define Gen_Count Gen_Dummy /* count of generators */
174 #define GenArrSize sizeof(SFGenAmount) * Gen_Count /* gen array size */
177 static const unsigned short invalid_inst_gen[] =
189 static const unsigned short invalid_preset_gen[] =
193 Gen_StartLoopAddrOfs,
195 Gen_StartAddrCoarseOfs,
196 Gen_EndAddrCoarseOfs,
197 Gen_StartLoopAddrCoarseOfs,
200 Gen_EndLoopAddrCoarseOfs,
208 #define CHNKIDSTR(id) &idlist.c[(id - 1) * 4]
210 /* sfont file chunk sizes */
211 #define SF_PHDR_SIZE (38)
212 #define SF_BAG_SIZE (4)
213 #define SF_MOD_SIZE (10)
214 #define SF_GEN_SIZE (4)
215 #define SF_IHDR_SIZE (22)
216 #define SF_SHDR_SIZE (46)
219 #define READCHUNK(sf, var) \
222 if (sf->fcbs->fread(var, 8, sf->sffd) == FLUID_FAILED) \
224 ((SFChunk *)(var))->size = FLUID_LE32TOH(((SFChunk *)(var))->size); \
227 #define READD(sf, var) \
231 if (sf->fcbs->fread(&_temp, 4, sf->sffd) == FLUID_FAILED) \
233 var = FLUID_LE32TOH(_temp); \
236 #define READW(sf, var) \
240 if (sf->fcbs->fread(&_temp, 2, sf->sffd) == FLUID_FAILED) \
242 var = FLUID_LE16TOH(_temp); \
245 #define READID(sf, var) \
248 if (sf->fcbs->fread(var, 4, sf->sffd) == FLUID_FAILED) \
252 #define READSTR(sf, var) \
255 if (sf->fcbs->fread(var, 20, sf->sffd) == FLUID_FAILED) \
260 #define READB(sf, var) \
263 if (sf->fcbs->fread(&var, 1, sf->sffd) == FLUID_FAILED) \
267 #define FSKIP(sf, size) \
270 if (sf->fcbs->fseek(sf->sffd, size, SEEK_CUR) == FLUID_FAILED) \
277 if (sf->fcbs->fseek(sf->sffd, 2, SEEK_CUR) == FLUID_FAILED) \
281 /* removes and advances a fluid_list_t pointer */
282 #define SLADVREM(list, item) \
285 fluid_list_t *_temp = item; \
286 item = fluid_list_next(item); \
287 list = fluid_list_remove_link(list, _temp); \
288 delete1_fluid_list(_temp); \
292 static int load_header(SFData *sf);
293 static int load_body(SFData *sf);
294 static int process_info(SFData *sf, int size);
295 static int process_sdta(SFData *sf, unsigned int size);
296 static int process_pdta(SFData *sf, int size);
297 static int load_phdr(SFData *sf, int size);
298 static int load_pbag(SFData *sf, int size);
299 static int load_pmod(SFData *sf, int size);
300 static int load_pgen(SFData *sf, int size);
301 static int load_ihdr(SFData *sf, int size);
302 static int load_ibag(SFData *sf, int size);
303 static int load_imod(SFData *sf, int size);
304 static int load_igen(SFData *sf, int size);
305 static int load_shdr(SFData *sf, unsigned int size);
306 static int fixup_pgen(SFData *sf);
307 static int fixup_igen(SFData *sf);
309 static int chunkid(uint32_t id);
310 static int read_listchunk(SFData *sf, SFChunk *chunk);
311 static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size);
312 static int preset_compare_func(void *a, void *b);
313 static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist);
314 static int valid_inst_genid(unsigned short genid);
315 static int valid_preset_genid(unsigned short genid);
318 static void delete_preset(SFPreset *preset);
319 static void delete_inst(SFInst *inst);
320 static void delete_zone(SFZone *zone);
322 static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data);
323 static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24);
326 * Open a SoundFont file and parse it's contents into a SFData structure.
328 * @param fname filename
329 * @param fcbs file callback structure
330 * @return the partially parsed SoundFont as SFData structure or NULL on error
332 SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs)
337 if(!(sf = FLUID_NEW(SFData)))
339 FLUID_LOG(FLUID_ERR, "Out of memory");
343 FLUID_MEMSET(sf, 0, sizeof(SFData));
347 if((sf->sffd = fcbs->fopen(fname)) == NULL)
349 FLUID_LOG(FLUID_ERR, "Unable to open file '%s'", fname);
353 sf->fname = FLUID_STRDUP(fname);
355 if(sf->fname == NULL)
357 FLUID_LOG(FLUID_ERR, "Out of memory");
361 /* get size of file by seeking to end */
362 if(fcbs->fseek(sf->sffd, 0L, SEEK_END) == FLUID_FAILED)
364 FLUID_LOG(FLUID_ERR, "Seek to end of file failed");
368 if((fsize = fcbs->ftell(sf->sffd)) == FLUID_FAILED)
370 FLUID_LOG(FLUID_ERR, "Get end of file position failed");
374 sf->filesize = fsize;
376 if(fcbs->fseek(sf->sffd, 0, SEEK_SET) == FLUID_FAILED)
378 FLUID_LOG(FLUID_ERR, "Rewind to start of file failed");
390 fluid_sffile_close(sf);
395 * Parse all preset information from the soundfont
397 * @return FLUID_OK on success, otherwise FLUID_FAILED
399 int fluid_sffile_parse_presets(SFData *sf)
409 /* Load sample data from the soundfont file
411 * This function will always return the sample data in WAV format. If the sample_type specifies an
412 * Ogg Vorbis compressed sample, it will be decompressed automatically before returning.
414 * @param sf SFData instance
415 * @param sample_start index of first sample point in Soundfont sample chunk
416 * @param sample_end index of last sample point in Soundfont sample chunk
417 * @param sample_type type of the sample in Soundfont
418 * @param data pointer to sample data pointer, will point to loaded sample data on success
419 * @param data24 pointer to 24-bit sample data pointer if 24-bit data present, will point to loaded
420 * 24-bit sample data on success or NULL if no 24-bit data is present in file
422 * @return The number of sample words in returned buffers or -1 on failure
424 int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,
425 int sample_type, short **data, char **data24)
429 if(sample_type & FLUID_SAMPLETYPE_OGG_VORBIS)
431 num_samples = fluid_sffile_read_vorbis(sf, sample_start, sample_end, data);
435 num_samples = fluid_sffile_read_wav(sf, sample_start, sample_end, data, data24);
442 * Close a SoundFont file and free the SFData structure.
444 * @param sf pointer to SFData structure
445 * @param fcbs file callback structure
447 void fluid_sffile_close(SFData *sf)
455 sf->fcbs->fclose(sf->sffd);
458 FLUID_FREE(sf->fname);
464 FLUID_FREE(fluid_list_get(entry));
465 entry = fluid_list_next(entry);
468 delete_fluid_list(sf->info);
474 preset = (SFPreset *)fluid_list_get(entry);
475 delete_preset(preset);
476 entry = fluid_list_next(entry);
479 delete_fluid_list(sf->preset);
485 inst = (SFInst *)fluid_list_get(entry);
487 entry = fluid_list_next(entry);
490 delete_fluid_list(sf->inst);
496 FLUID_FREE(fluid_list_get(entry));
497 entry = fluid_list_next(entry);
500 delete_fluid_list(sf->sample);
510 /* sound font file load functions */
511 static int chunkid(uint32_t id)
514 const uint32_t *p = &idlist.i;
516 for(i = 0; i < sizeof(idlist) / sizeof(idlist.i); i++, p += 1)
527 static int load_header(SFData *sf)
531 READCHUNK(sf, &chunk); /* load RIFF chunk */
533 if(chunkid(chunk.id) != RIFF_ID)
535 /* error if not RIFF */
536 FLUID_LOG(FLUID_ERR, "Not a RIFF file");
540 READID(sf, &chunk.id); /* load file ID */
542 if(chunkid(chunk.id) != SFBK_ID)
544 /* error if not SFBK_ID */
545 FLUID_LOG(FLUID_ERR, "Not a SoundFont file");
549 if(chunk.size != sf->filesize - 8)
551 FLUID_LOG(FLUID_ERR, "SoundFont file size mismatch");
555 /* Process INFO block */
556 if(!read_listchunk(sf, &chunk))
561 if(chunkid(chunk.id) != INFO_ID)
563 FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting INFO chunk");
567 if(!process_info(sf, chunk.size))
572 /* Process sample chunk */
573 if(!read_listchunk(sf, &chunk))
578 if(chunkid(chunk.id) != SDTA_ID)
580 FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting SAMPLE chunk");
584 if(!process_sdta(sf, chunk.size))
589 /* process HYDRA chunk */
590 if(!read_listchunk(sf, &chunk))
595 if(chunkid(chunk.id) != PDTA_ID)
597 FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting HYDRA chunk");
601 sf->hydrapos = sf->fcbs->ftell(sf->sffd);
602 sf->hydrasize = chunk.size;
607 static int load_body(SFData *sf)
609 if(sf->fcbs->fseek(sf->sffd, sf->hydrapos, SEEK_SET) == FLUID_FAILED)
611 FLUID_LOG(FLUID_ERR, "Failed to seek to HYDRA position");
615 if(!process_pdta(sf, sf->hydrasize))
630 /* sort preset list by bank, preset # */
631 sf->preset = fluid_list_sort(sf->preset, (fluid_compare_func_t)preset_compare_func);
636 static int read_listchunk(SFData *sf, SFChunk *chunk)
638 READCHUNK(sf, chunk); /* read list chunk */
640 if(chunkid(chunk->id) != LIST_ID) /* error if ! list chunk */
642 FLUID_LOG(FLUID_ERR, "Invalid chunk id in level 0 parse");
646 READID(sf, &chunk->id); /* read id string */
651 static int process_info(SFData *sf, int size)
660 READCHUNK(sf, &chunk);
663 id = chunkid(chunk.id);
667 /* sound font version chunk? */
670 FLUID_LOG(FLUID_ERR, "Sound font version info chunk has invalid size");
675 sf->version.major = ver;
677 sf->version.minor = ver;
679 if(sf->version.major < 2)
681 FLUID_LOG(FLUID_ERR, "Sound font version is %d.%d which is not"
682 " supported, convert to version 2.0x",
683 sf->version.major, sf->version.minor);
687 if(sf->version.major == 3)
689 #if !LIBSNDFILE_SUPPORT
690 FLUID_LOG(FLUID_WARN,
691 "Sound font version is %d.%d but fluidsynth was compiled without"
692 " support for (v3.x)",
693 sf->version.major, sf->version.minor);
697 else if(sf->version.major > 2)
699 FLUID_LOG(FLUID_WARN,
700 "Sound font version is %d.%d which is newer than"
701 " what this version of fluidsynth was designed for (v2.0x)",
702 sf->version.major, sf->version.minor);
706 else if(id == IVER_ID)
708 /* ROM version chunk? */
711 FLUID_LOG(FLUID_ERR, "ROM version info chunk has invalid size");
716 sf->romver.major = ver;
718 sf->romver.minor = ver;
720 else if(id != UNKN_ID)
722 if((id != ICMT_ID && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2))
724 FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes",
725 &chunk.id, chunk.size);
729 /* alloc for chunk id and da chunk */
730 if(!(item = FLUID_MALLOC(chunk.size + 1)))
732 FLUID_LOG(FLUID_ERR, "Out of memory");
736 /* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */
737 sf->info = fluid_list_append(sf->info, item);
739 *(unsigned char *)item = id;
741 if(sf->fcbs->fread(&item[1], chunk.size, sf->sffd) == FLUID_FAILED)
746 /* force terminate info item (don't forget uint8 info ID) */
747 *(item + chunk.size) = '\0';
751 FLUID_LOG(FLUID_ERR, "Invalid chunk id in INFO chunk");
760 FLUID_LOG(FLUID_ERR, "INFO chunk size mismatch");
767 static int process_sdta(SFData *sf, unsigned int size)
773 return TRUE; /* no sample data? */
777 READCHUNK(sf, &chunk);
780 if(chunkid(chunk.id) != SMPL_ID)
782 FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead");
786 /* SDTA chunk may also contain sm24 chunk for 24 bit samples
787 * (not yet supported), only an error if SMPL chunk size is
788 * greater than SDTA. */
789 if(chunk.size > size)
791 FLUID_LOG(FLUID_ERR, "SDTA chunk size mismatch");
795 /* sample data follows */
796 sf->samplepos = sf->fcbs->ftell(sf->sffd);
798 /* used to check validity of sample headers */
799 sf->samplesize = chunk.size;
801 FSKIP(sf, chunk.size);
804 if(sf->version.major >= 2 && sf->version.minor >= 4)
806 /* any chance to find another chunk here? */
810 READCHUNK(sf, &chunk);
813 if(chunkid(chunk.id) == SM24_ID)
815 int sm24size, sdtahalfsize;
817 FLUID_LOG(FLUID_DBG, "Found SM24 chunk");
819 if(chunk.size > size)
821 FLUID_LOG(FLUID_WARN, "SM24 exeeds SDTA chunk, ignoring SM24");
822 goto ret; // no error
825 sdtahalfsize = sf->samplesize / 2;
826 /* + 1 byte in the case that half the size of smpl chunk is an odd value */
827 sdtahalfsize += sdtahalfsize % 2;
828 sm24size = chunk.size;
830 if(sdtahalfsize != sm24size)
832 FLUID_LOG(FLUID_WARN, "SM24 not equal to half the size of SMPL chunk (0x%X != "
833 "0x%X), ignoring SM24",
834 sm24size, sdtahalfsize);
835 goto ret; // no error
838 /* sample data24 follows */
839 sf->sample24pos = sf->fcbs->ftell(sf->sffd);
840 sf->sample24size = sm24size;
851 static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size)
856 expstr = CHNKIDSTR(expid); /* in case we need it */
858 READCHUNK(sf, chunk);
861 if((id = chunkid(chunk->id)) != expid)
863 FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", expstr);
867 if(chunk->size % reclen) /* valid chunk size? */
869 FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", expstr, reclen);
873 if((*size -= chunk->size) < 0)
875 FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", expstr);
882 static int process_pdta(SFData *sf, int size)
886 if(!pdtahelper(sf, PHDR_ID, SF_PHDR_SIZE, &chunk, &size))
891 if(!load_phdr(sf, chunk.size))
896 if(!pdtahelper(sf, PBAG_ID, SF_BAG_SIZE, &chunk, &size))
901 if(!load_pbag(sf, chunk.size))
906 if(!pdtahelper(sf, PMOD_ID, SF_MOD_SIZE, &chunk, &size))
911 if(!load_pmod(sf, chunk.size))
916 if(!pdtahelper(sf, PGEN_ID, SF_GEN_SIZE, &chunk, &size))
921 if(!load_pgen(sf, chunk.size))
926 if(!pdtahelper(sf, IHDR_ID, SF_IHDR_SIZE, &chunk, &size))
931 if(!load_ihdr(sf, chunk.size))
936 if(!pdtahelper(sf, IBAG_ID, SF_BAG_SIZE, &chunk, &size))
941 if(!load_ibag(sf, chunk.size))
946 if(!pdtahelper(sf, IMOD_ID, SF_MOD_SIZE, &chunk, &size))
951 if(!load_imod(sf, chunk.size))
956 if(!pdtahelper(sf, IGEN_ID, SF_GEN_SIZE, &chunk, &size))
961 if(!load_igen(sf, chunk.size))
966 if(!pdtahelper(sf, SHDR_ID, SF_SHDR_SIZE, &chunk, &size))
971 if(!load_shdr(sf, chunk.size))
979 /* preset header loader */
980 static int load_phdr(SFData *sf, int size)
983 SFPreset *preset, *prev_preset = NULL;
984 unsigned short pbag_idx, prev_pbag_idx = 0;
986 if(size % SF_PHDR_SIZE || size == 0)
988 FLUID_LOG(FLUID_ERR, "Preset header chunk size is invalid");
992 i = size / SF_PHDR_SIZE - 1;
996 /* at least one preset + term record */
997 FLUID_LOG(FLUID_WARN, "File contains no presets");
998 FSKIP(sf, SF_PHDR_SIZE);
1004 /* load all preset headers */
1005 if((preset = FLUID_NEW(SFPreset)) == NULL)
1007 FLUID_LOG(FLUID_ERR, "Out of memory");
1011 sf->preset = fluid_list_append(sf->preset, preset);
1012 preset->zone = NULL; /* In case of failure, fluid_sffile_close can cleanup */
1013 READSTR(sf, &preset->name); /* possible read failure ^ */
1014 READW(sf, preset->prenum);
1015 READW(sf, preset->bank);
1016 READW(sf, pbag_idx);
1017 READD(sf, preset->libr);
1018 READD(sf, preset->genre);
1019 READD(sf, preset->morph);
1023 /* not first preset? */
1024 if(pbag_idx < prev_pbag_idx)
1026 FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");
1030 i2 = pbag_idx - prev_pbag_idx;
1034 prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);
1037 else if(pbag_idx > 0) /* 1st preset, warn if ofs >0 */
1039 FLUID_LOG(FLUID_WARN, "%d preset zones not referenced, discarding", pbag_idx);
1042 prev_preset = preset; /* update preset ptr */
1043 prev_pbag_idx = pbag_idx;
1047 READW(sf, pbag_idx); /* Read terminal generator index */
1050 if(pbag_idx < prev_pbag_idx)
1052 FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic");
1056 i2 = pbag_idx - prev_pbag_idx;
1060 prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL);
1066 /* preset bag loader */
1067 static int load_pbag(SFData *sf, int size)
1069 fluid_list_t *p, *p2;
1070 SFZone *z, *pz = NULL;
1071 unsigned short genndx, modndx;
1072 unsigned short pgenndx = 0, pmodndx = 0;
1075 if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */
1077 FLUID_LOG(FLUID_ERR, "Preset bag chunk size is invalid");
1085 /* traverse through presets */
1086 p2 = ((SFPreset *)(p->data))->zone;
1090 /* traverse preset's zones */
1091 if((size -= SF_BAG_SIZE) < 0)
1093 FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");
1097 if((z = FLUID_NEW(SFZone)) == NULL)
1099 FLUID_LOG(FLUID_ERR, "Out of memory");
1104 z->gen = NULL; /* Init gen and mod before possible failure, */
1105 z->mod = NULL; /* to ensure proper cleanup (fluid_sffile_close) */
1106 READW(sf, genndx); /* possible read failure ^ */
1112 /* if not first zone */
1113 if(genndx < pgenndx)
1115 FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");
1119 if(modndx < pmodndx)
1121 FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");
1125 i = genndx - pgenndx;
1129 pz->gen = fluid_list_prepend(pz->gen, NULL);
1132 i = modndx - pmodndx;
1136 pz->mod = fluid_list_prepend(pz->mod, NULL);
1140 pz = z; /* update previous zone ptr */
1141 pgenndx = genndx; /* update previous zone gen index */
1142 pmodndx = modndx; /* update previous zone mod index */
1143 p2 = fluid_list_next(p2);
1146 p = fluid_list_next(p);
1149 size -= SF_BAG_SIZE;
1153 FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch");
1164 FLUID_LOG(FLUID_WARN, "No preset generators and terminal index not 0");
1169 FLUID_LOG(FLUID_WARN, "No preset modulators and terminal index not 0");
1175 if(genndx < pgenndx)
1177 FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic");
1181 if(modndx < pmodndx)
1183 FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic");
1187 i = genndx - pgenndx;
1191 pz->gen = fluid_list_prepend(pz->gen, NULL);
1194 i = modndx - pmodndx;
1198 pz->mod = fluid_list_prepend(pz->mod, NULL);
1204 /* preset modulator loader */
1205 static int load_pmod(SFData *sf, int size)
1207 fluid_list_t *p, *p2, *p3;
1214 /* traverse through all presets */
1215 p2 = ((SFPreset *)(p->data))->zone;
1219 /* traverse this preset's zones */
1220 p3 = ((SFZone *)(p2->data))->mod;
1224 /* load zone's modulators */
1225 if((size -= SF_MOD_SIZE) < 0)
1227 FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");
1231 if((m = FLUID_NEW(SFMod)) == NULL)
1233 FLUID_LOG(FLUID_ERR, "Out of memory");
1240 READW(sf, m->amount);
1241 READW(sf, m->amtsrc);
1242 READW(sf, m->trans);
1243 p3 = fluid_list_next(p3);
1246 p2 = fluid_list_next(p2);
1249 p = fluid_list_next(p);
1253 If there isn't even a terminal record
1254 Hmmm, the specs say there should be one, but..
1261 size -= SF_MOD_SIZE;
1265 FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch");
1269 FSKIP(sf, SF_MOD_SIZE); /* terminal mod */
1274 /* -------------------------------------------------------------------
1275 * preset generator loader
1276 * generator (per preset) loading rules:
1277 * Zones with no generators or modulators shall be annihilated
1278 * Global zone must be 1st zone, discard additional ones (instrumentless zones)
1280 * generator (per zone) loading rules (in order of decreasing precedence):
1281 * KeyRange is 1st in list (if exists), else discard
1282 * if a VelRange exists only preceded by a KeyRange, else discard
1283 * if a generator follows an instrument discard it
1284 * if a duplicate generator exists replace previous one
1285 * ------------------------------------------------------------------- */
1286 static int load_pgen(SFData *sf, int size)
1288 fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
1292 unsigned short genid;
1293 int level, skip, drop, gzone, discarded;
1299 /* traverse through all presets */
1302 p2 = ((SFPreset *)(p->data))->zone;
1311 /* traverse preset's zones */
1313 z = (SFZone *)(p2->data);
1318 /* load zone's generators */
1323 if((size -= SF_GEN_SIZE) < 0)
1325 FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
1331 if(genid == Gen_KeyRange)
1333 /* nothing precedes */
1337 READB(sf, genval.range.lo);
1338 READB(sf, genval.range.hi);
1345 else if(genid == Gen_VelRange)
1347 /* only KeyRange precedes */
1351 READB(sf, genval.range.lo);
1352 READB(sf, genval.range.hi);
1359 else if(genid == Gen_Instrument)
1361 /* inst is last gen */
1363 READW(sf, genval.uword);
1364 ((SFZone *)(p2->data))->instsamp = FLUID_INT_TO_POINTER(genval.uword + 1);
1365 break; /* break out of generator loop */
1371 if(valid_preset_genid(genid))
1373 /* generator valid? */
1374 READW(sf, genval.sword);
1375 dup = find_gen_by_id(genid, z->gen);
1387 /* if gen ! dup alloc new */
1388 if((g = FLUID_NEW(SFGen)) == NULL)
1390 FLUID_LOG(FLUID_ERR, "Out of memory");
1399 g = (SFGen *)(dup->data); /* ptr to orig gen */
1407 /* Skip this generator */
1415 p3 = fluid_list_next(p3); /* next gen */
1419 SLADVREM(z->gen, p3); /* drop place holder */
1422 } /* generator loop */
1426 SLADVREM(z->gen, p3); /* zone has inst? */
1430 /* congratulations its a global zone */
1433 /* Prior global zones? */
1436 /* if global zone is not 1st zone, relocate */
1439 void *save = p2->data;
1440 FLUID_LOG(FLUID_WARN, "Preset '%s': Global zone is not first zone",
1441 ((SFPreset *)(p->data))->name);
1443 *hz = fluid_list_prepend(*hz, save);
1449 /* previous global zone exists, discard */
1450 FLUID_LOG(FLUID_WARN, "Preset '%s': Discarding invalid global zone",
1451 ((SFPreset *)(p->data))->name);
1452 *hz = fluid_list_remove(*hz, p2->data);
1453 delete_zone((SFZone *)fluid_list_get(p2));
1459 /* Kill any zones following an instrument */
1462 if((size -= SF_GEN_SIZE) < 0)
1464 FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
1468 FSKIP(sf, SF_GEN_SIZE);
1469 SLADVREM(z->gen, p3);
1472 p2 = fluid_list_next(p2); /* next zone */
1477 FLUID_LOG(FLUID_WARN,
1478 "Preset '%s': Some invalid generators were discarded",
1479 ((SFPreset *)(p->data))->name);
1482 p = fluid_list_next(p);
1485 /* in case there isn't a terminal record */
1491 size -= SF_GEN_SIZE;
1495 FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch");
1499 FSKIP(sf, SF_GEN_SIZE); /* terminal gen */
1504 /* instrument header loader */
1505 static int load_ihdr(SFData *sf, int size)
1508 SFInst *p, *pr = NULL; /* ptr to current & previous instrument */
1509 unsigned short zndx, pzndx = 0;
1511 if(size % SF_IHDR_SIZE || size == 0) /* chunk size is valid? */
1513 FLUID_LOG(FLUID_ERR, "Instrument header has invalid size");
1517 size = size / SF_IHDR_SIZE - 1;
1521 /* at least one preset + term record */
1522 FLUID_LOG(FLUID_WARN, "File contains no instruments");
1523 FSKIP(sf, SF_IHDR_SIZE);
1527 for(i = 0; i < size; i++)
1529 /* load all instrument headers */
1530 if((p = FLUID_NEW(SFInst)) == NULL)
1532 FLUID_LOG(FLUID_ERR, "Out of memory");
1536 sf->inst = fluid_list_append(sf->inst, p);
1537 p->zone = NULL; /* For proper cleanup if fail (fluid_sffile_close) */
1539 READSTR(sf, &p->name); /* Possible read failure ^ */
1544 /* not first instrument? */
1547 FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");
1555 pr->zone = fluid_list_prepend(pr->zone, NULL);
1558 else if(zndx > 0) /* 1st inst, warn if ofs >0 */
1560 FLUID_LOG(FLUID_WARN, "%d instrument zones not referenced, discarding", zndx);
1564 pr = p; /* update instrument ptr */
1572 FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic");
1580 pr->zone = fluid_list_prepend(pr->zone, NULL);
1586 /* instrument bag loader */
1587 static int load_ibag(SFData *sf, int size)
1589 fluid_list_t *p, *p2;
1590 SFZone *z, *pz = NULL;
1591 unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0;
1594 if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */
1596 FLUID_LOG(FLUID_ERR, "Instrument bag chunk size is invalid");
1604 /* traverse through inst */
1605 p2 = ((SFInst *)(p->data))->zone;
1609 /* load this inst's zones */
1610 if((size -= SF_BAG_SIZE) < 0)
1612 FLUID_LOG(FLUID_ERR, "Instrument bag chunk size mismatch");
1616 if((z = FLUID_NEW(SFZone)) == NULL)
1618 FLUID_LOG(FLUID_ERR, "Out of memory");
1623 z->gen = NULL; /* In case of failure, */
1624 z->mod = NULL; /* fluid_sffile_close can clean up */
1625 READW(sf, genndx); /* READW = possible read failure */
1631 /* if not first zone */
1632 if(genndx < pgenndx)
1634 FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");
1638 if(modndx < pmodndx)
1640 FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");
1644 i = genndx - pgenndx;
1648 pz->gen = fluid_list_prepend(pz->gen, NULL);
1651 i = modndx - pmodndx;
1655 pz->mod = fluid_list_prepend(pz->mod, NULL);
1659 pz = z; /* update previous zone ptr */
1662 p2 = fluid_list_next(p2);
1665 p = fluid_list_next(p);
1668 size -= SF_BAG_SIZE;
1672 FLUID_LOG(FLUID_ERR, "Instrument chunk size mismatch");
1681 /* in case that all are no zoners */
1684 FLUID_LOG(FLUID_WARN, "No instrument generators and terminal index not 0");
1689 FLUID_LOG(FLUID_WARN, "No instrument modulators and terminal index not 0");
1695 if(genndx < pgenndx)
1697 FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic");
1701 if(modndx < pmodndx)
1703 FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic");
1707 i = genndx - pgenndx;
1711 pz->gen = fluid_list_prepend(pz->gen, NULL);
1714 i = modndx - pmodndx;
1718 pz->mod = fluid_list_prepend(pz->mod, NULL);
1724 /* instrument modulator loader */
1725 static int load_imod(SFData *sf, int size)
1727 fluid_list_t *p, *p2, *p3;
1734 /* traverse through all inst */
1735 p2 = ((SFInst *)(p->data))->zone;
1739 /* traverse this inst's zones */
1740 p3 = ((SFZone *)(p2->data))->mod;
1744 /* load zone's modulators */
1745 if((size -= SF_MOD_SIZE) < 0)
1747 FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");
1751 if((m = FLUID_NEW(SFMod)) == NULL)
1753 FLUID_LOG(FLUID_ERR, "Out of memory");
1760 READW(sf, m->amount);
1761 READW(sf, m->amtsrc);
1762 READW(sf, m->trans);
1763 p3 = fluid_list_next(p3);
1766 p2 = fluid_list_next(p2);
1769 p = fluid_list_next(p);
1773 If there isn't even a terminal record
1774 Hmmm, the specs say there should be one, but..
1781 size -= SF_MOD_SIZE;
1785 FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch");
1789 FSKIP(sf, SF_MOD_SIZE); /* terminal mod */
1794 /* load instrument generators (see load_pgen for loading rules) */
1795 static int load_igen(SFData *sf, int size)
1797 fluid_list_t *p, *p2, *p3, *dup, **hz = NULL;
1801 unsigned short genid;
1802 int level, skip, drop, gzone, discarded;
1808 /* traverse through all instruments */
1811 p2 = ((SFInst *)(p->data))->zone;
1820 /* traverse this instrument's zones */
1822 z = (SFZone *)(p2->data);
1827 /* load zone's generators */
1832 if((size -= SF_GEN_SIZE) < 0)
1834 FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");
1840 if(genid == Gen_KeyRange)
1842 /* nothing precedes */
1846 READB(sf, genval.range.lo);
1847 READB(sf, genval.range.hi);
1854 else if(genid == Gen_VelRange)
1856 /* only KeyRange precedes */
1860 READB(sf, genval.range.lo);
1861 READB(sf, genval.range.hi);
1868 else if(genid == Gen_SampleId)
1870 /* sample is last gen */
1872 READW(sf, genval.uword);
1873 ((SFZone *)(p2->data))->instsamp = FLUID_INT_TO_POINTER(genval.uword + 1);
1874 break; /* break out of generator loop */
1880 if(valid_inst_genid(genid))
1883 READW(sf, genval.sword);
1884 dup = find_gen_by_id(genid, z->gen);
1896 /* if gen ! dup alloc new */
1897 if((g = FLUID_NEW(SFGen)) == NULL)
1899 FLUID_LOG(FLUID_ERR, "Out of memory");
1908 g = (SFGen *)(dup->data);
1916 /* skip this generator */
1924 p3 = fluid_list_next(p3); /* next gen */
1928 SLADVREM(z->gen, p3);
1931 } /* generator loop */
1935 SLADVREM(z->gen, p3); /* zone has sample? */
1939 /* its a global zone */
1944 /* if global zone is not 1st zone, relocate */
1947 void *save = p2->data;
1948 FLUID_LOG(FLUID_WARN, "Instrument '%s': Global zone is not first zone",
1949 ((SFPreset *)(p->data))->name);
1951 *hz = fluid_list_prepend(*hz, save);
1957 /* previous global zone exists, discard */
1958 FLUID_LOG(FLUID_WARN, "Instrument '%s': Discarding invalid global zone",
1959 ((SFInst *)(p->data))->name);
1960 *hz = fluid_list_remove(*hz, p2->data);
1961 delete_zone((SFZone *)fluid_list_get(p2));
1967 /* Kill any zones following a sample */
1970 if((size -= SF_GEN_SIZE) < 0)
1972 FLUID_LOG(FLUID_ERR, "Instrument generator chunk size mismatch");
1976 FSKIP(sf, SF_GEN_SIZE);
1977 SLADVREM(z->gen, p3);
1980 p2 = fluid_list_next(p2); /* next zone */
1985 FLUID_LOG(FLUID_WARN,
1986 "Instrument '%s': Some invalid generators were discarded",
1987 ((SFInst *)(p->data))->name);
1990 p = fluid_list_next(p);
1993 /* for those non-terminal record cases, grr! */
1999 size -= SF_GEN_SIZE;
2003 FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch");
2007 FSKIP(sf, SF_GEN_SIZE); /* terminal gen */
2012 /* sample header loader */
2013 static int load_shdr(SFData *sf, unsigned int size)
2018 if(size % SF_SHDR_SIZE || size == 0) /* size is multiple of SHDR size? */
2020 FLUID_LOG(FLUID_ERR, "Sample header has invalid size");
2024 size = size / SF_SHDR_SIZE - 1;
2028 /* at least one sample + term record? */
2029 FLUID_LOG(FLUID_WARN, "File contains no samples");
2030 FSKIP(sf, SF_SHDR_SIZE);
2034 /* load all sample headers */
2035 for(i = 0; i < size; i++)
2037 if((p = FLUID_NEW(SFSample)) == NULL)
2039 FLUID_LOG(FLUID_ERR, "Out of memory");
2043 sf->sample = fluid_list_append(sf->sample, p);
2044 READSTR(sf, &p->name);
2045 READD(sf, p->start);
2047 READD(sf, p->loopstart);
2048 READD(sf, p->loopend);
2049 READD(sf, p->samplerate);
2050 READB(sf, p->origpitch);
2051 READB(sf, p->pitchadj);
2052 FSKIPW(sf); /* skip sample link */
2053 READW(sf, p->sampletype);
2057 FSKIP(sf, SF_SHDR_SIZE); /* skip terminal shdr */
2062 /* "fixup" (inst # -> inst ptr) instrument references in preset list */
2063 static int fixup_pgen(SFData *sf)
2065 fluid_list_t *p, *p2, *p3;
2073 p2 = ((SFPreset *)(p->data))->zone;
2077 /* traverse this preset's zones */
2078 z = (SFZone *)(p2->data);
2080 if((i = FLUID_POINTER_TO_INT(z->instsamp)))
2082 /* load instrument # */
2083 p3 = fluid_list_nth(sf->inst, i - 1);
2087 FLUID_LOG(FLUID_ERR, "Preset %03d %03d: Invalid instrument reference",
2088 ((SFPreset *)(p->data))->bank, ((SFPreset *)(p->data))->prenum);
2099 p2 = fluid_list_next(p2);
2102 p = fluid_list_next(p);
2108 /* "fixup" (sample # -> sample ptr) sample references in instrument list */
2109 static int fixup_igen(SFData *sf)
2111 fluid_list_t *p, *p2, *p3;
2119 p2 = ((SFInst *)(p->data))->zone;
2123 /* traverse instrument's zones */
2124 z = (SFZone *)(p2->data);
2126 if((i = FLUID_POINTER_TO_INT(z->instsamp)))
2129 p3 = fluid_list_nth(sf->sample, i - 1);
2133 FLUID_LOG(FLUID_ERR, "Instrument '%s': Invalid sample reference",
2134 ((SFInst *)(p->data))->name);
2141 p2 = fluid_list_next(p2);
2144 p = fluid_list_next(p);
2150 static void delete_preset(SFPreset *preset)
2152 fluid_list_t *entry;
2160 entry = preset->zone;
2164 zone = (SFZone *)fluid_list_get(entry);
2166 entry = fluid_list_next(entry);
2169 delete_fluid_list(preset->zone);
2174 static void delete_inst(SFInst *inst)
2176 fluid_list_t *entry;
2188 zone = (SFZone *)fluid_list_get(entry);
2190 entry = fluid_list_next(entry);
2193 delete_fluid_list(inst->zone);
2199 /* Free all elements of a zone (Preset or Instrument) */
2200 static void delete_zone(SFZone *zone)
2202 fluid_list_t *entry;
2213 FLUID_FREE(fluid_list_get(entry));
2214 entry = fluid_list_next(entry);
2217 delete_fluid_list(zone->gen);
2223 FLUID_FREE(fluid_list_get(entry));
2224 entry = fluid_list_next(entry);
2227 delete_fluid_list(zone->mod);
2232 /* preset sort function, first by bank, then by preset # */
2233 static int preset_compare_func(void *a, void *b)
2237 aval = (int)(((SFPreset *)a)->bank) << 16 | ((SFPreset *)a)->prenum;
2238 bval = (int)(((SFPreset *)b)->bank) << 16 | ((SFPreset *)b)->prenum;
2240 return (aval - bval);
2243 /* Find a generator by its id in the passed in list.
2245 * @return pointer to SFGen if found, otherwise NULL
2247 static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist)
2249 /* is generator in gen list? */
2261 if(gen == ((SFGen *)p->data)->id)
2266 p = fluid_list_next(p);
2272 /* check validity of instrument generator */
2273 static int valid_inst_genid(unsigned short genid)
2277 if(genid > Gen_MaxValid)
2282 while(invalid_inst_gen[i] && invalid_inst_gen[i] != genid)
2287 return (invalid_inst_gen[i] == 0);
2290 /* check validity of preset generator */
2291 static int valid_preset_genid(unsigned short genid)
2295 if(!valid_inst_genid(genid))
2300 while(invalid_preset_gen[i] && invalid_preset_gen[i] != genid)
2305 return (invalid_preset_gen[i] == 0);
2309 static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24)
2311 short *loaded_data = NULL;
2312 char *loaded_data24 = NULL;
2314 int num_samples = (end + 1) - start;
2315 fluid_return_val_if_fail(num_samples > 0, -1);
2317 if((start * sizeof(short) > sf->samplesize) || (end * sizeof(short) > sf->samplesize))
2319 FLUID_LOG(FLUID_ERR, "Sample offsets exceed sample data chunk");
2323 /* Load 16-bit sample data */
2324 if(sf->fcbs->fseek(sf->sffd, sf->samplepos + (start * sizeof(short)), SEEK_SET) == FLUID_FAILED)
2326 FLUID_LOG(FLUID_ERR, "Failed to seek to sample position");
2330 loaded_data = FLUID_ARRAY(short, num_samples);
2332 if(loaded_data == NULL)
2334 FLUID_LOG(FLUID_ERR, "Out of memory");
2338 if(sf->fcbs->fread(loaded_data, num_samples * sizeof(short), sf->sffd) == FLUID_FAILED)
2340 FLUID_LOG(FLUID_ERR, "Failed to read sample data");
2344 /* If this machine is big endian, byte swap the 16 bit samples */
2345 if(FLUID_IS_BIG_ENDIAN)
2349 for(i = 0; i < num_samples; i++)
2351 loaded_data[i] = FLUID_LE16TOH(loaded_data[i]);
2355 *data = loaded_data;
2357 /* Optionally load additional 8 bit sample data for 24-bit support. Any failures while loading
2358 * the 24-bit sample data will be logged as errors but won't prevent the sample reading to
2359 * fail, as sound output is still possible with the 16-bit sample data. */
2362 if((start > sf->sample24size) || (end > sf->sample24size))
2364 FLUID_LOG(FLUID_ERR, "Sample offsets exceed 24-bit sample data chunk");
2368 if(sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED)
2370 FLUID_LOG(FLUID_ERR, "Failed to seek position for 24-bit sample data in data file");
2374 loaded_data24 = FLUID_ARRAY(char, num_samples);
2376 if(loaded_data24 == NULL)
2378 FLUID_LOG(FLUID_ERR, "Out of memory reading 24-bit sample data");
2382 if(sf->fcbs->fread(loaded_data24, num_samples, sf->sffd) == FLUID_FAILED)
2384 FLUID_LOG(FLUID_ERR, "Failed to read 24-bit sample data");
2389 *data24 = loaded_data24;
2394 FLUID_LOG(FLUID_WARN, "Ignoring 24-bit sample data, sound quality might suffer");
2395 FLUID_FREE(loaded_data24);
2400 FLUID_FREE(loaded_data);
2401 FLUID_FREE(loaded_data24);
2406 /* Ogg Vorbis loading and decompression */
2407 #if LIBSNDFILE_SUPPORT
2409 /* Virtual file access rountines to allow loading individually compressed
2410 * samples from the Soundfont sample data chunk using the file callbacks
2411 * passing in during opening of the file */
2412 typedef struct _sfvio_data_t
2415 sf_count_t start; /* start byte offset of compressed data */
2416 sf_count_t end; /* end byte offset of compressed data */
2417 sf_count_t offset; /* current virtual file offset from start byte offset */
2421 static sf_count_t sfvio_get_filelen(void *user_data)
2423 sfvio_data_t *data = user_data;
2425 return (data->end + 1) - data->start;
2428 static sf_count_t sfvio_seek(sf_count_t offset, int whence, void *user_data)
2430 sfvio_data_t *data = user_data;
2431 SFData *sf = data->sffile;
2432 sf_count_t new_offset;
2437 new_offset = offset;
2441 new_offset = data->offset + offset;
2445 new_offset = sfvio_get_filelen(user_data) + offset;
2449 goto fail; /* proper error handling not possible?? */
2452 if(sf->fcbs->fseek(sf->sffd, sf->samplepos + data->start + new_offset, SEEK_SET) != FLUID_FAILED)
2454 data->offset = new_offset;
2458 return data->offset;
2461 static sf_count_t sfvio_read(void *ptr, sf_count_t count, void *user_data)
2463 sfvio_data_t *data = user_data;
2464 SFData *sf = data->sffile;
2467 remain = sfvio_get_filelen(user_data) - data->offset;
2479 if(sf->fcbs->fread(ptr, count, sf->sffd) == FLUID_FAILED)
2481 FLUID_LOG(FLUID_ERR, "Failed to read compressed sample data");
2485 data->offset += count;
2490 static sf_count_t sfvio_tell(void *user_data)
2492 sfvio_data_t *data = user_data;
2494 return data->offset;
2498 * Read Ogg Vorbis compressed data from the Soundfont and decompress it, returning the number of samples
2499 * in the decompressed WAV. Only 16-bit mono samples are supported.
2501 * Note that this function takes byte indices for start and end source data. The sample headers in SF3
2502 * files use byte indices, so those pointers can be passed directly to this function.
2504 * This function uses a virtual file structure in order to read the Ogg Vorbis
2505 * data from arbitrary locations in the source file.
2507 static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)
2511 SF_VIRTUAL_IO sfvio =
2519 sfvio_data_t sfdata;
2520 short *wav_data = NULL;
2522 if((start_byte > sf->samplesize) || (end_byte > sf->samplesize))
2524 FLUID_LOG(FLUID_ERR, "Ogg Vorbis data offsets exceed sample data chunk");
2528 // Initialize file position indicator and SF_INFO structure
2530 sfdata.start = start_byte;
2531 sfdata.end = end_byte;
2534 memset(&sfinfo, 0, sizeof(sfinfo));
2536 /* Seek to beginning of Ogg Vorbis data in Soundfont */
2537 if(sf->fcbs->fseek(sf->sffd, sf->samplepos + start_byte, SEEK_SET) == FLUID_FAILED)
2539 FLUID_LOG(FLUID_ERR, "Failed to seek to compressd sample position");
2543 // Open sample as a virtual file
2544 sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, &sfdata);
2548 FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
2553 if(!sfinfo.frames || !sfinfo.channels)
2555 FLUID_LOG(FLUID_DBG, "Empty decompressed sample");
2561 /* FIXME: ensure that the decompressed WAV data is 16-bit mono? */
2563 wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels);
2567 FLUID_LOG(FLUID_ERR, "Out of memory");
2571 /* Automatically decompresses the Ogg Vorbis data to 16-bit WAV */
2572 if(sf_readf_short(sndfile, wav_data, sfinfo.frames) < sfinfo.frames)
2574 FLUID_LOG(FLUID_DBG, "Decompression failed!");
2575 FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
2583 return sfinfo.frames;
2586 FLUID_FREE(wav_data);
2591 static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data)