parameters. These seem to be used primarily to restrict percussion

instruments to specific notes.
- Changed note velocity to not use the volume curve in recompute_amp(), since
  this sounds closer to TiMidity++, although I don't believe it's correct
  MIDI behavior. Also changed expression so that it scales the channel volume
  before going through the curve.
- Reworked load_instrument to be less opaque.
- Went through the TiMidity code and removed pretty much all of the SDL_mixer
  extensions. The only exception would be kill_others(), which I reworked
  into a kill_key_group() function, which should be useful for DLS
  instruments in the future.


SVN r918 (trunk)
This commit is contained in:
Randy Heit 2008-04-16 05:41:03 +00:00
parent 52eeff6db8
commit 9450db3cec
8 changed files with 789 additions and 1959 deletions

View file

@ -1,3 +1,17 @@
April 15, 2008
- Added support for the GUS patch format's scale_frequency and scale_factor
parameters. These seem to be used primarily to restrict percussion
instruments to specific notes.
- Changed note velocity to not use the volume curve in recompute_amp(), since
this sounds closer to TiMidity++, although I don't believe it's correct
MIDI behavior. Also changed expression so that it scales the channel volume
before going through the curve.
- Reworked load_instrument to be less opaque.
- Went through the TiMidity code and removed pretty much all of the SDL_mixer
extensions. The only exception would be kill_others(), which I reworked
into a kill_key_group() function, which should be useful for DLS
instruments in the future.
April 15, 2008 (Changes by Graf Zahl) April 15, 2008 (Changes by Graf Zahl)
- Added translation support to multipatch textures. Not tested yet! - Added translation support to multipatch textures. Not tested yet!
- Added Martin Howe's morph weapon update. - Added Martin Howe's morph weapon update.

File diff suppressed because it is too large Load diff

View file

@ -1121,29 +1121,29 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
DLS_Region *rgn = &ins->regions[index]; DLS_Region *rgn = &ins->regions[index];
DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex]; DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex];
if (!(rgn->header->fusOptions & F_RGN_OPTION_SELFNONEXCLUSIVE)) sample->self_nonexclusive = !!(rgn->header->fusOptions & F_RGN_OPTION_SELFNONEXCLUSIVE);
{ sample->key_group = (SBYTE)rgn->header->usKeyGroup;
sample->exclusiveClass = (SBYTE)rgn->header->usKeyGroup;
}
sample->low_freq = SDWORD(note_to_freq(rgn->header->RangeKey.usLow)); sample->low_freq = SDWORD(note_to_freq(rgn->header->RangeKey.usLow));
sample->high_freq = SDWORD(note_to_freq(rgn->header->RangeKey.usHigh)); sample->high_freq = SDWORD(note_to_freq(rgn->header->RangeKey.usHigh));
sample->root_freq = SDWORD(note_to_freq(rgn->wsmp->usUnityNote)); sample->root_freq = SDWORD(note_to_freq(rgn->wsmp->usUnityNote));
sample->low_vel = rgn->header->RangeVelocity.usLow; sample->low_vel = rgn->header->RangeVelocity.usLow;
sample->high_vel = rgn->header->RangeVelocity.usHigh; sample->high_vel = rgn->header->RangeVelocity.usHigh;
sample->modes = wave->format->wBitsPerSample == 8 ? MODES_UNSIGNED : MODES_16BIT; sample->modes = wave->format->wBitsPerSample == 8 ? PATCH_UNSIGNED : PATCH_16;
sample->sample_rate = wave->format->dwSamplesPerSec; sample->sample_rate = wave->format->dwSamplesPerSec;
sample->data = NULL; sample->data = NULL;
sample->data_length = wave->length; sample->data_length = wave->length;
convert_sample_data(sample, wave->data); convert_sample_data(sample, wave->data);
if (rgn->wsmp->cSampleLoops) { if (rgn->wsmp->cSampleLoops)
sample->modes |= (MODES_LOOPING|MODES_SUSTAIN); {
sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN);
sample->loop_start = rgn->wsmp_loop->ulStart / 2; sample->loop_start = rgn->wsmp_loop->ulStart / 2;
sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2); sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2);
} }
sample->volume = 1.0f; sample->volume = 1.0f;
if (sample->modes & MODES_SUSTAIN) { if (sample->modes & PATCH_SUSTAIN)
{
int value; int value;
double attack, hold, decay, release; int sustain; double attack, hold, decay, release; int sustain;
CONNECTIONLIST *art = NULL; CONNECTIONLIST *art = NULL;
@ -1192,12 +1192,7 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
sample->envelope_offset[RELEASEC] = to_offset(0); sample->envelope_offset[RELEASEC] = to_offset(0);
sample->envelope_rate[RELEASEC] = to_offset(1); sample->envelope_rate[RELEASEC] = to_offset(1);
sample->modes |= MODES_ENVELOPE; sample->modes |= PATCH_NO_SRELEASE;
}
for (int j = ATTACK; j < DELAY; j++)
{
sample->modulation_rate[j] = float(sample->envelope_rate[j]);
sample->modulation_offset[j] = float(sample->envelope_offset[j]);
} }
sample->data_length <<= FRACTION_BITS; sample->data_length <<= FRACTION_BITS;
@ -1205,55 +1200,54 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
sample->loop_end <<= FRACTION_BITS; sample->loop_end <<= FRACTION_BITS;
} }
InstrumentLayer *load_instrument_dls(Renderer *song, int drum, int bank, int instrument) Instrument *load_instrument_dls(Renderer *song, int drum, int bank, int instrument)
{ {
InstrumentLayer *layer; Instrument *inst;
DWORD i; DWORD i;
DLS_Instrument *dls_ins = NULL; DLS_Instrument *dls_ins = NULL;
if (song->patches == NULL) if (song->patches == NULL)
{
return NULL; return NULL;
}
drum = drum ? 0x80000000 : 0; drum = drum ? 0x80000000 : 0;
for (i = 0; i < song->patches->cInstruments; ++i) { for (i = 0; i < song->patches->cInstruments; ++i)
{
dls_ins = &song->patches->instruments[i]; dls_ins = &song->patches->instruments[i];
if ((dls_ins->header->Locale.ulBank & 0x80000000) == (ULONG)drum && if ((dls_ins->header->Locale.ulBank & 0x80000000) == (ULONG)drum &&
((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == (ULONG)bank && ((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == (ULONG)bank &&
dls_ins->header->Locale.ulInstrument == (ULONG)instrument) dls_ins->header->Locale.ulInstrument == (ULONG)instrument)
break; break;
} }
if (i == song->patches->cInstruments && !bank) { if (i == song->patches->cInstruments && bank == 0)
for (i = 0; i < song->patches->cInstruments; ++i) { {
for (i = 0; i < song->patches->cInstruments; ++i)
{
dls_ins = &song->patches->instruments[i]; dls_ins = &song->patches->instruments[i];
if ((dls_ins->header->Locale.ulBank & 0x80000000) == (ULONG)drum && if ((dls_ins->header->Locale.ulBank & 0x80000000) == (ULONG)drum &&
dls_ins->header->Locale.ulInstrument == (ULONG)instrument) dls_ins->header->Locale.ulInstrument == (ULONG)instrument)
break; break;
} }
} }
if (i == song->patches->cInstruments) { if (i == song->patches->cInstruments)
{
// SNDDBG(("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank)); // SNDDBG(("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank));
return NULL; return NULL;
} }
layer = (InstrumentLayer *)safe_malloc(sizeof(InstrumentLayer)); inst = (Instrument *)safe_malloc(sizeof(Instrument));
layer->lo = 0; inst->type = INST_DLS;
layer->hi = 127; inst->samples = dls_ins->header->cRegions;
layer->instrument = (Instrument *)safe_malloc(sizeof(Instrument)); inst->sample = (Sample *)safe_malloc(inst->samples * sizeof(Sample));
layer->instrument->type = INST_DLS; memset(inst->sample, 0, inst->samples * sizeof(Sample));
layer->instrument->samples = dls_ins->header->cRegions;
layer->instrument->sample = (Sample *)safe_malloc(layer->instrument->samples * sizeof(Sample));
layer->instrument->left_samples = layer->instrument->samples;
layer->instrument->left_sample = layer->instrument->sample;
layer->instrument->right_samples = 0;
layer->instrument->right_sample = NULL;
memset(layer->instrument->sample, 0, layer->instrument->samples * sizeof(Sample));
/* /*
printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples); printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples);
*/ */
for (i = 0; i < dls_ins->header->cRegions; ++i) { for (i = 0; i < dls_ins->header->cRegions; ++i)
load_region_dls(song, &layer->instrument->sample[i], dls_ins, i); {
load_region_dls(song, &inst->sample[i], dls_ins, i);
} }
return layer; return inst;
} }
#endif /* !TEST_MAIN_DLS */ #endif /* !TEST_MAIN_DLS */

View file

@ -37,15 +37,14 @@ int recompute_envelope(Voice *v)
stage = v->envelope_stage; stage = v->envelope_stage;
if (stage >= DELAY) if (stage > RELEASEC)
{ {
/* Envelope ran out. */ /* Envelope ran out. */
int tmp = (v->status == VOICE_DIE); /* Already displayed as dead */
v->status = VOICE_FREE; v->status = VOICE_FREE;
return 1; return 1;
} }
if (v->sample->modes & MODES_ENVELOPE) if (v->sample->modes & PATCH_NO_SRELEASE)
{ {
if (v->status == VOICE_ON || v->status == VOICE_SUSTAINED) if (v->status == VOICE_ON || v->status == VOICE_SUSTAINED)
{ {
@ -60,7 +59,9 @@ int recompute_envelope(Voice *v)
v->envelope_stage = stage + 1; v->envelope_stage = stage + 1;
if (v->envelope_volume == v->sample->envelope_offset[stage]) if (v->envelope_volume == v->sample->envelope_offset[stage])
{
return recompute_envelope(v); return recompute_envelope(v);
}
v->envelope_target = v->sample->envelope_offset[stage]; v->envelope_target = v->sample->envelope_offset[stage];
v->envelope_increment = v->sample->envelope_rate[stage]; v->envelope_increment = v->sample->envelope_rate[stage];
if (v->envelope_target < v->envelope_volume) if (v->envelope_target < v->envelope_volume)
@ -75,28 +76,30 @@ void apply_envelope_to_amp(Voice *v)
{ {
ramp = v->right_amp; ramp = v->right_amp;
if (v->tremolo_phase_increment) if (v->tremolo_phase_increment != 0)
{ {
lamp *= v->tremolo_volume; lamp *= v->tremolo_volume;
ramp *= v->tremolo_volume; ramp *= v->tremolo_volume;
} }
if (v->sample->modes & MODES_ENVELOPE) if (v->sample->modes & PATCH_NO_SRELEASE)
{ {
double vol = calc_vol(v->envelope_volume / float(1 << 30)); double vol = calc_vol(v->envelope_volume / float(1 << 30));
lamp *= vol; lamp *= vol;
ramp *= vol; ramp *= vol;
} }
v->left_mix = float(lamp); v->left_mix = float(lamp);
v->right_mix = float(ramp); v->right_mix = float(ramp);
} }
else else
{ {
if (v->tremolo_phase_increment) if (v->tremolo_phase_increment != 0)
{
lamp *= v->tremolo_volume; lamp *= v->tremolo_volume;
if (v->sample->modes & MODES_ENVELOPE) }
if (v->sample->modes & PATCH_NO_SRELEASE)
{
lamp *= calc_vol(v->envelope_volume / float(1 << 30)); lamp *= calc_vol(v->envelope_volume / float(1 << 30));
}
v->left_mix = float(lamp); v->left_mix = float(lamp);
} }
} }
@ -104,13 +107,14 @@ void apply_envelope_to_amp(Voice *v)
static int update_envelope(Voice *v) static int update_envelope(Voice *v)
{ {
v->envelope_volume += v->envelope_increment; v->envelope_volume += v->envelope_increment;
/* Why is there no ^^ operator?? */
if (((v->envelope_increment < 0) && (v->envelope_volume <= v->envelope_target)) || if (((v->envelope_increment < 0) && (v->envelope_volume <= v->envelope_target)) ||
((v->envelope_increment > 0) && (v->envelope_volume >= v->envelope_target))) ((v->envelope_increment > 0) && (v->envelope_volume >= v->envelope_target)))
{ {
v->envelope_volume = v->envelope_target; v->envelope_volume = v->envelope_target;
if (recompute_envelope(v)) if (recompute_envelope(v))
{
return 1; return 1;
}
} }
return 0; return 0;
} }
@ -119,7 +123,7 @@ static void update_tremolo(Voice *v)
{ {
int depth = v->sample->tremolo_depth << 7; int depth = v->sample->tremolo_depth << 7;
if (v->tremolo_sweep) if (v->tremolo_sweep != 0)
{ {
/* Update sweep position */ /* Update sweep position */
@ -151,12 +155,14 @@ static void update_tremolo(Voice *v)
/* Returns 1 if the note died */ /* Returns 1 if the note died */
static int update_signal(Voice *v) static int update_signal(Voice *v)
{ {
if (v->envelope_increment && update_envelope(v)) if (v->envelope_increment != 0 && update_envelope(v))
{
return 1; return 1;
}
if (v->tremolo_phase_increment) if (v->tremolo_phase_increment != 0)
{
update_tremolo(v); update_tremolo(v);
}
apply_envelope_to_amp(v); apply_envelope_to_amp(v);
return 0; return 0;
} }

File diff suppressed because it is too large Load diff

View file

@ -215,12 +215,12 @@ static sample_t *rs_bidir(sample_t *resample_buffer, Voice *vp, int count)
/* We only need to compute one half of the vibrato sine cycle */ /* We only need to compute one half of the vibrato sine cycle */
static int vib_phase_to_inc_ptr(int phase) static int vib_phase_to_inc_ptr(int phase)
{ {
if (phase < VIBRATO_SAMPLE_INCREMENTS/2) if (phase < VIBRATO_SAMPLE_INCREMENTS / 2)
return VIBRATO_SAMPLE_INCREMENTS/2-1-phase; return VIBRATO_SAMPLE_INCREMENTS / 2 - 1 - phase;
else if (phase >= 3*VIBRATO_SAMPLE_INCREMENTS/2) else if (phase >= VIBRATO_SAMPLE_INCREMENTS * 3 / 2)
return 5*VIBRATO_SAMPLE_INCREMENTS/2-1-phase; return VIBRATO_SAMPLE_INCREMENTS * 5 / 2 - 1 - phase;
else else
return phase-VIBRATO_SAMPLE_INCREMENTS/2; return phase - VIBRATO_SAMPLE_INCREMENTS / 2;
} }
static int update_vibrato(float output_rate, Voice *vp, int sign) static int update_vibrato(float output_rate, Voice *vp, int sign)
@ -229,8 +229,8 @@ static int update_vibrato(float output_rate, Voice *vp, int sign)
int phase; int phase;
double a, pb; double a, pb;
if (vp->vibrato_phase++ >= 2*VIBRATO_SAMPLE_INCREMENTS-1) if (vp->vibrato_phase++ >= 2 * VIBRATO_SAMPLE_INCREMENTS - 1)
vp->vibrato_phase=0; vp->vibrato_phase = 0;
phase = vib_phase_to_inc_ptr(vp->vibrato_phase); phase = vib_phase_to_inc_ptr(vp->vibrato_phase);
if (vp->vibrato_sample_increment[phase]) if (vp->vibrato_sample_increment[phase])
@ -244,7 +244,7 @@ static int update_vibrato(float output_rate, Voice *vp, int sign)
/* Need to compute this sample increment. */ /* Need to compute this sample increment. */
depth = vp->sample->vibrato_depth << 7; depth = vp->sample->vibrato_depth << 7;
if (vp->vibrato_sweep) if (vp->vibrato_sweep != 0)
{ {
/* Need to update sweep */ /* Need to update sweep */
vp->vibrato_sweep_position += vp->vibrato_sweep; vp->vibrato_sweep_position += vp->vibrato_sweep;
@ -265,7 +265,7 @@ static int update_vibrato(float output_rate, Voice *vp, int sign)
pb = (sine(vp->vibrato_phase * (1.0/(2*VIBRATO_SAMPLE_INCREMENTS))) pb = (sine(vp->vibrato_phase * (1.0/(2*VIBRATO_SAMPLE_INCREMENTS)))
* (double)(depth) * VIBRATO_AMPLITUDE_TUNING); * (double)(depth) * VIBRATO_AMPLITUDE_TUNING);
a *= pow(2.0, pb / (8191 * 12.f)); a *= pow(2.0, pb / (8192 * 12.f));
/* If the sweep's over, we can store the newly computed sample_increment */ /* If the sweep's over, we can store the newly computed sample_increment */
if (!vp->vibrato_sweep) if (!vp->vibrato_sweep)
@ -511,11 +511,11 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr)
if (vp->vibrato_control_ratio) if (vp->vibrato_control_ratio)
{ {
if ((modes & MODES_LOOPING) && if ((modes & PATCH_LOOPEN) &&
((modes & MODES_ENVELOPE) || ((modes & PATCH_NO_SRELEASE) ||
(vp->status == VOICE_ON || vp->status == VOICE_SUSTAINED))) (vp->status == VOICE_ON || vp->status == VOICE_SUSTAINED)))
{ {
if (modes & MODES_PINGPONG) if (modes & PATCH_BIDIR)
return rs_vib_bidir(song->resample_buffer, song->rate, vp, *countptr); return rs_vib_bidir(song->resample_buffer, song->rate, vp, *countptr);
else else
return rs_vib_loop(song->resample_buffer, song->rate, vp, *countptr); return rs_vib_loop(song->resample_buffer, song->rate, vp, *countptr);
@ -527,11 +527,11 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr)
} }
else else
{ {
if ((modes & MODES_LOOPING) && if ((modes & PATCH_LOOPEN) &&
((modes & MODES_ENVELOPE) || ((modes & PATCH_NO_SRELEASE) ||
(vp->status == VOICE_ON || vp->status == VOICE_SUSTAINED))) (vp->status == VOICE_ON || vp->status == VOICE_SUSTAINED)))
{ {
if (modes & MODES_PINGPONG) if (modes & PATCH_BIDIR)
return rs_bidir(song->resample_buffer, vp, *countptr); return rs_bidir(song->resample_buffer, vp, *countptr);
else else
return rs_loop(song->resample_buffer, vp, *countptr); return rs_loop(song->resample_buffer, vp, *countptr);
@ -554,11 +554,14 @@ void pre_resample(Renderer *song, Sample *sp)
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
}; };
cmsg(CMSG_INFO, VERB_NOISY, " * pre-resampling for note %d (%s%d)", if (sp->scale_factor != 0)
sp->note_to_use, return;
note_name[sp->note_to_use % 12], (sp->note_to_use & 0x7F) / 12);
a = (sp->sample_rate * note_to_freq(sp->note_to_use)) / (sp->root_freq * song->rate); cmsg(CMSG_INFO, VERB_NOISY, " * pre-resampling for note %d (%s%d)\n",
sp->scale_note,
note_name[sp->scale_note % 12], (sp->scale_note & 0x7F) / 12);
a = (sp->sample_rate * note_to_freq(sp->scale_note)) / (sp->root_freq * song->rate);
if (a <= 0) if (a <= 0)
return; return;
newlen = (int)(sp->data_length / a); newlen = (int)(sp->data_length / a);

View file

@ -413,6 +413,13 @@ void FreeAll()
int LoadConfig(const char *filename) int LoadConfig(const char *filename)
{ {
/* !!! FIXME: This may be ugly, but slightly less so than requiring the
* default search path to have only one element. I think.
*
* We only need to include the likely locations for the config
* file itself since that file should contain any other directory
* that needs to be added to the search path.
*/
clear_pathlist(); clear_pathlist();
#ifdef _WIN32 #ifdef _WIN32
add_to_pathlist("C:\\TIMIDITY"); add_to_pathlist("C:\\TIMIDITY");
@ -443,25 +450,21 @@ Renderer::Renderer(float sample_rate)
{ {
rate = sample_rate; rate = sample_rate;
patches = NULL; patches = NULL;
default_instrument = NULL;
#ifdef FAST_DECAY
fast_decay = true;
#else
fast_decay = false;
#endif
resample_buffer_size = 0; resample_buffer_size = 0;
resample_buffer = NULL; resample_buffer = NULL;
adjust_panning_immediately = false;
control_ratio = clamp(int(rate / CONTROLS_PER_SECOND), 1, MAX_CONTROL_RATIO); control_ratio = clamp(int(rate / CONTROLS_PER_SECOND), 1, MAX_CONTROL_RATIO);
lost_notes = 0;
cut_notes = 0;
default_instrument = NULL;
default_program = DEFAULT_PROGRAM;
if (def_instr_name.IsNotEmpty()) if (def_instr_name.IsNotEmpty())
set_default_instrument(def_instr_name); set_default_instrument(def_instr_name);
voices = DEFAULT_VOICES; voices = DEFAULT_VOICES;
memset(voice, 0, sizeof(voice));
memset(drumvolume, 0, sizeof(drumvolume));
memset(drumpanpot, 0, sizeof(drumpanpot));
memset(drumreverberation, 0, sizeof(drumreverberation));
memset(drumchorusdepth, 0, sizeof(drumchorusdepth));
drumchannels = DEFAULT_DRUMCHANNELS; drumchannels = DEFAULT_DRUMCHANNELS;
} }
@ -492,22 +495,7 @@ void Renderer::ComputeOutput(float *buffer, int count)
{ {
if (v->status != VOICE_FREE) if (v->status != VOICE_FREE)
{ {
if (v->sample_offset == 0 && v->echo_delay_count) mix_voice(this, buffer, v, count);
{
if (v->echo_delay_count >= count)
{
v->echo_delay_count -= count;
}
else
{
mix_voice(this, buffer + v->echo_delay_count, v, count - v->echo_delay_count);
v->echo_delay_count = 0;
}
}
else
{
mix_voice(this, buffer, v, count);
}
} }
} }
} }
@ -520,6 +508,11 @@ void Renderer::MarkInstrument(int banknum, int percussion, int instr)
{ {
return; return;
} }
if (banknum != 0)
{
/* Mark the standard bank in case it's not defined by this one. */
MarkInstrument(0, percussion, instr);
}
if (percussion) if (percussion)
{ {
bank = drumset[banknum]; bank = drumset[banknum];
@ -532,9 +525,9 @@ void Renderer::MarkInstrument(int banknum, int percussion, int instr)
{ {
return; return;
} }
if (bank->tone[instr].layer == NULL) if (bank->instrument[instr] == NULL)
{ {
bank->tone[instr].layer = MAGIC_LOAD_INSTRUMENT; bank->instrument[instr] = MAGIC_LOAD_INSTRUMENT;
} }
} }
@ -557,9 +550,6 @@ void cmsg(int type, int verbosity_level, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vsprintf(buf, fmt, args); vsprintf(buf, fmt, args);
va_end(args); va_end(args);
size_t l = strlen(buf);
buf[l] = '\n';
buf[l+1] = '\0';
OutputDebugString(buf); OutputDebugString(buf);
#endif #endif
} }

View file

@ -33,33 +33,27 @@ config.h
*/ */
/* Acoustic Grand Piano seems to be the usual default instrument. */ /* Acoustic Grand Piano seems to be the usual default instrument. */
#define DEFAULT_PROGRAM 0 #define DEFAULT_PROGRAM 0
/* 9 here is MIDI channel 10, which is the standard percussion channel. /* 9 here is MIDI channel 10, which is the standard percussion channel.
Some files (notably C:\WINDOWS\CANYON.MID) think that 16 is one too. Some files (notably C:\WINDOWS\CANYON.MID) think that 16 is one too.
On the other hand, some files know that 16 is not a drum channel and On the other hand, some files know that 16 is not a drum channel and
try to play music on it. This is now a runtime option, so this isn't try to play music on it. This is now a runtime option, so this isn't
a critical choice anymore. */ a critical choice anymore. */
#define DEFAULT_DRUMCHANNELS (1<<9) #define DEFAULT_DRUMCHANNELS (1<<9)
/*#define DEFAULT_DRUMCHANNELS ((1<<9) | (1<<15))*/ /*#define DEFAULT_DRUMCHANNELS ((1<<9) | (1<<15))*/
/* Default sampling rate, default polyphony, and maximum polyphony. /* Default polyphony, and maximum polyphony. */
All but the last can be overridden from the command line. */ #define DEFAULT_VOICES 32
#define DEFAULT_RATE 32000 #define MAX_VOICES 256
#define DEFAULT_VOICES 32
#define MAX_VOICES 256 #define MAXCHAN 16
#define MAXCHAN 16 #define MAXNOTE 128
#define MAXNOTE 128
/* 1000 here will give a control ratio of 22:1 with 22 kHz output. /* 1000 here will give a control ratio of 22:1 with 22 kHz output.
Higher CONTROLS_PER_SECOND values allow more accurate rendering Higher CONTROLS_PER_SECOND values allow more accurate rendering
of envelopes and tremolo. The cost is CPU time. */ of envelopes and tremolo. The cost is CPU time. */
#define CONTROLS_PER_SECOND 1000 #define CONTROLS_PER_SECOND 1000
/* Make envelopes twice as fast. Saves ~20% CPU time (notes decay
faster) and sounds more like a GUS. There is now a command line
option to toggle this as well. */
//#define FAST_DECAY
/* How many bits to use for the fractional part of sample positions. /* How many bits to use for the fractional part of sample positions.
This affects tonal accuracy. The entire position counter must fit This affects tonal accuracy. The entire position counter must fit
@ -67,7 +61,7 @@ config.h
a sample is 1048576 samples (2 megabytes in memory). The GUS gets a sample is 1048576 samples (2 megabytes in memory). The GUS gets
by with just 9 bits and a little help from its friends... by with just 9 bits and a little help from its friends...
"The GUS does not SUCK!!!" -- a happy user :) */ "The GUS does not SUCK!!!" -- a happy user :) */
#define FRACTION_BITS 12 #define FRACTION_BITS 12
/* For some reason the sample volume is always set to maximum in all /* For some reason the sample volume is always set to maximum in all
patch files. Define this for a crude adjustment that may help patch files. Define this for a crude adjustment that may help
@ -76,7 +70,7 @@ config.h
/* The number of samples to use for ramping out a dying note. Affects /* The number of samples to use for ramping out a dying note. Affects
click removal. */ click removal. */
#define MAX_DIE_TIME 20 #define MAX_DIE_TIME 20
/**************************************************************************/ /**************************************************************************/
/* Anything below this shouldn't need to be changed unless you're porting /* Anything below this shouldn't need to be changed unless you're porting
@ -84,37 +78,37 @@ config.h
/**************************************************************************/ /**************************************************************************/
/* change FRACTION_BITS above, not these */ /* change FRACTION_BITS above, not these */
#define INTEGER_BITS (32 - FRACTION_BITS) #define INTEGER_BITS (32 - FRACTION_BITS)
#define INTEGER_MASK (0xFFFFFFFF << FRACTION_BITS) #define INTEGER_MASK (0xFFFFFFFF << FRACTION_BITS)
#define FRACTION_MASK (~ INTEGER_MASK) #define FRACTION_MASK (~ INTEGER_MASK)
#define MAX_SAMPLE_SIZE (1 << INTEGER_BITS) #define MAX_SAMPLE_SIZE (1 << INTEGER_BITS)
/* This is enforced by some computations that must fit in an int */ /* This is enforced by some computations that must fit in an int */
#define MAX_CONTROL_RATIO 255 #define MAX_CONTROL_RATIO 255
#define MAX_AMPLIFICATION 800 #define MAX_AMPLIFICATION 800
/* The TiMiditiy configuration file */ /* The TiMiditiy configuration file */
#define CONFIG_FILE "timidity.cfg" #define CONFIG_FILE "timidity.cfg"
typedef float sample_t; typedef float sample_t;
typedef float final_volume_t; typedef float final_volume_t;
#define FINAL_VOLUME(v) (v) #define FINAL_VOLUME(v) (v)
#define FSCALE(a,b) ((a) * (float)(1<<(b))) #define FSCALE(a,b) ((a) * (float)(1<<(b)))
#define FSCALENEG(a,b) ((a) * (1.0L / (float)(1<<(b)))) #define FSCALENEG(a,b) ((a) * (1.0L / (float)(1<<(b))))
/* Vibrato and tremolo Choices of the Day */ /* Vibrato and tremolo Choices of the Day */
#define SWEEP_TUNING 38 #define SWEEP_TUNING 38
#define VIBRATO_AMPLITUDE_TUNING 1.0L #define VIBRATO_AMPLITUDE_TUNING 1.0
#define VIBRATO_RATE_TUNING 38 #define VIBRATO_RATE_TUNING 38
#define TREMOLO_AMPLITUDE_TUNING 1.0L #define TREMOLO_AMPLITUDE_TUNING 1.0
#define TREMOLO_RATE_TUNING 38 #define TREMOLO_RATE_TUNING 38
#define SWEEP_SHIFT 16 #define SWEEP_SHIFT 16
#define RATE_SHIFT 5 #define RATE_SHIFT 5
#define VIBRATO_SAMPLE_INCREMENTS 32 #define VIBRATO_SAMPLE_INCREMENTS 32
#ifndef PI #ifndef PI
#define PI 3.14159265358979323846 #define PI 3.14159265358979323846
@ -188,21 +182,20 @@ FileReader *open_filereader(const char *name, int open, int *plumpnum);
controls.h controls.h
*/ */
#define CMSG_INFO 0 enum
#define CMSG_WARNING 1 {
#define CMSG_ERROR 2 CMSG_INFO,
#define CMSG_FATAL 3 CMSG_WARNING,
#define CMSG_TRACE 4 CMSG_ERROR
#define CMSG_TIME 5 };
#define CMSG_TOTAL 6
#define CMSG_FILE 7
#define CMSG_TEXT 8
#define VERB_NORMAL 0 enum
#define VERB_VERBOSE 1 {
#define VERB_NOISY 2 VERB_NORMAL,
#define VERB_DEBUG 3 VERB_VERBOSE,
#define VERB_DEBUG_SILLY 4 VERB_NOISY,
VERB_DEBUG
};
void cmsg(int type, int verbosity_level, const char *fmt, ...); void cmsg(int type, int verbosity_level, const char *fmt, ...);
@ -217,114 +210,174 @@ struct Sample
loop_start, loop_end, data_length, loop_start, loop_end, data_length,
sample_rate, low_vel, high_vel, low_freq, high_freq, root_freq; sample_rate, low_vel, high_vel, low_freq, high_freq, root_freq;
SDWORD SDWORD
envelope_rate[7], envelope_offset[7]; envelope_rate[6], envelope_offset[6];
float float
modulation_rate[7], modulation_offset[7]; volume;
float
volume, resonance,
modEnvToFilterFc, modEnvToPitch, modLfoToFilterFc;
sample_t *data; sample_t *data;
SDWORD SDWORD
tremolo_sweep_increment, tremolo_phase_increment, tremolo_sweep_increment, tremolo_phase_increment,
lfo_sweep_increment, lfo_phase_increment, vibrato_sweep_increment, vibrato_control_ratio;
vibrato_sweep_increment, vibrato_control_ratio,
cutoff_freq;
BYTE BYTE
reverberation, chorusdepth,
tremolo_depth, vibrato_depth, tremolo_depth, vibrato_depth,
modes, modes;
attenuation;
WORD WORD
freq_center, panning; panning, scale_factor;
SBYTE
note_to_use, exclusiveClass;
SWORD SWORD
keyToModEnvHold, keyToModEnvDecay, scale_note;
keyToVolEnvHold, keyToVolEnvDecay; bool
SDWORD self_nonexclusive;
freq_scale; BYTE
key_group;
}; };
void convert_sample_data(Sample *sample, const void *data); void convert_sample_data(Sample *sample, const void *data);
void free_instruments(); void free_instruments();
/* Bits in modes: */ /* Patch definition: */
#define MODES_16BIT (1<<0) enum
#define MODES_UNSIGNED (1<<1) {
#define MODES_LOOPING (1<<2) HEADER_SIZE = 12,
#define MODES_PINGPONG (1<<3) ID_SIZE = 10,
#define MODES_REVERSE (1<<4) DESC_SIZE = 60,
#define MODES_SUSTAIN (1<<5) RESERVED_SIZE = 40,
#define MODES_ENVELOPE (1<<6) PATCH_HEADER_RESERVED_SIZE = 36,
#define MODES_FAST_RELEASE (1<<7) LAYER_RESERVED_SIZE = 40,
PATCH_DATA_RESERVED_SIZE = 36,
INST_NAME_SIZE = 16,
ENVELOPES = 6,
MAX_LAYERS = 4
};
#define GF1_HEADER_TEXT "GF1PATCH110"
#define INST_GUS 0 enum
#define INST_SF2 1 {
#define INST_DLS 2 PATCH_16 = (1<<0),
PATCH_UNSIGNED = (1<<1),
PATCH_LOOPEN = (1<<2),
PATCH_BIDIR = (1<<3),
PATCH_BACKWARD = (1<<4),
PATCH_SUSTAIN = (1<<5),
PATCH_NO_SRELEASE = (1<<6),
PATCH_FAST_REL = (1<<7)
};
#ifdef _MSC_VER
#pragma pack(push, 1)
#define GCC_PACKED
#else
#define GCC_PACKED __attribute__((__packed__))
#endif
struct GF1PatchHeader
{
char Header[HEADER_SIZE];
char GravisID[ID_SIZE]; /* Id = "ID#000002" */
char Description[DESC_SIZE];
BYTE Instruments;
BYTE Voices;
BYTE Channels;
WORD WaveForms;
WORD MasterVolume;
DWORD DataSize;
BYTE Reserved[PATCH_HEADER_RESERVED_SIZE];
} GCC_PACKED;
struct GF1InstrumentData
{
WORD Instrument;
char InstrumentName[INST_NAME_SIZE];
int InstrumentSize;
BYTE Layers;
BYTE Reserved[RESERVED_SIZE];
} GCC_PACKED;
struct GF1LayerData
{
BYTE LayerDuplicate;
BYTE Layer;
int LayerSize;
BYTE Samples;
BYTE Reserved[LAYER_RESERVED_SIZE];
} GCC_PACKED;
struct GF1PatchData
{
char WaveName[7];
BYTE Fractions;
int WaveSize;
int StartLoop;
int EndLoop;
WORD SampleRate;
int LowFrequency;
int HighFrequency;
int RootFrequency;
SWORD Tune;
BYTE Balance;
BYTE EnvelopeRate[6];
BYTE EnvelopeOffset[6];
BYTE TremoloSweep;
BYTE TremoloRate;
BYTE TremoloDepth;
BYTE VibratoSweep;
BYTE VibratoRate;
BYTE VibratoDepth;
BYTE Modes;
SWORD ScaleFrequency;
WORD ScaleFactor; /* From 0 to 2048 or 0 to 2 */
BYTE Reserved[PATCH_DATA_RESERVED_SIZE];
} GCC_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
#undef GCC_PACKED
enum
{
INST_GUS,
INST_DLS
};
struct Instrument struct Instrument
{ {
Instrument();
~Instrument();
int type; int type;
int samples; int samples;
Sample *sample; Sample *sample;
int left_samples;
Sample *left_sample;
int right_samples;
Sample *right_sample;
}; };
struct InstrumentLayer
{
BYTE lo, hi;
Instrument *instrument;
InstrumentLayer *next;
};
struct cfg_type
{
int font_code;
int num;
const char *name;
};
#define FONT_NORMAL 0
#define FONT_FFF 1
#define FONT_SBK 2
#define FONT_TONESET 3
#define FONT_DRUMSET 4
#define FONT_PRESET 5
struct ToneBankElement struct ToneBankElement
{ {
ToneBankElement() : layer(NULL), font_type(0), sf_ix(0), tuning(0), ToneBankElement() :
note(0), amp(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0) note(0), amp(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0)
{} {}
FString name; FString name;
InstrumentLayer *layer;
int font_type, sf_ix, tuning;
int note, amp, pan, strip_loop, strip_envelope, strip_tail; int note, amp, pan, strip_loop, strip_envelope, strip_tail;
}; };
/* A hack to delay instrument loading until after reading the /* A hack to delay instrument loading until after reading the
entire MIDI file. */ entire MIDI file. */
#define MAGIC_LOAD_INSTRUMENT ((InstrumentLayer *)(-1)) #define MAGIC_LOAD_INSTRUMENT ((Instrument *)(-1))
#define MAXPROG 128 enum
#define MAXBANK 130 {
#define SFXBANK (MAXBANK-1) MAXPROG = 128,
#define SFXDRUM1 (MAXBANK-2) MAXBANK = 128
#define SFXDRUM2 (MAXBANK-1) };
#define XGDRUM 1
struct ToneBank struct ToneBank
{ {
FString name; ToneBank();
ToneBankElement tone[MAXPROG]; ~ToneBank();
ToneBankElement *tone;
Instrument *instrument[MAXPROG];
}; };
#define SPECIAL_PROGRAM -1 #define SPECIAL_PROGRAM -1
extern void pcmap(int *b, int *v, int *p, int *drums); extern void pcmap(int *b, int *v, int *p, int *drums);
@ -341,60 +394,55 @@ playmidi.h
*/ */
/* Midi events */ /* Midi events */
#define ME_NOTEOFF 0x80 enum
#define ME_NOTEON 0x90 {
#define ME_KEYPRESSURE 0xA0 ME_NOTEOFF = 0x80,
#define ME_CONTROLCHANGE 0xB0 ME_NOTEON = 0x90,
#define ME_PROGRAM 0xC0 ME_KEYPRESSURE = 0xA0,
#define ME_CHANNELPRESSURE 0xD0 ME_CONTROLCHANGE = 0xB0,
#define ME_PITCHWHEEL 0xE0 ME_PROGRAM = 0xC0,
ME_CHANNELPRESSURE = 0xD0,
ME_PITCHWHEEL = 0xE0
};
/* Controllers */ /* Controllers */
#define CTRL_BANK_SELECT 0 enum
#define CTRL_DATA_ENTRY 6 {
#define CTRL_VOLUME 7 CTRL_BANK_SELECT = 0,
#define CTRL_PAN 10 CTRL_DATA_ENTRY = 6,
#define CTRL_EXPRESSION 11 CTRL_VOLUME = 7,
#define CTRL_SUSTAIN 64 CTRL_PAN = 10,
#define CTRL_HARMONICCONTENT 71 CTRL_EXPRESSION = 11,
#define CTRL_RELEASETIME 72 CTRL_SUSTAIN = 64,
#define CTRL_ATTACKTIME 73 CTRL_HARMONICCONTENT = 71,
#define CTRL_BRIGHTNESS 74 CTRL_RELEASETIME = 72,
#define CTRL_REVERBERATION 91 CTRL_ATTACKTIME = 73,
#define CTRL_CHORUSDEPTH 93 CTRL_BRIGHTNESS = 74,
#define CTRL_NRPN_LSB 98 CTRL_REVERBERATION = 91,
#define CTRL_NRPN_MSB 99 CTRL_CHORUSDEPTH = 93,
#define CTRL_RPN_LSB 100 CTRL_NRPN_LSB = 98,
#define CTRL_RPN_MSB 101 CTRL_NRPN_MSB = 99,
#define CTRL_ALL_SOUNDS_OFF 120 CTRL_RPN_LSB = 100,
#define CTRL_RESET_CONTROLLERS 121 CTRL_RPN_MSB = 101,
#define CTRL_ALL_NOTES_OFF 123 CTRL_ALL_SOUNDS_OFF = 120,
CTRL_RESET_CONTROLLERS = 121,
/* NRPNs */ CTRL_ALL_NOTES_OFF = 123
#define NRPN_BRIGHTNESS 0x00A0 };
#define NRPN_HARMONICCONTENT 0x00A1
#define NRPN_DRUMVOLUME (26<<7) // drum number in low 7 bits
#define NRPN_DRUMPANPOT (28<<7) // "
#define NRPN_DRUMREVERBERATION (29<<7) // "
#define NRPN_DRUMCHORUSDEPTH (30<<7) // "
/* RPNs */ /* RPNs */
#define RPN_PITCH_SENS 0x0000 enum
#define RPN_FINE_TUNING 0x0001 {
#define RPN_COARSE_TUNING 0x0002 RPN_PITCH_SENS = 0x0000,
#define RPN_RESET 0x3fff RPN_FINE_TUNING = 0x0001,
RPN_COARSE_TUNING = 0x0002,
#define SFX_BANKTYPE 64 RPN_RESET = 0x3fff
};
struct Channel struct Channel
{ {
int int
bank, program, sustain, pitchbend, bank, program, sustain, pitchbend,
mono, /* one note only on this channel -- not implemented yet */ mono, /* one note only on this channel -- not implemented yet */
/* new stuff */
variationbank, reverberation, chorusdepth, harmoniccontent,
releasetime, attacktime, brightness, kit, sfx,
/* end new */
pitchsens; pitchsens;
WORD WORD
volume, expression; volume, expression;
@ -404,84 +452,71 @@ struct Channel
rpn, nrpn; rpn, nrpn;
bool bool
nrpn_mode; nrpn_mode;
char
transpose;
float float
pitchfactor; /* precomputed pitch bend factor to save some fdiv's */ pitchfactor; /* precomputed pitch bend factor to save some fdiv's */
}; };
/* Causes the instrument's default panning to be used. */ /* Causes the instrument's default panning to be used. */
#define NO_PANNING -1 #define NO_PANNING -1
/* envelope points */ /* envelope points */
#define MAXPOINT 7 #define MAXPOINT 6
struct Voice struct Voice
{ {
BYTE BYTE
status, channel, note, velocity, clone_type; status, channel, note, velocity;
Sample *sample; Sample *sample;
Sample *left_sample;
Sample *right_sample;
int clone_voice;
float float
orig_frequency, frequency; orig_frequency, frequency;
int int
sample_offset, loop_start, loop_end; sample_offset, sample_increment,
int envelope_volume, envelope_target, envelope_increment,
envelope_volume, modulation_volume; tremolo_sweep, tremolo_sweep_position,
int tremolo_phase, tremolo_phase_increment,
envelope_target, modulation_target; vibrato_sweep, vibrato_sweep_position;
int
tremolo_sweep, tremolo_sweep_position, tremolo_phase,
lfo_sweep, lfo_sweep_position, lfo_phase,
vibrato_sweep, vibrato_sweep_position, vibrato_depth,
echo_delay_count;
int
echo_delay,
sample_increment,
envelope_increment,
modulation_increment,
tremolo_phase_increment,
lfo_phase_increment;
final_volume_t left_mix, right_mix; final_volume_t left_mix, right_mix;
float float
left_amp, right_amp, left_amp, right_amp, tremolo_volume;
volume, tremolo_volume, lfo_volume;
int int
vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS]; vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS];
int
envelope_rate[MAXPOINT], envelope_offset[MAXPOINT];
int int
vibrato_phase, vibrato_control_ratio, vibrato_control_counter, vibrato_phase, vibrato_control_ratio, vibrato_control_counter,
envelope_stage, modulation_stage, control_counter, envelope_stage, control_counter, panning, panned;
modulation_delay, modulation_counter, panning, panned;
}; };
/* Voice status options: */ /* Voice status options: */
#define VOICE_FREE 0 enum
#define VOICE_ON 1 {
#define VOICE_SUSTAINED 2 VOICE_FREE,
#define VOICE_OFF 3 VOICE_ON,
#define VOICE_DIE 4 VOICE_SUSTAINED,
VOICE_OFF,
VOICE_DIE
};
/* Voice panned options: */ /* Voice panned options: */
#define PANNED_MYSTERY 0 enum
#define PANNED_LEFT 1 {
#define PANNED_RIGHT 2 PANNED_MYSTERY,
#define PANNED_CENTER 3 PANNED_LEFT,
PANNED_RIGHT,
PANNED_CENTER
};
/* Anything but PANNED_MYSTERY only uses the left volume */ /* Anything but PANNED_MYSTERY only uses the left volume */
/* Envelope stages: */ /* Envelope stages: */
#define ATTACK 0 enum
#define HOLD 1 {
#define DECAY 2 ATTACK,
#define RELEASE 3 HOLD,
#define RELEASEB 4 DECAY,
#define RELEASEC 5 RELEASE,
#define DELAY 6 RELEASEB,
RELEASEC
};
#define ISDRUMCHANNEL(c) ((drumchannels & (1<<(c)))) #define ISDRUMCHANNEL(c) ((drumchannels & (1<<(c))))
@ -498,9 +533,7 @@ tables.h
#define sine(x) (sin((2*PI/1024.0) * (x))) #define sine(x) (sin((2*PI/1024.0) * (x)))
#define note_to_freq(x) (float(8175.7989473096690661233836992789 * pow(2.0, (x) / 12.0))) #define note_to_freq(x) (float(8175.7989473096690661233836992789 * pow(2.0, (x) / 12.0)))
#define calc_vol(x) (pow(2.0,((x)*6.0 - 6.0))) #define calc_vol(x) (pow(2.0,((x)*6.0 - 6.0)))
#define XMAPMAX 800
/* /*
timidity.h timidity.h
@ -517,27 +550,16 @@ struct Renderer
{ {
float rate; float rate;
DLS_Data *patches; DLS_Data *patches;
InstrumentLayer *default_instrument; Instrument *default_instrument;
int default_program; int default_program;
bool fast_decay;
int resample_buffer_size; int resample_buffer_size;
sample_t *resample_buffer; sample_t *resample_buffer;
Channel channel[16]; Channel channel[16];
Voice voice[MAX_VOICES]; Voice voice[MAX_VOICES];
signed char drumvolume[MAXCHAN][MAXNOTE];
signed char drumpanpot[MAXCHAN][MAXNOTE];
signed char drumreverberation[MAXCHAN][MAXNOTE];
signed char drumchorusdepth[MAXCHAN][MAXNOTE];
int control_ratio, amp_with_poly; int control_ratio, amp_with_poly;
int drumchannels; int drumchannels;
int adjust_panning_immediately; int adjust_panning_immediately;
int voices; int voices;
int GM_System_On;
int XG_System_On;
int GS_System_On;
int XG_System_reverb_type;
int XG_System_chorus_type;
int XG_System_variation_type;
int lost_notes, cut_notes; int lost_notes, cut_notes;
Renderer(float sample_rate); Renderer(float sample_rate);
@ -558,10 +580,8 @@ struct Renderer
int convert_vibrato_rate(BYTE rate); int convert_vibrato_rate(BYTE rate);
void recompute_amp(Voice *v); void recompute_amp(Voice *v);
int vc_alloc(int not_this_voice); void kill_key_group(int voice);
void kill_others(int voice); float calculate_scaled_frequency(Sample *sample, int note);
void clone_voice(Instrument *ip, int v, int note, int vel, int clone_type, int variationbank);
void xremap(int *banknumpt, int *this_notept, int this_kit);
void start_note(int chan, int note, int vel, int voice); void start_note(int chan, int note, int vel, int voice);
void note_on(int chan, int note, int vel); void note_on(int chan, int note, int vel);
@ -579,7 +599,6 @@ struct Renderer
void reset_midi(); void reset_midi();
void select_sample(int voice, Instrument *instr, int vel); void select_sample(int voice, Instrument *instr, int vel);
void select_stereo_samples(int voice, InstrumentLayer *layer, int vel);
void recompute_freq(int voice); void recompute_freq(int voice);
void kill_note(int voice); void kill_note(int voice);