mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-24 13:11:33 +00:00
Fix Timidity's DLS instrument loading:
- Envelope data needed to be converted to SF2 values. - Fine tuning was ignored which made pretty much every instrument off tune. - Despite this, it still sounds like shit compared to FMOD or Microsoft's wavetable synth. There are lots of missing notes and some instruments are still off tune. I'm not sure it's worth trying to salvage it. It'd probably be better to scrap it, since Timidity is very much oriented toward GF1 patches, which it handles perfectly fine.
This commit is contained in:
parent
d234a6af5d
commit
f9574a98fd
4 changed files with 52 additions and 27 deletions
|
@ -1126,7 +1126,7 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
|
|||
sample->key_group = (SBYTE)rgn->header->usKeyGroup;
|
||||
sample->low_freq = note_to_freq(rgn->header->RangeKey.usLow);
|
||||
sample->high_freq = note_to_freq(rgn->header->RangeKey.usHigh);
|
||||
sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote);
|
||||
sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote + rgn->wsmp->sFineTune * .01f);
|
||||
sample->low_vel = (BYTE)rgn->header->RangeVelocity.usLow;
|
||||
sample->high_vel = (BYTE)rgn->header->RangeVelocity.usHigh;
|
||||
|
||||
|
@ -1137,15 +1137,17 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
|
|||
convert_sample_data(sample, wave->data);
|
||||
if (rgn->wsmp->cSampleLoops)
|
||||
{
|
||||
sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN);
|
||||
sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN/* | PATCH_NO_SRELEASE*/);
|
||||
sample->loop_start = rgn->wsmp_loop->ulStart / 2;
|
||||
sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2);
|
||||
}
|
||||
sample->scale_factor = 1024;
|
||||
sample->scale_note = rgn->wsmp->usUnityNote;
|
||||
|
||||
if (sample->modes & PATCH_SUSTAIN)
|
||||
{
|
||||
int value;
|
||||
double attack, hold, decay, release; int sustain;
|
||||
int attack, hold, decay, release; int sustain;
|
||||
CONNECTIONLIST *art = NULL;
|
||||
CONNECTION *artList = NULL;
|
||||
|
||||
|
@ -1157,16 +1159,11 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
|
|||
artList = rgn->artList;
|
||||
}
|
||||
|
||||
value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME);
|
||||
attack = to_msec(value);
|
||||
value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME);
|
||||
hold = to_msec(value);
|
||||
value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME);
|
||||
decay = to_msec(value);
|
||||
value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME);
|
||||
release = to_msec(value);
|
||||
value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL);
|
||||
sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0);
|
||||
attack = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME);
|
||||
hold = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME);
|
||||
decay = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME);
|
||||
release = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME);
|
||||
sustain = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL);
|
||||
value = load_connection(art->cConnections, artList, CONN_DST_PAN);
|
||||
sample->panning = (int)((0.5 + to_normalized_percent(value)) * 16383.f);
|
||||
|
||||
|
@ -1174,12 +1171,12 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
|
|||
printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release);
|
||||
*/
|
||||
|
||||
sample->envelope.sf2.decay_vol = 0;
|
||||
sample->envelope.sf2.attack_vol = (short)attack;
|
||||
sample->envelope.sf2.hold_vol = (short)hold;
|
||||
sample->envelope.sf2.decay_vol = (short)decay;
|
||||
sample->envelope.sf2.release_vol = (short)release;
|
||||
sample->envelope.sf2.sustain_vol = (short)sustain;
|
||||
sample->envelope.sf2.delay_vol = -32768;
|
||||
sample->envelope.sf2.attack_vol = (short)(attack >> 16);
|
||||
sample->envelope.sf2.hold_vol = (short)(hold >> 16);
|
||||
sample->envelope.sf2.decay_vol = (short)(decay >> 16);
|
||||
sample->envelope.sf2.release_vol = (short)(release >> 16);
|
||||
sample->envelope.sf2.sustain_vol = (short)(sustain >> 16);
|
||||
}
|
||||
|
||||
sample->data_length <<= FRACTION_BITS;
|
||||
|
|
|
@ -231,6 +231,10 @@ bool SF2Envelope::Update(Voice *v)
|
|||
double sec;
|
||||
double newvolume = 0;
|
||||
|
||||
// NOTE! The volume scale is different for different stages of the
|
||||
// envelope generator:
|
||||
// Attack stage goes from 0.0 -> 1.0, multiplied directly to the output.
|
||||
// The following stages go from 0 -> -1000 cB (but recorded positively)
|
||||
switch (stage)
|
||||
{
|
||||
case SF2_DELAY:
|
||||
|
@ -333,6 +337,11 @@ bool SF2Envelope::Update(Voice *v)
|
|||
#define FLUID_ATTEN_POWER_FACTOR (-531.509)
|
||||
#define atten2amp(x) pow(10.0, (x) / FLUID_ATTEN_POWER_FACTOR)
|
||||
|
||||
static double cb_to_amp(double x) // centibels to amp
|
||||
{
|
||||
return pow(10, x / -200.f);
|
||||
}
|
||||
|
||||
void SF2Envelope::ApplyToAmp(Voice *v)
|
||||
{
|
||||
double amp;
|
||||
|
@ -343,13 +352,21 @@ void SF2Envelope::ApplyToAmp(Voice *v)
|
|||
v->right_mix = 0;
|
||||
return;
|
||||
}
|
||||
else if (stage == SF2_ATTACK)
|
||||
|
||||
amp = v->sample->type == INST_SF2 ? atten2amp(v->attenuation) : cb_to_amp(v->attenuation);
|
||||
|
||||
switch (stage)
|
||||
{
|
||||
amp = atten2amp(v->attenuation) * volume;
|
||||
}
|
||||
else
|
||||
{
|
||||
amp = atten2amp(v->attenuation) * cb_to_amp(volume);
|
||||
case SF2_ATTACK:
|
||||
amp *= volume;
|
||||
break;
|
||||
|
||||
case SF2_HOLD:
|
||||
break;
|
||||
|
||||
default:
|
||||
amp *= cb_to_amp(volume);
|
||||
break;
|
||||
}
|
||||
amp *= FINAL_MIX_SCALE * 0.5;
|
||||
v->left_mix = float(amp * v->left_offset);
|
||||
|
|
|
@ -678,6 +678,9 @@ int LoadDMXGUS()
|
|||
return 0;
|
||||
}
|
||||
|
||||
DLS_Data *LoadDLS(FILE *src);
|
||||
void FreeDLS(DLS_Data *data);
|
||||
|
||||
Renderer::Renderer(float sample_rate, const char *args)
|
||||
{
|
||||
// 'args' should be used to load a custom config or DMXGUS, but since setup currently requires a snd_reset call, this will need some refactoring first
|
||||
|
@ -701,6 +704,11 @@ Renderer::Renderer(float sample_rate, const char *args)
|
|||
voices = MAX(*midi_voices, 16);
|
||||
voice = new Voice[voices];
|
||||
drumchannels = DEFAULT_DRUMCHANNELS;
|
||||
#if 0
|
||||
FILE *f = fopen("c:\\windows\\system32\\drivers\\gm.dls", "rb");
|
||||
patches = LoadDLS(f);
|
||||
fclose(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
|
@ -713,6 +721,10 @@ Renderer::~Renderer()
|
|||
{
|
||||
delete[] voice;
|
||||
}
|
||||
if (patches != NULL)
|
||||
{
|
||||
FreeDLS(patches);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::ComputeOutput(float *buffer, int count)
|
||||
|
|
|
@ -445,7 +445,7 @@ struct Channel
|
|||
|
||||
struct MinEnvelope
|
||||
{
|
||||
int stage;
|
||||
BYTE stage;
|
||||
BYTE bUpdating;
|
||||
};
|
||||
|
||||
|
@ -599,7 +599,6 @@ const double log_of_2 = 0.69314718055994529;
|
|||
#define freq_to_note(x) (log((x) / 8175.7989473096690661233836992789) * (12.0 / log_of_2))
|
||||
|
||||
#define calc_gf1_amp(x) (pow(2.0,((x)*16.0 - 16.0))) // Actual GUS equation
|
||||
#define cb_to_amp(x) (pow(10.0, (x) * (1 / -200.0))) // centibels to amp
|
||||
|
||||
/*
|
||||
timidity.h
|
||||
|
|
Loading…
Reference in a new issue