📄 sndfont.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 code from awesfx * Modified by Masanao Izumo <mo@goice.co.jp> *//*================================================================ * parsesf.c * parse SoundFonr layers and convert it to AWE driver patch * * 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 *================================================================*/#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 <math.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "timidity.h"#include "common.h"#include "tables.h"#include "instrum.h"#include "playmidi.h"#include "controls.h"#include "sffile.h"#include "sflayer.h"#include "sfitem.h"#include "output.h"#include "filter.h"#include "resample.h"#define FILENAME_NORMALIZE(fname) url_expand_home_dir(fname)#define FILENAME_REDUCED(fname) url_unexpand_home_dir(fname)#define SFMalloc(rec, count) new_segment(&(rec)->pool, count)#define SFStrdup(rec, s) strdup_mblock(&(rec)->pool, s)/*---------------------------------------------------------------- * compile flags *----------------------------------------------------------------*/#ifdef CFG_FOR_SF#define SF_SUPPRESS_ENVELOPE#define SF_SUPPRESS_TREMOLO#define SF_SUPPRESS_VIBRATO#else#define SF_CLOSE_EACH_FILE/*#define SF_SUPPRESS_ENVELOPE*//*#define SF_SUPPRESS_TREMOLO*//*#define SF_SUPPRESS_VIBRATO*/#endif /* CFG_FOR_SF *//* return value */#define AWE_RET_OK 0 /* successfully loaded */#define AWE_RET_ERR 1 /* some fatal error occurs */#define AWE_RET_SKIP 2 /* some fonts are skipped */#define AWE_RET_NOMEM 3 /* out or memory; not all fonts loaded */#define AWE_RET_NOT_FOUND 4 /* the file is not found *//*---------------------------------------------------------------- * local parameters *----------------------------------------------------------------*/typedef struct _SFPatchRec { int preset, bank, keynote; /* -1 = matches all */} SFPatchRec;typedef struct _SampleList { Sample v; struct _SampleList *next; int32 start; int32 len; int32 cutoff_freq; int16 resonance; int16 root, tune; char low, high; /* key note range */ int8 reverb_send, chorus_send; /* Depend on play_mode->rate */ int32 vibrato_freq; int32 attack; int32 hold; int32 sustain; int32 decay; int32 release; int32 modattack; int32 modhold; int32 modsustain; int32 moddecay; int32 modrelease; int bank, keynote; /* for drum instruments */} SampleList;typedef struct _InstList { SFPatchRec pat; int pr_idx; int samples; int order; SampleList *slist; struct _InstList *next;} InstList;typedef struct _SFExclude { SFPatchRec pat; struct _SFExclude *next;} SFExclude;typedef struct _SFOrder { SFPatchRec pat; int order; struct _SFOrder *next;} SFOrder;#define INSTHASHSIZE 127#define INSTHASH(bank, preset, keynote) \ ((int)(((unsigned)bank ^ (unsigned)preset ^ (unsigned)keynote) % INSTHASHSIZE))typedef struct _SFInsts { struct timidity_file *tf; char *fname; int8 def_order, def_cutoff_allowed, def_resonance_allowed; uint16 version, minorversion; int32 samplepos, samplesize; InstList *instlist[INSTHASHSIZE]; char **inst_namebuf; SFExclude *sfexclude; SFOrder *sforder; struct _SFInsts *next; FLOAT_T amptune; MBlockList pool;} SFInsts;/*----------------------------------------------------------------*//* prototypes */#define P_GLOBAL 1#define P_LAYER 2#ifndef FALSE#define FALSE 0#endif /* FALSE */#ifndef TRUE#define TRUE 1#endif /* TRUE */static SFInsts *find_soundfont(char *sf_file);static SFInsts *new_soundfont(char *sf_file);static void init_sf(SFInsts *rec);static void end_soundfont(SFInsts *rec);static Instrument *try_load_soundfont(SFInsts *rec, int order, int bank, int preset, int keynote);static Instrument *load_from_file(SFInsts *rec, InstList *ip);static int is_excluded(SFInsts *rec, int bank, int preset, int keynote);static int is_ordered(SFInsts *rec, int bank, int preset, int keynote);static int load_font(SFInfo *sf, int pridx);static int parse_layer(SFInfo *sf, int pridx, LayerTable *tbl, int level);static int is_global(SFGenLayer *layer);static void clear_table(LayerTable *tbl);static void set_to_table(SFInfo *sf, LayerTable *tbl, SFGenLayer *lay, int level);static void add_item_to_table(LayerTable *tbl, int oper, int amount, int level);static void merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src);static void init_and_merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src);static int sanity_range(LayerTable *tbl);static int make_patch(SFInfo *sf, int pridx, LayerTable *tbl);static void make_info(SFInfo *sf, SampleList *vp, LayerTable *tbl);static FLOAT_T calc_volume(LayerTable *tbl);static void set_sample_info(SFInfo *sf, SampleList *vp, LayerTable *tbl);static void set_init_info(SFInfo *sf, SampleList *vp, LayerTable *tbl);static int abscent_to_Hz(int abscents);static void set_rootkey(SFInfo *sf, SampleList *vp, LayerTable *tbl);static void set_rootfreq(SampleList *vp);static int32 to_offset(int32 offset);static int32 to_rate(int32 diff, int timecent);static int32 calc_rate(int32 diff, double msec);static double to_msec(int timecent);static int32 calc_sustain(int sust_cB);static void convert_volume_envelope(SampleList *vp, LayerTable *tbl);static void convert_tremolo(SampleList *vp, LayerTable *tbl);static void convert_vibrato(SampleList *vp, LayerTable *tbl);/*----------------------------------------------------------------*/static SFInsts *sfrecs = NULL;static SFInsts *current_sfrec = NULL;#define def_drum_inst 0static SFInsts *find_soundfont(char *sf_file){ SFInsts *sf; sf_file = FILENAME_NORMALIZE(sf_file); for(sf = sfrecs; sf != NULL; sf = sf->next) if(sf->fname != NULL && strcmp(sf->fname, sf_file) == 0) return sf; return NULL;}static SFInsts *new_soundfont(char *sf_file){ SFInsts *sf; sf_file = FILENAME_NORMALIZE(sf_file); for(sf = sfrecs; sf != NULL; sf = sf->next) if(sf->fname == NULL) break; if(sf == NULL) sf = (SFInsts *)safe_malloc(sizeof(SFInsts)); memset(sf, 0, sizeof(SFInsts)); init_mblock(&sf->pool); sf->fname = SFStrdup(sf, FILENAME_NORMALIZE(sf_file)); sf->def_order = DEFAULT_SOUNDFONT_ORDER; sf->amptune = 1.0; return sf;}void add_soundfont(char *sf_file, int sf_order, int sf_cutoff, int sf_resonance, int amp){ SFInsts *sf; if((sf = find_soundfont(sf_file)) == NULL) { sf = new_soundfont(sf_file); sf->next = sfrecs; sfrecs = sf; } if(sf_order >= 0) sf->def_order = sf_order; if(sf_cutoff >= 0) sf->def_cutoff_allowed = sf_cutoff; if(sf_resonance >= 0) sf->def_resonance_allowed = sf_resonance; if(amp >= 0) sf->amptune = (FLOAT_T)amp * 0.01; current_sfrec = sf;}void remove_soundfont(char *sf_file){ SFInsts *sf; if((sf = find_soundfont(sf_file)) != NULL) end_soundfont(sf);}char *soundfont_preset_name(int bank, int preset, int keynote, char **sndfile){ SFInsts *rec; if(sndfile != NULL) *sndfile = NULL; for(rec = sfrecs; rec != NULL; rec = rec->next) if(rec->fname != NULL) { int addr; InstList *ip; addr = INSTHASH(bank, preset, keynote); for(ip = rec->instlist[addr]; ip; ip = ip->next) if(ip->pat.bank == bank && ip->pat.preset == preset && (keynote < 0 || keynote == ip->pat.keynote)) break; if(ip != NULL) { if(sndfile != NULL) *sndfile = rec->fname; return rec->inst_namebuf[ip->pr_idx]; } } return NULL;}static void init_sf(SFInsts *rec){ SFInfo sfinfo; int i; ctl->cmsg(CMSG_INFO, VERB_NOISY, "Init soundfonts `%s'", FILENAME_REDUCED(rec->fname)); if ((rec->tf = open_file(rec->fname, 1, OF_VERBOSE)) == NULL) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't open soundfont file %s", FILENAME_REDUCED(rec->fname)); end_soundfont(rec); return; } if(load_soundfont(&sfinfo, rec->tf)) { end_soundfont(rec); return; } correct_samples(&sfinfo); current_sfrec = rec; for (i = 0; i < sfinfo.npresets; i++) { int bank = sfinfo.preset[i].bank; int preset = sfinfo.preset[i].preset; if (bank == 128) /* FIXME: why not allow exclusion of drumsets? */ alloc_instrument_bank(1, preset); else { if (is_excluded(rec, bank, preset, -1)) continue; alloc_instrument_bank(0, bank); } load_font(&sfinfo, i); } /* copy header info */ rec->version = sfinfo.version; rec->minorversion = sfinfo.minorversion; rec->samplepos = sfinfo.samplepos; rec->samplesize = sfinfo.samplesize; rec->inst_namebuf = (char **)SFMalloc(rec, sfinfo.npresets * sizeof(char *)); for(i = 0; i < sfinfo.npresets; i++) rec->inst_namebuf[i] = (char *)SFStrdup(rec, sfinfo.preset[i].hdr.name); free_soundfont(&sfinfo);#ifndef SF_CLOSE_EACH_FILE if(!IS_URL_SEEK_SAFE(rec->tf->url))#endif { close_file(rec->tf); rec->tf = NULL; }}void init_load_soundfont(void){ SFInsts *rec; for(rec = sfrecs; rec != NULL; rec = rec->next) if(rec->fname != NULL) init_sf(rec);}static void end_soundfont(SFInsts *rec){ if (rec->tf) { close_file(rec->tf); rec->tf = NULL; } rec->fname = NULL; rec->inst_namebuf = NULL; rec->sfexclude = NULL; rec->sforder = NULL; reuse_mblock(&rec->pool);}Instrument *extract_soundfont(char *sf_file, int bank, int preset, int keynote){ SFInsts *sf; if((sf = find_soundfont(sf_file)) != NULL) return try_load_soundfont(sf, -1, bank, preset, keynote); sf = new_soundfont(sf_file); sf->next = sfrecs; sf->def_order = 2; sfrecs = sf; init_sf(sf); return try_load_soundfont(sf, -1, bank, preset, keynote);}/*---------------------------------------------------------------- * get converted instrument info and load the wave data from file *----------------------------------------------------------------*/static Instrument *try_load_soundfont(SFInsts *rec, int order, int bank, int preset, int keynote){ InstList *ip; Instrument *inst = NULL; int addr; if (rec->tf == NULL) { if (rec->fname == NULL) return NULL; if ((rec->tf = open_file(rec->fname, 1, OF_VERBOSE)) == NULL) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't open soundfont file %s", FILENAME_REDUCED(rec->fname)); end_soundfont(rec); return NULL; }#ifndef SF_CLOSE_EACH_FILE if(!IS_URL_SEEK_SAFE(rec->tf->url)) rec->tf->url = url_cache_open(rec->tf->url, 1);#endif /* SF_CLOSE_EACH_FILE */ } addr = INSTHASH(bank, preset, keynote); for (ip = rec->instlist[addr]; ip; ip = ip->next) { if (ip->pat.bank == bank && ip->pat.preset == preset && (keynote < 0 || ip->pat.keynote == keynote) && (order < 0 || ip->order == order)) break; } if (ip && ip->samples) inst = load_from_file(rec, ip);#ifdef SF_CLOSE_EACH_FILE close_file(rec->tf); rec->tf = NULL;#endif return inst;}Instrument *load_soundfont_inst(int order, int bank, int preset, int keynote){ SFInsts *rec; Instrument *ip; /* * Search through all ordered soundfonts */ int o = order; for(rec = sfrecs; rec != NULL; rec = rec->next) { if(rec->fname != NULL) { ip = try_load_soundfont(rec, o, bank, preset, keynote); if(ip != NULL) return ip; if (o > 0) o++; } } return NULL;}/*----------------------------------------------------------------*/#define TO_MHZ(abscents) (int32)(8176.0 * pow(2.0,(double)(abscents)/1200.0))#if 0#ifndef M_LN2#define M_LN2 0.69314718055994530942#endif /* M_LN2 */#ifndef M_LN10#define M_LN10 2.30258509299404568402#endif /* M_LN10 */#define TO_VOLUME(centibel) (uint8)(255 * (1.0 - \ (centibel) * (M_LN10 / 1200.0 / M_LN2)))#else#define TO_VOLUME(level) (uint8)(255.0 - (level) * (255.0/1000.0))#endifstatic FLOAT_T calc_volume(LayerTable *tbl){ int v; if(!tbl->set[SF_initAtten] || (int)tbl->val[SF_initAtten] == 0) return (FLOAT_T)1.0; v = (int)tbl->val[SF_initAtten]; if(v < 0) {v = 0;} else if(v > 960) {v = 960;} return cb_to_amp_table[v];}/* convert from 16bit value to fractional offset (15.15) */static int32 to_offset(int32 offset){ return offset << 14;}#define SF_ENVRATE_MAX (0x3FFFFFFFL)#define SF_ENVRATE_MIN (1L)/* calculate ramp rate in fractional unit; * diff = 16bit, time = msec */static int32 calc_rate(int32 diff, double msec){ double rate; if(msec == 0) {return (int32)SF_ENVRATE_MAX + 1;} if(diff <= 0) {diff = 1;} diff <<= 14; rate = ((double)diff / play_mode->rate) * control_ratio * 1000.0 / msec; if(fast_decay) {rate *= 2;} if(rate > SF_ENVRATE_MAX) {rate = SF_ENVRATE_MAX;} else if(rate < SF_ENVRATE_MIN) {rate = SF_ENVRATE_MIN;} return (int32)rate;}/* calculate ramp rate in fractional unit; * diff = 16bit, timecent */static int32 to_rate(int32 diff, int timecent){ double rate; if(timecent == -12000) /* instantaneous attack */ {return (int32)SF_ENVRATE_MAX + 1;} if(diff <= 0) {diff = 1;} diff <<= 14; rate = (double)diff * control_ratio / play_mode->rate / pow(2.0, (double)timecent / 1200.0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -