/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo
Copyright (C) 1995 Tuukka Toivonen
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
instrum.c
Code to load and unload GUS-compatible instrument patches.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include
#include
#ifndef NO_STRING_H
#include
#else
#include
#endif
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "readmidi.h"
#include "output.h"
#include "controls.h"
#include "resample.h"
#include "tables.h"
#include "filter.h"
#define INSTRUMENT_HASH_SIZE 128
struct InstrumentCache
{
char *name;
int panning, amp, note_to_use, strip_loop, strip_envelope, strip_tail;
Instrument *ip;
struct InstrumentCache *next;
};
static struct InstrumentCache *instrument_cache[INSTRUMENT_HASH_SIZE];
/* Some functions get aggravated if not even the standard banks are
available. */
static ToneBank standard_tonebank, standard_drumset;
ToneBank
*tonebank[128]={&standard_tonebank},
*drumset[128]={&standard_drumset};
/* This is a special instrument, used for all melodic programs */
Instrument *default_instrument=0;
SpecialPatch *special_patch[NSPECIAL_PATCH];
int progbase = 0;
struct inst_map_elem
{
int set, elem;
};
static struct inst_map_elem *inst_map_table[NUM_INST_MAP][128];
/* This is only used for tracks that don't specify a program */
int default_program[MAX_CHANNELS];
char *default_instrument_name = NULL;
int antialiasing_allowed=0;
#ifdef FAST_DECAY
int fast_decay=1;
#else
int fast_decay=0;
#endif
/*Pseudo Reverb*/
int32 modify_release;
/** below three functinos are imported from sndfont.c **/
/* 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;
}
/*End of Pseudo Reverb*/
static void free_instrument(Instrument *ip)
{
Sample *sp;
int i;
if (!ip) return;
for (i=0; isamples; i++)
{
sp=&(ip->sample[i]);
if(sp->data_alloced)
free(sp->data);
}
free(ip->sample);
free(ip);
}
void clear_magic_instruments(void)
{
int i, j;
for(j = 0; j < 128; j++)
{
if(tonebank[j])
{
ToneBank *bank = tonebank[j];
for(i = 0; i < 128; i++)
if(IS_MAGIC_INSTRUMENT(bank->tone[i].instrument))
bank->tone[i].instrument = NULL;
}
if(drumset[j])
{
ToneBank *bank = drumset[j];
for(i = 0; i < 128; i++)
if(IS_MAGIC_INSTRUMENT(bank->tone[i].instrument))
bank->tone[i].instrument = NULL;
}
}
}
static int32 convert_envelope_rate(uint8 rate)
{
int32 r;
r=3-((rate>>6) & 0x3);
r*=3;
r = (int32)(rate & 0x3f) << r; /* 6.9 fixed point */
/* 15.15 fixed point. */
return (((r * 44100) / play_mode->rate) * control_ratio)
<< ((fast_decay) ? 10 : 9);
}
static int32 convert_envelope_offset(uint8 offset)
{
/* This is not too good... Can anyone tell me what these values mean?
Are they GUS-style "exponential" volumes? And what does that mean? */
/* 15.15 fixed point */
return offset << (7+15);
}
static int32 convert_tremolo_sweep(uint8 sweep)
{
if (!sweep)
return 0;
return
((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
(play_mode->rate * sweep);
}
static int32 convert_vibrato_sweep(uint8 sweep, int32 vib_control_ratio)
{
if (!sweep)
return 0;
return (int32)(TIM_FSCALE((double) (vib_control_ratio)
* SWEEP_TUNING, SWEEP_SHIFT)
/ (double)(play_mode->rate * sweep));
/* this was overflowing with seashore.pat
((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
(play_mode->rate * sweep); */
}
static int32 convert_tremolo_rate(uint8 rate)
{
return
((SINE_CYCLE_LENGTH * control_ratio * rate) << RATE_SHIFT) /
(TREMOLO_RATE_TUNING * play_mode->rate);
}
static int32 convert_vibrato_rate(uint8 rate)
{
/* Return a suitable vibrato_control_ratio value */
return
(VIBRATO_RATE_TUNING * play_mode->rate) /
(rate * 2 * VIBRATO_SAMPLE_INCREMENTS);
}
static void reverse_data(int16 *sp, int32 ls, int32 le)
{
int16 s, *ep=sp+le;
int32 i;
sp+=ls;
le-=ls;
le/=2;
for(i = 0; i < le; i++)
{
s=*sp;
*sp++=*ep;
*ep--=s;
}
}
static int name_hash(char *name)
{
unsigned int addr = 0;
while(*name)
addr += *name++;
return addr % INSTRUMENT_HASH_SIZE;
}
static Instrument *search_instrument_cache(char *name,
int panning, int amp, int note_to_use,
int strip_loop, int strip_envelope,
int strip_tail)
{
struct InstrumentCache *p;
for(p = instrument_cache[name_hash(name)]; p != NULL; p = p->next)
{
if(strcmp(p->name, name) != 0)
return NULL;
if(p->panning == panning &&
p->amp == amp &&
p->note_to_use == note_to_use &&
p->strip_loop == strip_loop &&
p->strip_envelope == strip_envelope &&
p->strip_tail == strip_tail)
return p->ip;
}
return NULL;
}
static void store_instrument_cache(Instrument *ip,
char *name,
int panning, int amp, int note_to_use,
int strip_loop, int strip_envelope,
int strip_tail)
{
struct InstrumentCache *p;
int addr;
addr = name_hash(name);
p = (struct InstrumentCache *)safe_malloc(sizeof(struct InstrumentCache));
p->next = instrument_cache[addr];
instrument_cache[addr] = p;
p->name = name;
p->panning = panning;
p->amp = amp;
p->note_to_use = note_to_use;
p->strip_loop = strip_loop;
p->strip_envelope = strip_envelope;
p->strip_tail = strip_tail;
p->ip = ip;
}
/*
If panning or note_to_use != -1, it will be used for all samples,
instead of the sample-specific values in the instrument file.
For note_to_use, any value <0 or >127 will be forced to 0.
For other parameters, 1 means yes, 0 means no, other values are
undefined.
TODO: do reverse loops right */
static Instrument *load_gus_instrument(char *name,
ToneBank *bank,
int dr, int prog,
char *infomsg)
{
Instrument *ip;
Sample *sp;
struct timidity_file *tf;
uint8 tmp[1024];
int i,j,noluck=0;
int panning, amp, note_to_use, strip_loop, strip_envelope, strip_tail;
#ifdef PATCH_EXT_LIST
static char *patch_ext[] = PATCH_EXT_LIST;
#endif
if (!name) return 0;
if(infomsg != NULL)
ctl->cmsg(CMSG_INFO, VERB_NOISY, "%s: %s", infomsg, name);
else
ctl->cmsg(CMSG_INFO, VERB_NOISY, "Loading instrument %s", name);
if(bank)
{
ToneBankElement *tone;
tone = &bank->tone[prog];
panning = tone->pan;
amp = tone->amp;
note_to_use = (tone->note != -1) ? tone->note : (dr ? prog : -1);
strip_loop = (tone->strip_loop!=-1) ? tone->strip_loop : (dr ? 1 : -1);
strip_envelope = (tone->strip_envelope != -1) ? tone->strip_envelope : (dr ? 1 : -1);
strip_tail = tone->strip_tail;
}
else
{
panning = amp = note_to_use = -1;
strip_loop = strip_envelope = strip_tail = 0;
}
if((ip = search_instrument_cache(name, panning, amp, note_to_use,
strip_loop, strip_envelope, strip_tail))
!= NULL)
{
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * Cached");
return ip;
}
/* Open patch file */
if (!(tf=open_file(name, 2, OF_NORMAL)))
{
int name_len, ext_len;
noluck=1;
#ifdef PATCH_EXT_LIST
name_len = strlen(name);
/* Try with various extensions */
for (i=0; patch_ext[i]; i++)
{
ext_len = strlen(patch_ext[i]);
if (name_len + ext_len < 1024)
{
if(name_len >= ext_len &&
strcmp(name + name_len - ext_len, patch_ext[i]) == 0)
continue; /* duplicated ext. */
strcpy((char *)tmp, name);
strcat((char *)tmp, patch_ext[i]);
if ((tf=open_file((char *)tmp, 1, OF_NORMAL)))
{
noluck=0;
break;
}
}
}
#endif
}
if (noluck)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"Instrument `%s' can't be found.", name);
return 0;
}
/* Read some headers and do cursory sanity checks. There are loads
of magic offsets. This could be rewritten... */
tmp[0] = tf_getc(tf);
if(tmp[0] == '\0') {
/* for Mac binary */
skip(tf, 127);
tmp[0] = tf_getc(tf);
}
if ((238 != tf_read(tmp + 1, 1, 238, tf)) ||
(memcmp(tmp, "GF1PATCH110\0ID#000002", 22) &&
memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the
differences are */
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: not an instrument", name);
close_file(tf);
return 0;
}
if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers,
0 means 1 */
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"Can't handle patches with %d instruments", tmp[82]);
close_file(tf);
return 0;
}
if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"Can't handle instruments with %d layers", tmp[151]);
close_file(tf);
return 0;
}
ip = (Instrument *)safe_malloc(sizeof(Instrument));
ip->type = INST_GUS;
ip->samples = tmp[198];
ip->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples);
memset(ip->sample, 0, sizeof(Sample) * ip->samples);
for (i=0; isamples; i++)
{
uint8 fractions;
int32 tmplong;
uint16 tmpshort;
uint8 tmpchar;
#define READ_CHAR(thing) \
if (1 != tf_read(&tmpchar, 1, 1, tf)) goto fail; \
thing = tmpchar;
#define READ_SHORT(thing) \
if (1 != tf_read(&tmpshort, 2, 1, tf)) goto fail; \
thing = LE_SHORT(tmpshort);
#define READ_LONG(thing) \
if (1 != tf_read(&tmplong, 4, 1, tf)) goto fail; \
thing = LE_LONG(tmplong);
skip(tf, 7); /* Skip the wave name */
if (1 != tf_read(&fractions, 1, 1, tf))
{
fail:
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Error reading sample %d", i);
for (j=0; jsample[j].data);
free(ip->sample);
free(ip);
close_file(tf);
return 0;
}
sp=&(ip->sample[i]);
sp->low_vel = 0;
sp->high_vel = 127;
READ_LONG(sp->data_length);
READ_LONG(sp->loop_start);
READ_LONG(sp->loop_end);
READ_SHORT(sp->sample_rate);
READ_LONG(sp->low_freq);
READ_LONG(sp->high_freq);
READ_LONG(sp->root_freq);
skip(tf, 2); /* Why have a "root frequency" and then "tuning"?? */
READ_CHAR(tmp[0]);
ctl->cmsg(CMSG_INFO, VERB_DEBUG /* sms _debug*/,
"Rate/Low/Hi/Root = %d/%d/%d/%d",
sp->sample_rate, sp->low_freq, sp->high_freq, sp->root_freq);
if (panning==-1)
{
/* 0x07 and 0x08 are both center panning */
if (tmp[0] <= 7)
sp->panning = 64 + ((tmp[0] - 7) * 63) / 7;
else if (tmp[0] >= 8)
sp->panning = 64 + ((tmp[0] - 8) * 63) / 7;
}
else
sp->panning=(uint8)(panning & 0x7F);
/* envelope, tremolo, and vibrato */
if (18 != tf_read(tmp, 1, 18, tf)) goto fail;
if (!tmp[13] || !tmp[14])
{
sp->tremolo_sweep_increment=
sp->tremolo_phase_increment=sp->tremolo_depth=0;
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * no tremolo");
}
else
{
sp->tremolo_sweep_increment=convert_tremolo_sweep(tmp[12]);
sp->tremolo_phase_increment=convert_tremolo_rate(tmp[13]);
sp->tremolo_depth=tmp[14];
ctl->cmsg(CMSG_INFO, VERB_DEBUG,
" * tremolo: sweep %d, phase %d, depth %d",
sp->tremolo_sweep_increment, sp->tremolo_phase_increment,
sp->tremolo_depth);
}
if (!tmp[16] || !tmp[17])
{
sp->vibrato_sweep_increment=
sp->vibrato_control_ratio=sp->vibrato_depth=0;
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * no vibrato");
}
else
{
sp->vibrato_control_ratio=convert_vibrato_rate(tmp[16]);
sp->vibrato_sweep_increment=
convert_vibrato_sweep(tmp[15], sp->vibrato_control_ratio);
sp->vibrato_depth=tmp[17];
ctl->cmsg(CMSG_INFO, VERB_DEBUG,
" * vibrato: sweep %d, ctl %d, depth %d",
sp->vibrato_sweep_increment, sp->vibrato_control_ratio,
sp->vibrato_depth);
}
READ_CHAR(sp->modes);
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * mode: 0x%02x", sp->modes);
skip(tf, 40); /* skip the useless scale frequency, scale factor
(what's it mean?), and reserved space */
/* Mark this as a fixed-pitch instrument if such a deed is desired. */
if (note_to_use!=-1)
sp->note_to_use=(uint8)(note_to_use);
else
sp->note_to_use=0;
/* seashore.pat in the Midia patch set has no Sustain. I don't
understand why, and fixing it by adding the Sustain flag to
all looped patches probably breaks something else. We do it
anyway. */
if (sp->modes & MODES_LOOPING)
sp->modes |= MODES_SUSTAIN;
/* Strip any loops and envelopes we're permitted to */
if ((strip_loop==1) &&
(sp->modes & (MODES_SUSTAIN | MODES_LOOPING |
MODES_PINGPONG | MODES_REVERSE)))
{
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Removing loop and/or sustain");
sp->modes &=~(MODES_SUSTAIN | MODES_LOOPING |
MODES_PINGPONG | MODES_REVERSE);
}
if (strip_envelope==1)
{
if (sp->modes & MODES_ENVELOPE)
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Removing envelope");
sp->modes &= ~MODES_ENVELOPE;
}
else if (strip_envelope != 0)
{
/* Have to make a guess. */
if (!(sp->modes & (MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE)))
{
/* No loop? Then what's there to sustain? No envelope needed
either... */
sp->modes &= ~(MODES_SUSTAIN|MODES_ENVELOPE);
ctl->cmsg(CMSG_INFO, VERB_DEBUG,
" - No loop, removing sustain and envelope");
}
else if (!memcmp(tmp, "??????", 6) || tmp[11] >= 100)
{
/* Envelope rates all maxed out? Envelope end at a high "offset"?
That's a weird envelope. Take it out. */
sp->modes &= ~MODES_ENVELOPE;
ctl->cmsg(CMSG_INFO, VERB_DEBUG,
" - Weirdness, removing envelope");
}
else if (!(sp->modes & MODES_SUSTAIN))
{
/* No sustain? Then no envelope. I don't know if this is
justified, but patches without sustain usually don't need the
envelope either... at least the Gravis ones. They're mostly
drums. I think. */
sp->modes &= ~MODES_ENVELOPE;
ctl->cmsg(CMSG_INFO, VERB_DEBUG,
" - No sustain, removing envelope");
}
}
for (j=0; j<6; j++)
{
sp->envelope_rate[j]=
convert_envelope_rate(tmp[j]);
sp->envelope_offset[j]=
convert_envelope_offset(tmp[6+j]);
}
/* sms: get envelope times in milliseconds cf. sndfont.c */
{ double cc=((1<<22)*control_ratio*1000.0/play_mode->rate);
double attack, hold, release, decay;
attack = 255.0*cc/sp->envelope_rate[0];
hold = 5.0*cc/sp->envelope_rate[1];
decay = 250.0*cc/sp->envelope_rate[2]; /* approx */
release = 255.0*cc/sp->envelope_rate[3];
ctl->cmsg(CMSG_INFO, VERB_DEBUG,
"attack %lg msec hold %lg decay %lg release %lg",
attack, hold, decay, release);
}
/* sms */
/* this envelope seems to give reverb like effects to most patches */
/* use the same method as soundfont */
if (modify_release){
sp->envelope_offset[3] = to_offset(5);
sp->envelope_rate[3] = calc_rate(255, modify_release);
sp->envelope_offset[4] = to_offset(4);
sp->envelope_rate[4] = to_offset(200);
sp->envelope_offset[5] = to_offset(4);
sp->envelope_rate[5] = to_offset(200);
}
/* Then read the sample data */
sp->data = (sample_t *)safe_malloc(sp->data_length+2);
sp->data_alloced = 1;
if ((j = tf_read(sp->data, 1, sp->data_length, tf)) != sp->data_length)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Too small this patch length: %d < %d", j, sp->data_length);
goto fail;
}
if (!(sp->modes & MODES_16BIT)) /* convert to 16-bit data */
{
int32 i = sp->data_length, j;
uint8 *cp = (uint8 *)sp->data;
uint16 *tmp, *new;
tmp = new = (uint16 *)safe_malloc(sp->data_length*2+2);
for(j = 0; j < i; j++)
tmp[j] = (uint16)(cp[j]) << 8;
cp=(uint8 *)(sp->data);
sp->data = (sample_t *)new;
free(cp);
sp->data_length *= 2;
sp->loop_start *= 2;
sp->loop_end *= 2;
}
#ifndef LITTLE_ENDIAN
else
/* convert to machine byte order */
{
int32 i=sp->data_length/2, j;
int16 *tmp=(int16 *)sp->data,s;
for(j = 0; j < i; j++)
{
s = LE_SHORT(tmp[j]);
tmp[j] = s;
}
}
#endif
if (sp->modes & MODES_UNSIGNED) /* convert to signed data */
{
int32 i=sp->data_length/2;
int16 *tmp=(int16 *)sp->data;
while (i--)
*tmp++ ^= 0x8000;
}
/* Reverse reverse loops and pass them off as normal loops */
if (sp->modes & MODES_REVERSE)
{
int32 t;
/* The GUS apparently plays reverse loops by reversing the
whole sample. We do the same because the GUS does not SUCK. */
ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Reverse loop in %s", name);
reverse_data((int16 *)sp->data, 0, sp->data_length/2);
t=sp->loop_start;
sp->loop_start=sp->data_length - sp->loop_end;
sp->loop_end=sp->data_length - t;
sp->modes &= ~MODES_REVERSE;
sp->modes |= MODES_LOOPING; /* just in case */
}
/* If necessary do some anti-aliasing filtering */
if (antialiasing_allowed)
antialiasing((int16 *)sp->data, sp->data_length / 2,
sp->sample_rate,
play_mode->rate);
#ifdef ADJUST_SAMPLE_VOLUMES
if (amp!=-1)
sp->volume=(double)(amp) / 100.0;
else
{
/* Try to determine a volume scaling factor for the sample.
This is a very crude adjustment, but things sound more
balanced with it. Still, this should be a runtime option. */
int32 i=sp->data_length/2, j;
int32 maxamp=0,a;
int16 *tmp=(int16 *)sp->data;
for(j = 0; j < i; j++)
{
a=tmp[j];
if (a<0) a=-a;
if (a>maxamp)
maxamp=a;
}
sp->volume=32768.0 / (double)(maxamp);
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * volume comp: %f", sp->volume);
}
#else
if (amp!=-1)
sp->volume=(double)(amp) / 100.0;
else
sp->volume=1.0;
#endif
sp->data_length /= 2; /* These are in bytes. Convert into samples. */
sp->loop_start /= 2;
sp->loop_end /= 2;
/* The sample must be padded out by 1 extra sample, so that
round off errors in the offsets used in interpolation will not
cause a "pop" by reading random data beyond data_length */
sp->data[sp->data_length] = sp->data[sp->data_length-1];
/* Then fractional samples */
sp->data_length <<= FRACTION_BITS;
sp->loop_start <<= FRACTION_BITS;
sp->loop_end <<= FRACTION_BITS;
/* Adjust for fractional loop points. This is a guess. Does anyone
know what "fractions" really stands for? */
sp->loop_start |=
(fractions & 0x0F) << (FRACTION_BITS-4);
sp->loop_end |=
((fractions>>4) & 0x0F) << (FRACTION_BITS-4);
/* If this instrument will always be played on the same note,
and it's not looped, we can resample it now. */
if (sp->note_to_use && !(sp->modes & MODES_LOOPING))
pre_resample(sp);
#ifdef LOOKUP_HACK
/* Squash the 16-bit data into 8 bits. */
{
uint8 *gulp,*ulp;
int16 *swp;
int l=sp->data_length >> FRACTION_BITS;
gulp = ulp = (uint8 *)safe_malloc(l + 1);
swp=(int16 *)sp->data;
while(l--)
*ulp++ = (*swp++ >> 8) & 0xFF;
free(sp->data);
sp->data=(sample_t *)gulp;
}
#endif
if (strip_tail==1)
{
/* Let's not really, just say we did. */
ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Stripping tail");
sp->data_length = sp->loop_end;
}
}
close_file(tf);
store_instrument_cache(ip, name, panning, amp, note_to_use,
strip_loop, strip_envelope, strip_tail);
return ip;
}
Instrument *load_instrument(int dr, int b, int prog)
{
ToneBank *bank=((dr) ? drumset[b] : tonebank[b]);
Instrument *ip;
char infomsg[256];
int font_bank, font_preset, font_keynote;
if(bank->tone[prog].instype == 1)
{
/* Font extention */
font_bank = bank->tone[prog].font_bank;
font_preset = bank->tone[prog].font_preset;
font_keynote = bank->tone[prog].note;
ip = extract_soundfont(bank->tone[prog].name,
font_bank, font_preset, font_keynote);
if(ip != NULL && bank->tone[prog].amp != -1)
{
int i;
for(i = 0; i < ip->samples; i++)
ip->sample[i].volume = bank->tone[prog].amp / 100.0;
}
if (ip != NULL) {
int i;
i = (dr ? 0 : prog);
if (bank->tone[i].comment)
free(bank->tone[i].comment);
bank->tone[i].comment = safe_strdup(ip->instname);
}
return ip;
}
if(dr)
{
font_bank = 128;
font_preset = b;
font_keynote = prog;
}
else
{
font_bank = b;
font_preset = prog;
font_keynote = -1;
}
/* preload soundfont */
ip = load_soundfont_inst(0, font_bank, font_preset, font_keynote);
if (ip != NULL) {
if (bank->tone[prog].comment)
free(bank->tone[prog].comment);
bank->tone[prog].comment = safe_strdup(ip->instname);
}
if(ip == NULL)
{
/* load GUS/patch file */
if(dr)
sprintf(infomsg, "Drumset %d %d(%s)", b + progbase, prog,
note_name[prog % 12]);
else
sprintf(infomsg, "Tonebank %d %d", b, prog + progbase);
ip = load_gus_instrument(bank->tone[prog].name, bank, dr, prog,
infomsg);
if(ip == NULL) { /* no patch; search soundfont again */
ip = load_soundfont_inst(1, font_bank, font_preset, font_keynote);
if (ip != NULL) {
if (bank->tone[0].comment)
free(bank->tone[0].comment);
bank->tone[0].comment = safe_strdup(ip->instname);
}
}
}
return ip;
}
static int fill_bank(int dr, int b, int *rc)
{
int i, errors = 0;
ToneBank *bank=((dr) ? drumset[b] : tonebank[b]);
if(rc != NULL)
*rc = RC_NONE;
for(i = 0; i < 128; i++)
{
if(bank->tone[i].instrument == MAGIC_LOAD_INSTRUMENT)
{
if(!(bank->tone[i].name))
{
bank->tone[i].instrument = load_instrument(dr, b, i);
if(bank->tone[i].instrument == NULL)
{
ctl->cmsg(CMSG_WARNING,
(b != 0) ? VERB_VERBOSE : VERB_NORMAL,
"No instrument mapped to %s %d, program %d%s",
dr ? "drum set" : "tone bank",
dr ? b+progbase : b,
dr ? i : i+progbase,
(b != 0) ? "" :
" - this instrument will not be heard");
if(b != 0)
{
/* Mark the corresponding instrument in the default
bank / drumset for loading (if it isn't already) */
if(!dr)
{
if(!(standard_tonebank.tone[i].instrument))
standard_tonebank.tone[i].instrument =
MAGIC_LOAD_INSTRUMENT;
}
else
{
if(!(standard_drumset.tone[i].instrument))
standard_drumset.tone[i].instrument =
MAGIC_LOAD_INSTRUMENT;
}
bank->tone[i].instrument = 0;
}
else
bank->tone[i].instrument = MAGIC_ERROR_INSTRUMENT;
errors++;
}
}
else
{
if(rc != NULL)
{
*rc = check_apply_control();
if(RC_IS_SKIP_FILE(*rc))
return errors;
}
bank->tone[i].instrument = load_instrument(dr, b, i);
if(!bank->tone[i].instrument)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"Couldn't load instrument %s "
"(%s %d, program %d)", bank->tone[i].name,
dr ? "drum set" : "tone bank",
dr ? b+progbase : b,
dr ? i : i+progbase);
errors++;
}
}
}
}
return errors;
}
int load_missing_instruments(int *rc)
{
int i=128,errors=0;
if(rc != NULL)
*rc = RC_NONE;
while (i--)
{
if (tonebank[i])
errors+=fill_bank(0,i,rc);
if(rc != NULL && RC_IS_SKIP_FILE(*rc))
return errors;
if (drumset[i])
errors+=fill_bank(1,i,rc);
if(rc != NULL && RC_IS_SKIP_FILE(*rc))
return errors;
}
return errors;
}
void free_instruments(int reload_default_inst)
{
int i=128, j;
struct InstrumentCache *p;
ToneBank *bank;
Instrument *ip;
struct InstrumentCache *default_entry;
int default_entry_addr;
clear_magic_instruments();
/* Free soundfont instruments */
while(i--)
{
/* Note that bank[*]->tone[j].instrument may pointer to
bank[0]->tone[j].instrument. See play_midi_load_instrument()
at playmidi.c for the implementation */
if((bank = tonebank[i]) != NULL)
for(j = 127; j >= 0; j--)
{
ip = bank->tone[j].instrument;
if(ip != NULL && ip->type == INST_SF2 &&
(i == 0 || ip != tonebank[0]->tone[j].instrument))
free_instrument(ip);
bank->tone[j].instrument = NULL;
}
if((bank = drumset[i]) != NULL)
for(j = 127; j >= 0; j--)
{
ip = bank->tone[j].instrument;
if(ip != NULL && ip->type == INST_SF2 &&
(i == 0 || ip != drumset[0]->tone[j].instrument))
free_instrument(ip);
bank->tone[j].instrument = NULL;
}
}
/* Free GUS/patch instruments */
default_entry = NULL;
default_entry_addr = 0;
for(i = 0; i < INSTRUMENT_HASH_SIZE; i++)
{
p = instrument_cache[i];
while(p != NULL)
{
if(!reload_default_inst && p->ip == default_instrument)
{
default_entry = p;
default_entry_addr = i;
p = p->next;
}
else
{
struct InstrumentCache *tmp;
tmp = p;
p = p->next;
free_instrument(tmp->ip);
free(tmp);
}
}
instrument_cache[i] = NULL;
}
if(reload_default_inst)
set_default_instrument(NULL);
else if(default_entry)
{
default_entry->next = NULL;
instrument_cache[default_entry_addr] = default_entry;
}
}
void free_special_patch(int id)
{
int i, j, start, end;
if(id >= 0)
start = end = id;
else
{
start = 0;
end = NSPECIAL_PATCH - 1;
}
for(i = start; i <= end; i++)
if(special_patch[i] != NULL)
{
Sample *sp;
int n;
if(special_patch[i]->name != NULL)
free(special_patch[i]->name);
n = special_patch[i]->samples;
sp = special_patch[i]->sample;
if(sp)
{
for(j = 0; j < n; j++)
if(sp[j].data_alloced && sp[j].data)
free(sp[j].data);
free(sp);
}
free(special_patch[i]);
special_patch[i] = NULL;
}
}
int set_default_instrument(char *name)
{
Instrument *ip;
int i;
static char *last_name;
if(name == NULL)
{
name = last_name;
if(name == NULL)
return 0;
}
if(!(ip = load_gus_instrument(name, NULL, 0, 0, NULL)))
return -1;
if(default_instrument)
free_instrument(default_instrument);
default_instrument = ip;
for(i = 0; i < MAX_CHANNELS; i++)
default_program[i] = SPECIAL_PROGRAM;
last_name = name;
return 0;
}
void alloc_instrument_bank(int dr, int bk)
{
ToneBank *b;
if(dr)
{
if((b = drumset[bk]) == NULL)
{
b = drumset[bk] = (ToneBank *)safe_malloc(sizeof(ToneBank));
memset(b, 0, sizeof(ToneBank));
}
}
else
{
if((b = tonebank[bk]) == NULL)
{
b = tonebank[bk] = (ToneBank *)safe_malloc(sizeof(ToneBank));
memset(b, 0, sizeof(ToneBank));
}
}
}
/* Instrument alias map - Written by Masanao Izumo */
int instrument_map(int mapID, int *set, int *elem)
{
int s, e;
struct inst_map_elem *p;
if(mapID == INST_NO_MAP)
return 0; /* No map */
s = *set;
e = *elem;
p = inst_map_table[mapID][s];
if(p != NULL)
{
*set = p[e].set;
*elem = p[e].elem;
return 1;
}
if(s != 0)
{
p = inst_map_table[mapID][0];
if(p != NULL)
{
*set = p[e].set;
*elem = p[e].elem;
}
return 2;
}
return 0;
}
void set_instrument_map(int mapID,
int set_from, int elem_from,
int set_to, int elem_to)
{
struct inst_map_elem *p;
p = inst_map_table[mapID][set_from];
if(p == NULL)
{
p = (struct inst_map_elem *)
safe_malloc(128 * sizeof(struct inst_map_elem));
memset(p, 0, 128 * sizeof(struct inst_map_elem));
inst_map_table[mapID][set_from] = p;
}
p[elem_from].set = set_to;
p[elem_from].elem = elem_to;
}
void free_instrument_map(void)
{
int i, j, k;
for (i = 0; i < NUM_INST_MAP; i++) {
for (j = 0; j < 128; j++) {
struct inst_map_elem *map;
map = inst_map_table[i][j];
if (map) {
free(map);
inst_map_table[i][j] = NULL;
}
}
}
}
/* Alternate assign - Written by Masanao Izumo */
AlternateAssign *add_altassign_string(AlternateAssign *old,
char **params, int n)
{
int i, j;
char *p;
int beg, end;
AlternateAssign *alt;
if(n == 0)
return old;
if(!strcmp(*params, "clear")) {
while(old) {
AlternateAssign *next;
next = old->next;
free(old);
old = next;
}
params++;
n--;
if(n == 0)
return NULL;
}
alt = (AlternateAssign *)safe_malloc(sizeof(AlternateAssign));
memset(alt, 0, sizeof(AlternateAssign));
for(i = 0; i < n; i++) {
p = params[i];
if(*p == '-') {
beg = 0;
p++;
} else
beg = atoi(p);
if((p = strchr(p, '-')) != NULL) {
if(p[1] == '\0')
end = 127;
else
end = atoi(p + 1);
} else
end = beg;
if(beg > end) {
int t;
t = beg;
beg = end;
end = t;
}
if(beg < 0)
beg = 0;
if(end > 127)
end = 127;
for(j = beg; j <= end; j++)
alt->bits[(j >> 5) & 0x3] |= 1 << (j & 0x1F);
}
alt->next = old;
return alt;
}
AlternateAssign *find_altassign(AlternateAssign *altassign, int note)
{
AlternateAssign *p;
uint32 mask;
int idx;
mask = 1 << (note & 0x1F);
idx = (note >> 5) & 0x3;
for(p = altassign; p != NULL; p = p->next)
if(p->bits[idx] & mask)
return p;
return NULL;
}