/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo
Copyright (C) 1995 Tuukka Toivonen
*/
/* This code from awesfx
* Modified by Masanao Izumo
*/
/*================================================================
* 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
#ifndef NO_STRING_H
#include
#else
#include
#endif
#include
#include
#ifdef HAVE_UNISTD_H
#include
#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
*----------------------------------------------------------------*/
/*#define SF_CLOSE_EACH_FILE*/
/*#define SF_SUPPRESS_ENVELOPE*/
/*#define SF_SUPPRESS_TREMOLO*/
/*#define SF_SUPPRESS_VIBRATO*/
#define CUTOFF_AMPTUNING 0.6
/* 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, len;
int32 cutoff_freq;
FLOAT_T resonance;
int16 scaleTuning; /* pitch scale tuning(%), normally 100 */
int16 root, tune;
char low, high; /* key note range */
/* Depend on play_mode->rate */
int32 vibrato_freq;
double attack;
double hold;
int sustain;
double decay;
double release;
} 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 double to_msec(int timecent);
static int32 to_offset(int offset);
static int32 calc_rate(int diff, double msec);
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 void do_lowpass(Sample *sp, int32 freq, FLOAT_T resonance);
/*----------------------------------------------------------------*/
static SFInsts *sfrecs = NULL;
static SFInsts *current_sfrec = NULL;
#define def_drum_inst 0
static 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)
{
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;
return;
}
sf = new_soundfont(sf_file);
if(sf_order >= 0)
sf->def_order = sf_order;
if(sf_cutoff > 0)
sf->def_cutoff_allowed = 1;
if(amp >= 0)
sf->amptune = (FLOAT_T)amp * 0.01;
sf->next = sfrecs;
current_sfrec = sfrecs = 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)
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;
for(rec = sfrecs; rec != NULL; rec = rec->next)
{
if(rec->fname != NULL)
{
ip = try_load_soundfont(rec, order, bank, preset, keynote);
if(ip != NULL)
return ip;
}
}
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))
#endif
static FLOAT_T calc_volume(LayerTable *tbl)
{
int v;
if(!tbl->set[SF_initAtten] || tbl->val[SF_initAtten] == 0)
return (FLOAT_T)1.0;
v = tbl->val[SF_initAtten];
if(v < 0)
return (FLOAT_T)1.0;
if(v > 956)
return (FLOAT_T)0.0;
v = v * 127 / 956; /* 0..127 */
return vol_table[127 - v];
}
/*
* convert timecents to sec
*/
static double to_msec(int timecent)
{
return 1000.0 * pow(2.0, (double)timecent / 1200.0);
}
/* convert from 8bit value to fractional offset (15.15) */
static int32 to_offset(int offset)
{
return (int32)offset << (7+15);
}
/* calculate ramp rate in fractional unit;
* diff = 8bit, time = msec
*/
static int32 calc_rate(int diff, double msec)
{
double rate;
if(msec < 6)
msec = 6;
if(diff == 0)
diff = 255;
diff <<= (7+15);
rate = ((double)diff / play_mode->rate) * control_ratio * 1000.0 / msec;
if(fast_decay)
rate *= 2;
return (int32)rate;
}
/*
* Sustain level
* sf: centibels
* parm: 0x7f - sustain_level(dB) * 0.75
*/
static int32 calc_sustain(int sust_cB)
{
double level;
if(sust_cB <= 0)
return 255;
level = (double)sust_cB;
if(level >= 1000)
return 1;
return TO_VOLUME(level);
}
static Instrument *load_from_file(SFInsts *rec, InstList *ip)
{
SampleList *sp;
Instrument *inst;
int i;
if(ip->pat.bank == 128)
ctl->cmsg(CMSG_INFO, VERB_NOISY,
"Loading SF Drumset %d %d: %s",
ip->pat.preset + progbase, ip->pat.keynote,
rec->inst_namebuf[ip->pr_idx]);
else
ctl->cmsg(CMSG_INFO, VERB_NOISY,
"Loading SF Tonebank %d %d: %s",
ip->pat.bank, ip->pat.preset + progbase,
rec->inst_namebuf[ip->pr_idx]);
inst = (Instrument *)safe_malloc(sizeof(Instrument));
/*
inst->instname = (char *)safe_malloc(strlen(rec->inst_namebuf[ip->pr_idx]));
strcpy(inst->instname,rec->inst_namebuf[ip->pr_idx]);
*/
inst->instname = rec->inst_namebuf[ip->pr_idx];
inst->type = INST_SF2;
inst->samples = ip->samples;
inst->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples);
memset(inst->sample, 0, sizeof(Sample) * ip->samples);
for (i = 0, sp = ip->slist; i < ip->samples && sp; i++, sp = sp->next) {
Sample *sample = inst->sample + i;
int32 j;
#ifndef LITTLE_ENDIAN
int32 k;
int16 *tmp, s;
#endif
ctl->cmsg(CMSG_INFO, VERB_NORMAL, /* VERB_DEBUG */
"[%d] Rate=%d LV=%d HV=%d "
"Low=%d Hi=%d Root=%d Pan=%d",
sp->start, sp->v.sample_rate,
sp->v.low_vel, sp->v.high_vel,
sp->v.low_freq, sp->v.high_freq, sp->v.root_freq,
sp->v.panning);
memcpy(sample, &sp->v, sizeof(Sample));
/* convert mHz to control ratio */
sample->vibrato_control_ratio = sp->vibrato_freq *
(VIBRATO_RATE_TUNING * play_mode->rate) /
(2 * VIBRATO_SAMPLE_INCREMENTS);
/* convert envelop parameters */
sample->envelope_offset[0] = to_offset(255);
sample->envelope_rate[0] = calc_rate(255, sp->attack);
sample->envelope_offset[1] = to_offset(250);
sample->envelope_rate[1] = calc_rate(5, sp->hold);
sample->envelope_offset[2] = to_offset(sp->sustain);
sample->envelope_rate[2] = calc_rate(250 - sp->sustain, sp->decay);
sample->envelope_offset[3] = to_offset(5);
sample->envelope_rate[3] = calc_rate(255, sp->release);
/* 035.06 sms */
ctl->cmsg(CMSG_INFO, VERB_DEBUG,
"attack=%lg rate[0]=%d hold=%lg sustain=%d "
"decay=%lg release=%lg rate[3]=%d",
sp->attack, sample->envelope_rate[0], sp->hold,
sp->sustain, sp->decay,
sp->release, sample->envelope_rate[3] );
/* 035.06 sms */
sample->envelope_offset[4] = to_offset(4);
sample->envelope_rate[4] = to_offset(200);
sample->envelope_offset[5] = to_offset(4);
sample->envelope_rate[5] = to_offset(200);
#if 0
sample->envelope_offset[3] = to_offset(1);
sample->envelope_rate[3] = calc_rate(sp->sustain, sp->release);
sample->envelope_offset[4] = sp->v.envelope_offset[3];
sample->envelope_rate[4] = sp->v.envelope_rate[3];
sample->envelope_offset[5] = sp->v.envelope_offset[4];
sample->envelope_rate[5] = sp->v.envelope_rate[4];
#endif
if(i > 0 && (sample->note_to_use ||
(sample->modes & MODES_LOOPING)))
{
SampleList *sps;
Sample *found, *s;
found = NULL;
for(j = 0, sps = ip->slist, s = inst->sample; j < i && sps;
j++, sps = sps->next, s++)
{
if(s->data == NULL)
break;
if(sp->start == sps->start)
{
if(sp->cutoff_freq != sps->cutoff_freq ||
sp->resonance != sps->cutoff_freq)
continue;
if(antialiasing_allowed)
{
if(sample->data_length != s->data_length ||
sample->sample_rate != s->sample_rate)
continue;
}
if(s->note_to_use && !(s->modes & MODES_LOOPING))
continue;
found = s;
break;
}
}
if(found)
{
sample->data = found->data;
sample->data_alloced = 0;
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * Cached");
continue;
}
}
sample->data = (sample_t *)safe_malloc(sp->len);
sample->data_alloced = 1;
ctl->cmsg(CMSG_INFO, VERB_DEBUG_SILLY,
"Data: %d %d V=%g, envofs: %d %d %d %d %d %d",
sp->start, sp->start + sp->len,
sample->volume,
sample->envelope_offset[0] >> 22,
sample->envelope_offset[1] >> 22,
sample->envelope_offset[2] >> 22,
sample->envelope_offset[3] >> 22,
sample->envelope_offset[4] >> 22,
sample->envelope_offset[5] >> 22);
tf_seek(rec->tf, sp->start, SEEK_SET);
tf_read(sample->data, sp->len, 1, rec->tf);
#ifndef LITTLE_ENDIAN
tmp = (int16*)sample->data;
k = sp->len/2;
for (j = 0; j < k; j++) {
s = LE_SHORT(*tmp);
*tmp++ = s;
}
#endif
/* do some filtering if necessary */
if (sp->cutoff_freq > 0) {
/* restore the normal value */
sample->data_length >>= FRACTION_BITS;
ctl->cmsg(CMSG_INFO, VERB_DEBUG,
" * Filter: cutoff=%dHz resonance=%g",
ip->pat.bank, ip->pat.preset, ip->pat.keynote, sp->cutoff_freq, sp->resonance);
do_lowpass(sample, sp->cutoff_freq, sp->resonance);
/* convert again to the fractional value */
sample->data_length <<= FRACTION_BITS;
}
if (antialiasing_allowed)
antialiasing((int16 *)sample->data,
sample->data_length >> FRACTION_BITS,
sample->sample_rate,
play_mode->rate);
/* resample it if possible */
if (sample->note_to_use && !(sample->modes & MODES_LOOPING))
pre_resample(sample);
#ifdef LOOKUP_HACK
/* squash the 16-bit data into 8 bits. */
{
uint8 *gulp,*ulp;
int16 *swp;
int l = sample->data_length >> FRACTION_BITS;
gulp = ulp = (uint8 *)safe_malloc(l + 1);
swp = (int16 *)sample->data;
while (l--)
*ulp++ = (*swp++ >> 8) & 0xFF;
free(sample->data);
sample->data=(sample_t *)gulp;
}
#endif
}
return inst;
}
/*----------------------------------------------------------------
* excluded samples
*----------------------------------------------------------------*/
int exclude_soundfont(int bank, int preset, int keynote)
{
SFExclude *exc;
if(current_sfrec == NULL)
return 1;
exc = (SFExclude*)SFMalloc(current_sfrec , sizeof(SFExclude));
exc->pat.bank = bank;
exc->pat.preset = preset;
exc->pat.keynote = keynote;
exc->next = current_sfrec->sfexclude;
current_sfrec->sfexclude = exc;
return 0;
}
/* check the instrument is specified to be excluded */
static int is_excluded(SFInsts *rec, int bank, int preset, int keynote)
{
SFExclude *p;
for (p = rec->sfexclude; p; p = p->next) {
if (p->pat.bank == bank &&
(p->pat.preset < 0 || p->pat.preset == preset) &&
(p->pat.keynote < 0 || p->pat.keynote == keynote))
return 1;
}
return 0;
}
/*----------------------------------------------------------------
* ordered samples
*----------------------------------------------------------------*/
int order_soundfont(int bank, int preset, int keynote, int order)
{
SFOrder *p;
if(current_sfrec == NULL)
return 1;
p = (SFOrder*)SFMalloc(current_sfrec, sizeof(SFOrder));
p->pat.bank = bank;
p->pat.preset = preset;
p->pat.keynote = keynote;
p->order = order;
p->next = current_sfrec->sforder;
current_sfrec->sforder = p;
return 0;
}
/* check the instrument is specified to be ordered */
static int is_ordered(SFInsts *rec, int bank, int preset, int keynote)
{
SFOrder *p;
for (p = rec->sforder; p; p = p->next) {
if (p->pat.bank == bank &&
(p->pat.preset < 0 || p->pat.preset == preset) &&
(p->pat.keynote < 0 || p->pat.keynote == keynote))
return p->order;
}
return -1;
}
/*----------------------------------------------------------------*/
static int load_font(SFInfo *sf, int pridx)
{
SFPresetHdr *preset = &sf->preset[pridx];
int rc, j, nlayers;
SFGenLayer *layp, *globalp;
/* if layer is empty, skip it */
if ((nlayers = preset->hdr.nlayers) <= 0 ||
(layp = preset->hdr.layer) == NULL)
return AWE_RET_SKIP;
/* check global layer */
globalp = NULL;
if (is_global(layp)) {
globalp = layp;
layp++;
nlayers--;
}
/* parse for each preset layer */
for (j = 0; j < nlayers; j++, layp++) {
LayerTable tbl;
/* set up table */
clear_table(&tbl);
if (globalp)
set_to_table(sf, &tbl, globalp, P_GLOBAL);
set_to_table(sf, &tbl, layp, P_LAYER);
/* parse the instrument */
rc = parse_layer(sf, pridx, &tbl, 0);
if(rc == AWE_RET_ERR || rc == AWE_RET_NOMEM)
return rc;
}
return AWE_RET_OK;
}
/*----------------------------------------------------------------*/
/* parse a preset layer and convert it to the patch structure */
static int parse_layer(SFInfo *sf, int pridx, LayerTable *tbl, int level)
{
SFInstHdr *inst;
int rc, i, nlayers;
SFGenLayer *lay, *globalp;
#if 0
SFPresetHdr *preset = &sf->preset[pridx];
#endif
if (level >= 2) {
fprintf(stderr, "parse_layer: too deep instrument level\n");
return AWE_RET_ERR;
}
/* instrument must be defined */
if (!tbl->set[SF_instrument])
return AWE_RET_SKIP;
inst = &sf->inst[tbl->val[SF_instrument]];
/* Here, TiMidity makes the reference of the data. The real data
* is loaded after. So, duplicated data is allowed */
#if 0
/* if non-standard drumset includes standard drum instruments,
skip it to avoid duplicate the data */
if (def_drum_inst >= 0 && preset->bank == 128 && preset->preset != 0 &&
tbl->val[SF_instrument] == def_drum_inst)
return AWE_RET_SKIP;
#endif
/* if layer is empty, skip it */
if ((nlayers = inst->hdr.nlayers) <= 0 ||
(lay = inst->hdr.layer) == NULL)
return AWE_RET_SKIP;
/* check global layer */
globalp = NULL;
if (is_global(lay)) {
globalp = lay;
lay++;
nlayers--;
}
/* parse for each layer */
for (i = 0; i < nlayers; i++, lay++) {
LayerTable ctbl;
clear_table(&ctbl);
if (globalp)
set_to_table(sf, &ctbl, globalp, P_GLOBAL);
set_to_table(sf, &ctbl, lay, P_LAYER);
if (!ctbl.set[SF_sampleId]) {
/* recursive loading */
merge_table(sf, &ctbl, tbl);
if (! sanity_range(&ctbl))
continue;
rc = parse_layer(sf, pridx, &ctbl, level+1);
if (rc != AWE_RET_OK && rc != AWE_RET_SKIP)
return rc;
} else {
init_and_merge_table(sf, &ctbl, tbl);
if (! sanity_range(&ctbl))
continue;
/* load the info data */
if ((rc = make_patch(sf, pridx, &ctbl)) == AWE_RET_ERR)
return rc;
}
}
return AWE_RET_OK;
}
static int is_global(SFGenLayer *layer)
{
int i;
for (i = 0; i < layer->nlists; i++) {
if (layer->list[i].oper == SF_instrument ||
layer->list[i].oper == SF_sampleId)
return 0;
}
return 1;
}
/*----------------------------------------------------------------
* layer table handlers
*----------------------------------------------------------------*/
/* initialize layer table */
static void clear_table(LayerTable *tbl)
{
memset(tbl->val, 0, sizeof(tbl->val));
memset(tbl->set, 0, sizeof(tbl->set));
}
/* set items in a layer to the table */
static void set_to_table(SFInfo *sf, LayerTable *tbl, SFGenLayer *lay, int level)
{
int i;
for (i = 0; i < lay->nlists; i++) {
SFGenRec *gen = &lay->list[i];
/* copy the value regardless of its copy policy */
tbl->val[gen->oper] = gen->amount;
tbl->set[gen->oper] = level;
}
}
/* add an item to the table */
static void add_item_to_table(LayerTable *tbl, int oper, int amount, int level)
{
LayerItem *item = &layer_items[oper];
int o_lo, o_hi, lo, hi;
switch (item->copy) {
case L_INHRT:
tbl->val[oper] += amount;
break;
case L_OVWRT:
tbl->val[oper] = amount;
break;
case L_PRSET:
case L_INSTR:
/* do not overwrite */
if (!tbl->set[oper])
tbl->val[oper] = amount;
break;
case L_RANGE:
if (!tbl->set[oper]) {
tbl->val[oper] = amount;
} else {
o_lo = LOWNUM(tbl->val[oper]);
o_hi = HIGHNUM(tbl->val[oper]);
lo = LOWNUM(amount);
hi = HIGHNUM(amount);
if (lo < o_lo) lo = o_lo;
if (hi > o_hi) hi = o_hi;
tbl->val[oper] = RANGE(lo, hi);
}
break;
}
}
/* merge two tables */
static void merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src)
{
int i;
for (i = 0; i < SF_EOF; i++) {
if (src->set[i]) {
if (sf->version == 1) {
if (!dst->set[i] ||
i == SF_keyRange || i == SF_velRange)
/* just copy it */
dst->val[i] = src->val[i];
}
else
add_item_to_table(dst, i, src->val[i], P_GLOBAL);
dst->set[i] = P_GLOBAL;
}
}
}
/* merge and set default values */
static void init_and_merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src)
{
int i;
/* default value is not zero */
if (sf->version == 1) {
layer_items[SF_sustainEnv1].defv = 1000;
layer_items[SF_sustainEnv2].defv = 1000;
layer_items[SF_freqLfo1].defv = -725;
layer_items[SF_freqLfo2].defv = -15600;
} else {
layer_items[SF_sustainEnv1].defv = 0;
layer_items[SF_sustainEnv2].defv = 0;
layer_items[SF_freqLfo1].defv = 0;
layer_items[SF_freqLfo2].defv = 0;
}
/* set default */
for (i = 0; i < SF_EOF; i++) {
if (!dst->set[i])
dst->val[i] = layer_items[i].defv;
}
merge_table(sf, dst, src);
/* convert from SBK to SF2 */
if (sf->version == 1) {
for (i = 0; i < SF_EOF; i++) {
if (dst->set[i])
dst->val[i] = sbk_to_sf2(i, dst->val[i]);
}
}
}
/*----------------------------------------------------------------
* check key and velocity range
*----------------------------------------------------------------*/
static int sanity_range(LayerTable *tbl)
{
int lo, hi;
lo = LOWNUM(tbl->val[SF_keyRange]);
hi = HIGHNUM(tbl->val[SF_keyRange]);
if (lo < 0 || lo > 127 || hi < 0 || hi > 127 || hi < lo)
return 0;
lo = LOWNUM(tbl->val[SF_velRange]);
hi = HIGHNUM(tbl->val[SF_velRange]);
if (lo < 0 || lo > 127 || hi < 0 || hi > 127 || hi < lo)
return 0;
return 1;
}
/*----------------------------------------------------------------
* create patch record from the stored data table
*----------------------------------------------------------------*/
#ifdef CFG_FOR_SF
static int cfg_for_sf_scan(char *name, int x_bank, int x_preset, int x_keynote_from, int x_keynote_to, int romflag);
#endif
static int make_patch(SFInfo *sf, int pridx, LayerTable *tbl)
{
int bank, preset, keynote;
int keynote_from, keynote_to, done;
int addr, order;
InstList *ip;
SFSampleInfo *sample;
SampleList *sp;
sample = &sf->sample[tbl->val[SF_sampleId]];
#ifdef CFG_FOR_SF
cfg_for_sf_scan(sample->name,sf->preset[pridx].bank,sf->preset[pridx].preset,LOWNUM(tbl->val[SF_keyRange]),
HIGHNUM(tbl->val[SF_keyRange]),sample->sampletype & 0x8000);
#endif
if(sample->sampletype & 0x8000) /* is ROM sample? */
{
ctl->cmsg(CMSG_INFO, VERB_DEBUG, "preset %d is ROM sample: 0x%x",
pridx, sample->sampletype);
return AWE_RET_SKIP;
}
bank = sf->preset[pridx].bank;
preset = sf->preset[pridx].preset;
if(bank == 128){
keynote_from = LOWNUM(tbl->val[SF_keyRange]);
keynote_to = HIGHNUM(tbl->val[SF_keyRange]);
} else
keynote_from = keynote_to = -1;
done = 0;
for(keynote=keynote_from;keynote<=keynote_to;keynote++){
ctl->cmsg(CMSG_INFO, VERB_DEBUG_SILLY,
"SF make inst pridx=%d bank=%d preset=%d keynote=%d",
pridx, bank, preset, keynote);
if(is_excluded(current_sfrec, bank, preset, keynote))
{
ctl->cmsg(CMSG_INFO, VERB_DEBUG_SILLY, " * Excluded");
continue;
} else
done++;
order = is_ordered(current_sfrec, bank, preset, keynote);
if(order < 0)
order = current_sfrec->def_order;
addr = INSTHASH(bank, preset, keynote);
for(ip = current_sfrec->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)
{
ip = (InstList*)SFMalloc(current_sfrec, sizeof(InstList));
memset(ip, 0, sizeof(InstList));
ip->pr_idx = pridx;
ip->pat.bank = bank;
ip->pat.preset = preset;
ip->pat.keynote = keynote;
ip->order = order;
ip->samples = 0;
ip->slist = NULL;
ip->next = current_sfrec->instlist[addr];
current_sfrec->instlist[addr] = ip;
}
/* new sample */
sp = (SampleList *)SFMalloc(current_sfrec, sizeof(SampleList));
memset(sp, 0, sizeof(SampleList));
if(bank == 128)
sp->v.note_to_use = keynote;
sp->v.high_vel = 127;
make_info(sf, sp, tbl);
/* add a sample */
if(ip->slist == NULL)
ip->slist = sp;
else
{
SampleList *cur, *prev;
int32 start;
/* Insert sample */
start = sp->start;
cur = ip->slist;
prev = NULL;
while(cur && cur->start <= start)
{
prev = cur;
cur = cur->next;
}
if(prev == NULL)
{
sp->next = ip->slist;
ip->slist = sp;
}
else
{
prev->next = sp;
sp->next = cur;
}
}
ip->samples++;
} /* for(;;) */
if(done==0)
return AWE_RET_SKIP;
else
return AWE_RET_OK;
}
/*----------------------------------------------------------------
*
* Modified for TiMidity
*/
/* conver to Sample parameter */
static void make_info(SFInfo *sf, SampleList *vp, LayerTable *tbl)
{
set_sample_info(sf, vp, tbl);
set_init_info(sf, vp, tbl);
set_rootkey(sf, vp, tbl);
set_rootfreq(vp);
/* tremolo & vibrato */
#ifndef SF_SUPPRESS_TREMOLO
convert_tremolo(vp, tbl);
#endif /* SF_SUPPRESS_TREMOLO */
#ifndef SF_SUPPRESS_VIBRATO
convert_vibrato(vp, tbl);
#endif /* SF_SUPPRESS_VIBRATO */
}
/* set sample address */
static void set_sample_info(SFInfo *sf, SampleList *vp, LayerTable *tbl)
{
SFSampleInfo *sp = &sf->sample[tbl->val[SF_sampleId]];
/* set sample position */
vp->start = (tbl->val[SF_startAddrsHi] << 15)
+ tbl->val[SF_startAddrs]
+ sp->startsample;
vp->len = (tbl->val[SF_endAddrsHi] << 15)
+ tbl->val[SF_endAddrs]
+ sp->endsample - vp->start;
/* set loop position */
vp->v.loop_start = (tbl->val[SF_startloopAddrsHi] << 15)
+ tbl->val[SF_startloopAddrs]
+ sp->startloop - vp->start;
vp->v.loop_end = (tbl->val[SF_endloopAddrsHi] << 15)
+ tbl->val[SF_endloopAddrs]
+ sp->endloop - vp->start;
/* set data length */
vp->v.data_length = vp->len;
if(vp->v.loop_end > vp->len)
vp->v.loop_end = vp->len;
/* Sample rate */
vp->v.sample_rate = sp->samplerate;
/* sample mode */
vp->v.modes = MODES_16BIT;
/* volume envelope & total volume */
vp->v.volume = calc_volume(tbl) * current_sfrec->amptune;
if(tbl->val[SF_sampleFlags] == 1 || tbl->val[SF_sampleFlags] == 3)
{
/* looping */
vp->v.modes |= MODES_LOOPING|MODES_SUSTAIN;
#ifndef SF_SUPPRESS_ENVELOPE
convert_volume_envelope(vp, tbl);
#endif /* SF_SUPPRESS_ENVELOPE */
if(tbl->val[SF_sampleFlags] == 3)
vp->v.data_length = vp->v.loop_end; /* strip the tail */
}
else
{
#if 0 /* What?? */
/* short-shot; set a small blank loop at the tail */
if (sp->loopshot > 8) {
vp->loopstart = sp->endsample + 8 - sp->startloop;
vp->loopend = sp->endsample + sp->loopshot - 8 - sp->endloop;
} else {
fprintf(stderr, "loop size is too short: %d\n", sp->loopshot);
exit(1);
}
#endif
}
/* convert to fractional samples */
vp->v.data_length <<= FRACTION_BITS;
vp->v.loop_start <<= FRACTION_BITS;
vp->v.loop_end <<= FRACTION_BITS;
/* point to the file position */
vp->start = vp->start * 2 + sf->samplepos;
vp->len *= 2;
}
/*----------------------------------------------------------------*/
/* set global information */
static void set_init_info(SFInfo *sf, SampleList *vp, LayerTable *tbl)
{
int val;
/* key range */
if(tbl->set[SF_keyRange])
{
vp->low = LOWNUM(tbl->val[SF_keyRange]);
vp->high = HIGHNUM(tbl->val[SF_keyRange]);
}
else
{
vp->low = 0;
vp->high = 127;
}
vp->v.low_freq = freq_table[(int)vp->low];
vp->v.high_freq = freq_table[(int)vp->high];
/* velocity range */
if(tbl->set[SF_velRange])
{
vp->v.low_vel = LOWNUM(tbl->val[SF_velRange]);
vp->v.high_vel = HIGHNUM(tbl->val[SF_velRange]);
}
/* fixed key & velocity */
if(tbl->set[SF_keynum])
vp->v.note_to_use = tbl->val[SF_keynum];
#if 0 /* Not supported */
vp->fixvel = tbl->val[SF_velocity];
#endif
/* panning position: 0 to 127 */
val = (int)tbl->val[SF_panEffectsSend];
if(val < -500)
vp->v.panning = 0;
else if(val > 500)
vp->v.panning = 127;
else
vp->v.panning = (int8)((val + 500) * 127 / 1000);
/* vp->fixpan = -1; */
#if 0 /* Not supported */
/* initial volume */
vp->amplitude = awe_option.default_volume * 127 / 100;
/* this is not a centibel? */
vp->attenuation = awe_calc_attenuation((int)(tbl->val[SF_initAtten] / awe_option.atten_sense));
/* chorus & reverb effects */
if (tbl->set[SF_chorusEffectsSend])
vp->parm.chorus = awe_calc_chorus(tbl->val[SF_chorusEffectsSend]);
else
vp->parm.chorus = awe_option.default_chorus * 255 / 100;
if (tbl->set[SF_reverbEffectsSend])
vp->parm.reverb = awe_calc_reverb(tbl->val[SF_chorusEffectsSend]);
else
vp->parm.reverb = awe_option.default_reverb * 255 / 100;
#endif
/* initial cutoff & resonance */
vp->cutoff_freq = 0;
if(tbl->val[SF_initialFilterFc] < 0)
tbl->set[SF_initialFilterFc] = tbl->val[SF_initialFilterFc] = 0;
if(current_sfrec->def_cutoff_allowed &&
(tbl->set[SF_initialFilterFc] || tbl->set[SF_env1ToFilterFc]))
{
if(!tbl->set[SF_initialFilterFc])
val = 13500;
else
val = tbl->val[SF_initialFilterFc];
if(tbl->set[SF_env1ToFilterFc])
val += tbl->val[SF_env1ToFilterFc];
vp->cutoff_freq = abscent_to_Hz(val);
}
vp->resonance = 0;
if(current_sfrec->def_resonance_allowed && tbl->set[SF_initialFilterQ])
{
val = tbl->val[SF_initialFilterQ];
vp->resonance = pow(10.0, (double)val / 2.0 / 200.0) - 1;
if(vp->resonance < 0)
vp->resonance = 0;
}
#if 0 /* Not supported */
/* exclusive class key */
vp->exclusiveClass = tbl->val[SF_keyExclusiveClass];
#endif
}
static int abscent_to_Hz(int abscents)
{
return (int)(8.176 * pow(2.0, (double)abscents / 1200.0));
}
/*----------------------------------------------------------------*/
/* calculate root key & fine tune */
static void set_rootkey(SFInfo *sf, SampleList *vp, LayerTable *tbl)
{
SFSampleInfo *sp = &sf->sample[tbl->val[SF_sampleId]];
/* scale tuning */
vp->scaleTuning = tbl->val[SF_scaleTuning];
/* set initial root key & fine tune */
if(sf->version == 1 && tbl->set[SF_samplePitch])
{
/* set from sample pitch */
vp->root = tbl->val[SF_samplePitch] / 100;
vp->tune = -tbl->val[SF_samplePitch] % 100;
if(vp->tune <= -50)
{
vp->root++;
vp->tune = 100 + vp->tune;
}
if(vp->scaleTuning == 50)
vp->tune /= 2;
}
else
{
/* from sample info */
vp->root = sp->originalPitch;
vp->tune = sp->pitchCorrection;
if (vp->tune >= 0x80)
vp->tune -= 0x100; /* correct sign */
}
/* orverride root key */
if(tbl->set[SF_rootKey])
vp->root += tbl->val[SF_rootKey] - sp->originalPitch;
vp->tune += tbl->val[SF_coarseTune] * vp->scaleTuning +
(int)tbl->val[SF_fineTune] * (int)vp->scaleTuning / 100;
/* correct too high pitch */
if(vp->root >= vp->high + 60)
vp->root -= 60;
/* correct tune with the sustain level of modulation envelope */
vp->tune += ((int)tbl->val[SF_env1ToPitch] * (1000 - (int)tbl->val[SF_sustainEnv1])) / 1000;
/* correct tune */
vp->tune += (int)tbl->val[SF_lfo1ToPitch];
vp->tune += (int)tbl->val[SF_lfo2ToPitch];
}
static void set_rootfreq(SampleList *vp)
{
int root, tune;
root = vp->root;
tune = vp->tune;
while(tune <= -100)
{
root++;
tune += 100;
}
while(tune > 0)
{
root--;
tune -= 100;
}
/* -100 < tune <= 0 */
tune = (-tune * 256) / 100;
if(root > 127)
vp->v.root_freq = (int32)((FLOAT_T)freq_table[127] *
bend_coarse[root - 127] * bend_fine[tune]);
else if(root < 0)
vp->v.root_freq = (int32)((FLOAT_T)freq_table[0] /
bend_coarse[-root] * bend_fine[tune]);
else
vp->v.root_freq = (int32)((FLOAT_T)freq_table[root] * bend_fine[tune]);
}
/*----------------------------------------------------------------*/
/*Pseudo Reverb*/
extern int32 modify_release;
/* volume envelope parameters */
static void convert_volume_envelope(SampleList *vp, LayerTable *tbl)
{
vp->attack = to_msec(tbl->val[SF_attackEnv2]);
vp->hold = to_msec(tbl->val[SF_holdEnv2]);
vp->sustain = calc_sustain(tbl->val[SF_sustainEnv2]);
if(vp->sustain > 250)
vp->sustain = 250;
vp->decay = to_msec(tbl->val[SF_decayEnv2]);
if(modify_release)
vp->release = modify_release;
else
vp->release = to_msec(tbl->val[SF_releaseEnv2]); /* Pseudo Reverb */
#if 0 /* Not supported */
/* key hold/decay */
vp->parm.volkeyhold = tbl->val[SF_autoHoldEnv2];
vp->parm.volkeydecay = tbl->val[SF_autoDecayEnv2];
#endif
vp->v.modes |= MODES_ENVELOPE;
}
#ifndef SF_SUPPRESS_TREMOLO
/*----------------------------------------------------------------
* tremolo (LFO1) conversion
*----------------------------------------------------------------*/
static void convert_tremolo(SampleList *vp, LayerTable *tbl)
{
int32 level, freq;
if(!tbl->set[SF_lfo1ToVolume])
return;
level = tbl->val[SF_lfo1ToVolume];
level = (level * 0x80) / 120;
if(level < -128)
level = -128;
if(level > 127)
level = 127;
if(level < 0)
level += 0x100;
vp->v.tremolo_depth = (uint8)level;
/* frequency in mHz */
if(!tbl->set[SF_freqLfo1])
freq = 0;
else
{
freq = tbl->val[SF_freqLfo1];
freq = TO_MHZ(freq);
}
/* convert mHz to sine table increment; 1024<v.tremolo_phase_increment = (freq * 1024) << RATE_SHIFT;
vp->v.tremolo_sweep_increment = 0;
}
#endif
#ifndef SF_SUPPRESS_VIBRATO
/*----------------------------------------------------------------
* vibrato (LFO2) conversion
*----------------------------------------------------------------*/
static void convert_vibrato(SampleList *vp, LayerTable *tbl)
{
int32 shift, freq;
if(!tbl->set[SF_lfo2ToPitch])
return;
shift = tbl->val[SF_lfo2ToPitch];
/* cents to linear; 400cents = 256 */
shift = shift * 256 / 400;
if(shift < 0)
shift = -shift;
vp->v.vibrato_depth = (uint8)shift;
/* frequency in mHz */
if(!tbl->set[SF_freqLfo2])
freq = 0;
else
{
freq = tbl->val[SF_freqLfo2];
freq = TO_MHZ(freq);
}
vp->vibrato_freq = freq;
vp->v.vibrato_sweep_increment = 0;
}
#endif
/*----------------------------------------------------------------
* low-pass filter:
* y(n) = A * x(n) + B * y(n-1)
* A = 2.0 * pi * center
* B = exp(-A / frequency)
*----------------------------------------------------------------
* resonance filter:
* y(n) = a * x(n) - b * y(n-1) - c * y(n-2)
* c = exp(-2 * pi * width / rate)
* b = -4 * c / (1+c) * cos(2 * pi * center / rate)
* a = sqt(1-b*b/(4 * c)) * (1-c)
*----------------------------------------------------------------*/
#ifdef LOOKUP_HACK
#define MAX_DATAVAL 127
#define MIN_DATAVAL -128
#else
#define MAX_DATAVAL 32767
#define MIN_DATAVAL -32768
#endif
static void do_lowpass(Sample *sp, int32 freq, FLOAT_T resonance)
{
int32 i,length;
FLOAT_T f,k,p,r,scale;
sample_t *buf;
sample_t y1,y2,y3,y4,oldy1,oldy2,oldy3,oldx,x;
if (freq > sp->sample_rate * 2) {
ctl->cmsg(CMSG_WARNING, VERB_NORMAL,
"Lowpass: center freq must be < data rate * 2");
return;
}
buf = sp->data;
length = sp->data_length;
y1=y2=y3=y4=oldx=oldy1=oldy2=oldy3=0;
f = 2.0 * freq / sp->sample_rate;
k = 3.6*f - 1.6*f*f - 1;
p = (k+1)*0.5;
scale = exp((1-p)*1.386249);
r = resonance * scale;
r /= 4;
y4 = buf[0];
for(i=0;i
static int cmsg(int type, int verbosity_level, char *fmt, ...)
{
va_list ap;
if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
ctl->verbosityverbosity = -1;
#ifdef SUPPORT_SOCKET
// init_mail_addr();
if(url_user_agent == NULL){
url_user_agent = (char *)safe_malloc(10 + strlen(timidity_version));
strcpy(url_user_agent, "TiMidity-");
strcat(url_user_agent, timidity_version);
}
#endif /* SUPPORT_SOCKET */
for(i = 0; url_module_list[i]; i++)
url_add_module(url_module_list[i]);
x_sf_file_name = argv[1];
sf = new_soundfont(x_sf_file_name);
sf->next = NULL;
sf->def_order = 2;
sfrecs = sf;
x_cfg_info_init();
init_sf(sf);
if(x_sort){
for(x_bank=0;x_bank<=127;x_bank++){
int flag = 0;
for(x_preset=0;x_preset<=127;x_preset++){
if(x_cfg_info.m_bank[x_bank][x_preset] >= 0 && x_cfg_info.m_preset[x_bank][x_preset] >= 0){
flag = 1;
}
}
if(!flag)
continue;
if(!initial){
initial = 1;
fprintf(x_out,"bank %d\n",x_bank);
} else
fprintf(x_out,"\nbank %d\n",x_bank);
for(x_preset=0;x_preset<=127;x_preset++){
if(x_cfg_info.m_bank[x_bank][x_preset] >= 0 && x_cfg_info.m_preset[x_bank][x_preset] >= 0){
if(x_cfg_info.m_rom[x_bank][x_preset])
fprintf(x_out,"# %d %%font %s %d %d # (ROM)\n%s",x_preset,x_sf_file_name,x_cfg_info.m_bank[x_bank][x_preset],x_cfg_info.m_preset[x_bank][x_preset],x_cfg_info.m_str[x_bank][x_preset]);
else
fprintf(x_out," %d %%font %s %d %d\n%s",x_preset,x_sf_file_name,x_cfg_info.m_bank[x_bank][x_preset],x_cfg_info.m_preset[x_bank][x_preset],x_cfg_info.m_str[x_bank][x_preset]);
}
}
}
for(x_preset=0;x_preset<=127;x_preset++){
int flag = 0;
for(x_keynote=0;x_keynote<=127;x_keynote++){
if(x_cfg_info.d_preset[x_preset][x_keynote] >= 0 && x_cfg_info.d_keynote[x_preset][x_keynote] >= 0){
flag = 1;
}
}
if(!flag)
continue;
if(!initial){
initial = 1;
fprintf(x_out,"drumset %d\n",x_preset);
} else
fprintf(x_out,"\ndrumset %d\n",x_preset);
for(x_keynote=0;x_keynote<=127;x_keynote++){
if(x_cfg_info.d_preset[x_preset][x_keynote] >= 0 && x_cfg_info.d_keynote[x_preset][x_keynote] >= 0){
if(x_cfg_info.d_rom[x_preset][x_keynote])
fprintf(x_out,"# %d %%font %s 128 %d %d #%s (ROM)\n",x_keynote,x_sf_file_name,x_cfg_info.d_preset[x_preset][x_keynote],x_cfg_info.d_keynote[x_preset][x_keynote],x_cfg_info.d_str[x_preset][x_keynote]);
else
fprintf(x_out," %d %%font %s 128 %d %d #%s\n",x_keynote,x_sf_file_name,x_cfg_info.d_preset[x_preset][x_keynote],x_cfg_info.d_keynote[x_preset][x_keynote],x_cfg_info.d_str[x_preset][x_keynote]);
}
}
}
}
if(x_out!=stdout)
fclose(x_out);
return 0;
}
#endif /* CFG_FOR_SF */