📄 sffile.c
字号:
/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp> Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//*================================================================ * sffile.c * read SoundFont file (SBK/SF2) and store the layer lists * * Copyright (C) 1996,1997 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *================================================================*//* * Modified by Masanao Izumo <mo@goice.co.jp> */#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <stdio.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include <stdlib.h>#include "timidity.h"#include "common.h"#include "controls.h"#include "sffile.h"extern int progbase;/*================================================================ * preset / instrument bag record *================================================================*/typedef struct _SFBags { int nbags; uint16 *bag; int ngens; SFGenRec *gen;} SFBags;static SFBags prbags, inbags;/*---------------------------------------------------------------- * function prototypes *----------------------------------------------------------------*/#define NEW(type,nums) (type*)safe_malloc(sizeof(type) * (nums))static int READCHUNK(SFChunk *vp, struct timidity_file *tf){ if(tf_read(vp, 8, 1, tf) != 1) return -1; vp->size = LE_LONG(vp->size); return 1;}static int READDW(uint32 *vp, struct timidity_file *tf){ if(tf_read(vp, 4, 1, tf) != 1) return -1; *vp = LE_LONG(*vp); return 1;}static int READW(uint16 *vp, struct timidity_file *tf){ if(tf_read(vp, 2, 1, tf) != 1) return -1; *vp = LE_SHORT(*vp); return 1;}static int READSTR(char *str, struct timidity_file *tf){ int n; if(tf_read(str, 20, 1, tf) != 1) return -1; str[19] = '\0'; n = strlen(str); while(n > 0 && str[n - 1] == ' ') n--; str[n] = '\0'; return n;}#define READID(var,tf) tf_read(var, 4, 1, tf)#define READB(var,tf) tf_read(&var, 1, 1, tf)#define SKIPB(tf) skip(tf, 1)#define SKIPW(tf) skip(tf, 2)#define SKIPDW(tf) skip(tf, 4)#define FSKIP(size,tf) skip(tf, size)/*----------------------------------------------------------------*/static int chunkid(char *id);static int process_list(int size, SFInfo *sf, struct timidity_file *fd);static int process_info(int size, SFInfo *sf, struct timidity_file *fd);static int process_sdta(int size, SFInfo *sf, struct timidity_file *fd);static int process_pdta(int size, SFInfo *sf, struct timidity_file *fd);static void load_sample_names(int size, SFInfo *sf, struct timidity_file *fd);static void load_preset_header(int size, SFInfo *sf, struct timidity_file *fd);static void load_inst_header(int size, SFInfo *sf, struct timidity_file *fd);static void load_bag(int size, SFBags *bagp, struct timidity_file *fd);static void load_gen(int size, SFBags *bagp, struct timidity_file *fd);static void load_sample_info(int size, SFInfo *sf, struct timidity_file *fd);static void convert_layers(SFInfo *sf);static void generate_layers(SFHeader *hdr, SFHeader *next, SFBags *bags);static void free_layer(SFHeader *hdr);/*---------------------------------------------------------------- * id numbers *----------------------------------------------------------------*/enum { /* level 0; chunk */ UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID, /* level 1; id only */ INFO_ID, SDTA_ID, PDTA_ID, /* info stuff; chunk */ IFIL_ID, ISNG_ID, IROM_ID, INAM_ID, IVER_ID, IPRD_ID, ICOP_ID, ICRD_ID, IENG_ID, ISFT_ID, ICMT_ID, /* sample data stuff; chunk */ SNAM_ID, SMPL_ID, /* preset stuff; chunk */ PHDR_ID, PBAG_ID, PMOD_ID, PGEN_ID, /* inst stuff; chunk */ INST_ID, IBAG_ID, IMOD_ID, IGEN_ID, /* sample header; chunk */ SHDR_ID};/*================================================================ * load a soundfont file *================================================================*/int load_soundfont(SFInfo *sf, struct timidity_file *fd){ SFChunk chunk; sf->preset = NULL; sf->sample = NULL; sf->inst = NULL; sf->sf_name = NULL; prbags.bag = inbags.bag = NULL; prbags.gen = inbags.gen = NULL; /* check RIFF file header */ READCHUNK(&chunk, fd); if (chunkid(chunk.id) != RIFF_ID) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: *** not a RIFF file", current_filename); return -1; } /* check file id */ READID(chunk.id, fd); if (chunkid(chunk.id) != SFBK_ID) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: *** not a SoundFont file", current_filename); return -1; } for (;;) { if(READCHUNK(&chunk, fd) <= 0) break; else if (chunkid(chunk.id) == LIST_ID) { if (process_list(chunk.size, sf, fd)) break; } else { ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "%s: *** illegal id in level 0: %4.4s %4d", current_filename, chunk.id, chunk.size); FSKIP(chunk.size, fd); } } /* parse layer structure */ convert_layers(sf); /* free private tables */ if (prbags.bag) free(prbags.bag); if (prbags.gen) free(prbags.gen); if (inbags.bag) free(inbags.bag); if (inbags.gen) free(inbags.gen); return 0;}/*================================================================ * free buffer *================================================================*/void free_soundfont(SFInfo *sf){ int i; if (sf->preset) { for (i = 0; i < sf->npresets; i++) free_layer(&sf->preset[i].hdr); free(sf->preset); } if (sf->inst) { for (i = 0; i < sf->ninsts; i++) free_layer(&sf->inst[i].hdr); free(sf->inst); } if (sf->sample) free(sf->sample); if (sf->sf_name) free(sf->sf_name);}/*---------------------------------------------------------------- * get id value from 4bytes ID string *----------------------------------------------------------------*/static int chunkid(char *id){ static struct idstring { char *str; int id; } idlist[] = { {"RIFF", RIFF_ID}, {"LIST", LIST_ID}, {"sfbk", SFBK_ID}, {"INFO", INFO_ID}, {"sdta", SDTA_ID}, {"snam", SNAM_ID}, {"smpl", SMPL_ID}, {"pdta", PDTA_ID}, {"phdr", PHDR_ID}, {"pbag", PBAG_ID}, {"pmod", PMOD_ID}, {"pgen", PGEN_ID}, {"inst", INST_ID}, {"ibag", IBAG_ID}, {"imod", IMOD_ID}, {"igen", IGEN_ID}, {"shdr", SHDR_ID}, {"ifil", IFIL_ID}, {"isng", ISNG_ID}, {"irom", IROM_ID}, {"iver", IVER_ID}, {"INAM", INAM_ID}, {"IPRD", IPRD_ID}, {"ICOP", ICOP_ID}, {"ICRD", ICRD_ID}, {"IENG", IENG_ID}, {"ISFT", ISFT_ID}, {"ICMT", ICMT_ID}, }; int i; for (i = 0; i < sizeof(idlist)/sizeof(idlist[0]); i++) { if (strncmp(id, idlist[i].str, 4) == 0) return idlist[i].id; } return UNKN_ID;}/*================================================================ * process a list chunk *================================================================*/static int process_list(int size, SFInfo *sf, struct timidity_file *fd){ SFChunk chunk; /* read the following id string */ READID(chunk.id, fd); size -= 4; ctl->cmsg(CMSG_INFO, VERB_DEBUG, "%c%c%c%c:", chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]); switch (chunkid(chunk.id)) { case INFO_ID: return process_info(size, sf, fd); case SDTA_ID: return process_sdta(size, sf, fd); case PDTA_ID: return process_pdta(size, sf, fd); default: ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "%s: *** illegal id in level 1: %4.4s", current_filename, chunk.id); FSKIP(size, fd); /* skip it */ return 0; }} /*================================================================ * process info list *================================================================*/ static int process_info(int size, SFInfo *sf, struct timidity_file *fd){ sf->infopos = tf_tell(fd); sf->infosize = size; /* parse the buffer */ while (size > 0) { SFChunk chunk; /* read a sub chunk */ if(READCHUNK(&chunk, fd) <= 0) return -1; size -= 8; ctl->cmsg(CMSG_INFO, VERB_DEBUG, " %c%c%c%c:", chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]); switch (chunkid(chunk.id)) { case IFIL_ID: /* soundfont file version */ READW(&sf->version, fd); READW(&sf->minorversion, fd); ctl->cmsg(CMSG_INFO, VERB_DEBUG, " version %d, minor %d", sf->version, sf->minorversion); break; case INAM_ID: /* name of the font */ sf->sf_name = (char*)safe_malloc(chunk.size + 1); tf_read(sf->sf_name, 1, chunk.size, fd); sf->sf_name[chunk.size] = 0; ctl->cmsg(CMSG_INFO, VERB_DEBUG, " name %s", sf->sf_name); break; default: if(ctl->verbosity >= VERB_DEBUG) { char buff[100]; if(chunk.size < sizeof(buff) - 1) { tf_read(buff, chunk.size, 1, fd); buff[chunk.size] = '\0'; } else { int i = sizeof(buff) - 4; tf_read(buff, i, 1, fd); FSKIP(chunk.size - i, fd); buff[i++] = '.'; buff[i++] = '.'; buff[i++] = '.'; buff[i] = '\0'; } ctl->cmsg(CMSG_INFO, VERB_DEBUG, " %s", buff); } else FSKIP(chunk.size, fd); break; } size -= chunk.size; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -