Skip to content
Merged
1 change: 1 addition & 0 deletions include/internal_midi.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ struct _event {
struct _mdi {
int lock;
uint32_t samples_to_mix;
uint32_t tail_allowance; /* release tail already counted in approx_total_samples */
struct _event *events;
struct _event *current_event;
uint32_t event_count;
Expand Down
74 changes: 39 additions & 35 deletions src/internal_midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -593,17 +593,6 @@ void _WM_do_note_off_extra(struct _note *nte) {

} else if (nte->hold) {
nte->hold |= HOLD_OFF;
#if 0
} else if (nte->modes & SAMPLE_SUSTAIN) {
if (nte->env < 3) {
nte->env = 3;
if (nte->env_level > nte->sample->env_target[3]) {
nte->env_inc = -nte->sample->env_rate[3];
} else {
nte->env_inc = nte->sample->env_rate[3];
}
}
#endif
} else if (nte->modes & SAMPLE_CLAMPED) {
if (nte->env < 5) {
nte->env = 5;
Expand All @@ -613,12 +602,16 @@ void _WM_do_note_off_extra(struct _note *nte) {
nte->env_inc = nte->sample->env_rate[5];
}
}
} else if (nte->env < 4) {
nte->env = 4;
if (nte->env_level > nte->sample->env_target[4]) {
nte->env_inc = -nte->sample->env_rate[4];
} else if (nte->env < 3) {
/* GUS/timidity release semantics: the envelope resumes at stage 3
on note off (stages 3-5 are the release phases). Entering at 4
skips the release entirely on patches that keep it in stage 3
(issue #229). */
nte->env = 3;
if (nte->env_level > nte->sample->env_target[3]) {
nte->env_inc = -nte->sample->env_rate[3];
} else {
nte->env_inc = nte->sample->env_rate[4];
nte->env_inc = nte->sample->env_rate[3];
}
}
}
Expand Down Expand Up @@ -1047,22 +1040,16 @@ void _WM_do_control_channel_notes_off(struct _mdi *mdi,
if (note_data) {
do {
if ((note_data->noteid >> 8) == ch) {
if (!note_data->hold) {
if (note_data->modes & SAMPLE_ENVELOPE) {
if (note_data->env < 5) {
if (note_data->env_level
> note_data->sample->env_target[5]) {
note_data->env_inc =
-note_data->sample->env_rate[5];
} else {
note_data->env_inc =
note_data->sample->env_rate[5];
}
note_data->env = 5;
}
}
/* All Notes Off releases each note as if a note off was
received (normal release); only All Sound Off (CC 120)
silences immediately. */
if ((note_data->modes & SAMPLE_ENVELOPE)
&& (note_data->env == 0)) {
/* defer release until the initial envelope step has
completed, same as _WM_do_note_off */
note_data->is_off = 1;
} else {
note_data->hold |= HOLD_OFF;
_WM_do_note_off_extra(note_data);
}
}
note_data = note_data->next;
Expand Down Expand Up @@ -1215,21 +1202,32 @@ void _WM_Release_Allowance(struct _mdi *mdi) {
while (note != NULL) {

if (note->modes & SAMPLE_ENVELOPE) {
/* ensure envelope isin a release state */
if (note->env < 4) {
note->env = 4;
/* ensure envelope is in a release state; release starts at
stage 3 (see _WM_do_note_off_extra) */
if (note->env < 3) {
note->env = 3;
}

/* make sure this is set */
note->env_inc = -note->sample->env_rate[note->env];

release = note->env_level / -note->env_inc;

/* a non-looping sample can't ring longer than its
remaining data */
if (!(note->modes & SAMPLE_LOOP) && note->sample_inc) {
uint32_t remaining = (note->sample->data_length
- note->sample_pos) / note->sample_inc;
if (remaining < release) release = remaining;
}
} else {
/* Sample release */
if (note->modes & SAMPLE_LOOP) {
note->modes ^= SAMPLE_LOOP;
}
release = note->sample->data_length - note->sample_pos;
/* data_length/sample_pos are 22.10 fixed point */
release = (note->sample->data_length - note->sample_pos)
/ (note->sample_inc ? note->sample_inc : 1024);
}

if (release > longest_release) longest_release = release;
Expand All @@ -1239,6 +1237,12 @@ void _WM_Release_Allowance(struct _mdi *mdi) {

mdi->samples_to_mix = longest_release;

/* Keep the reported length in sync with the tail we are about to
render. Delta against what was already added so repeated end of
track events (looping, seeks) don't inflate the total. */
mdi->extra_info.approx_total_samples += longest_release - mdi->tail_allowance;
mdi->tail_allowance = longest_release;

return;
}

Expand Down
30 changes: 25 additions & 5 deletions src/wildmidi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ struct _mdi_patches {
#define FPBITS 10
#define FPMASK ((1L<<FPBITS)-1L)

/* GUS envelope level to linear amplitude: 2^((level - 1) * 6), i.e. dB-linear
over a 36 dB range, matching the GF1's exponential volume ramps and
timidity's vol_table. A linear mapping leaves releasing notes ~12 dB too
loud mid-decay. Filled in _WM_Init(). */
static int32_t env_amp_table[1024];
#define ENV_AMP(lvl) (env_amp_table[(lvl) >> 12])


/* Gauss Interpolation code adapted from code supplied by Eric. A. Welsh */
static double newt_coeffs[58][58]; /* for start/end of samples */
Expand Down Expand Up @@ -972,7 +979,9 @@ static int WM_GetOutput_Linear(midi * handle, int8_t *buffer, uint32_t size) {
_WM_ResetToStart(mdi);
event = mdi->current_event;
} else {
mdi->samples_to_mix = event->samples_to_next;
/* += : keep any release allowance set by the
end-of-track event (_WM_Release_Allowance). */
mdi->samples_to_mix += event->samples_to_next;
event++;
mdi->current_event = event;
}
Expand Down Expand Up @@ -1015,7 +1024,7 @@ static int WM_GetOutput_Linear(midi * handle, int8_t *buffer, uint32_t size) {
* ===================
*/
data_pos = note_data->sample_pos >> FPBITS;
premix = ((note_data->sample->data[data_pos] + (((note_data->sample->data[data_pos + 1] - note_data->sample->data[data_pos]) * (int32_t)(note_data->sample_pos & FPMASK)) / 1024)) * (note_data->env_level >> 12)) / 1024;
premix = ((note_data->sample->data[data_pos] + (((note_data->sample->data[data_pos + 1] - note_data->sample->data[data_pos]) * (int32_t)(note_data->sample_pos & FPMASK)) / 1024)) * ENV_AMP(note_data->env_level)) / 1024;

left_mix += (premix * (int32_t)note_data->left_mix_volume) / 1024;
right_mix += (premix * (int32_t)note_data->right_mix_volume) / 1024;
Expand Down Expand Up @@ -1304,7 +1313,9 @@ static int WM_GetOutput_Gauss(midi * handle, int8_t *buffer, uint32_t size) {
_WM_ResetToStart(mdi);
event = mdi->current_event;
} else {
mdi->samples_to_mix = event->samples_to_next;
/* += : keep any release allowance set by the
end-of-track event (_WM_Release_Allowance). */
mdi->samples_to_mix += event->samples_to_next;
event++;
mdi->current_event = event;
}
Expand Down Expand Up @@ -1384,7 +1395,7 @@ static int WM_GetOutput_Gauss(midi * handle, int8_t *buffer, uint32_t size) {
} while (gptr <= gend);
}

premix = (int32_t)((y * (note_data->env_level >> 12)) / 1024);
premix = (int32_t)((y * ENV_AMP(note_data->env_level)) / 1024);

left_mix += (premix * (int32_t)note_data->left_mix_volume) / 1024;
right_mix += (premix * (int32_t)note_data->right_mix_volume) / 1024;
Expand Down Expand Up @@ -1793,6 +1804,13 @@ static int _WM_Init(const struct _WM_VIO *callbacks,
gauss_lock = 0;
_WM_patch_lock = 0;
_WM_MasterVolume = 948;
{
int i;
for (i = 0; i < 1024; i++) {
env_amp_table[i] = (int32_t)(1024.0
* pow(2.0, ((double)i / 1023.0 - 1.0) * 6.0) + 0.5);
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
WM_Initialized = 1;

return (0);
Expand Down Expand Up @@ -2246,7 +2264,9 @@ static int WM_GetOutput_SF2(midi * handle, int8_t *buffer, uint32_t size) {
_WM_ResetToStart(mdi);
event = mdi->current_event;
} else {
mdi->samples_to_mix = event->samples_to_next;
/* += : keep any release allowance set by the
end-of-track event (_WM_Release_Allowance). */
mdi->samples_to_mix += event->samples_to_next;
event++;
mdi->current_event = event;
}
Expand Down
Loading