Skip to content
Merged
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ TARGET_INCLUDE_DIRECTORIES(libwildmidi-static INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# Consumers of the static archive need libm (pow/log10 etc.)
IF (M_LIBRARY)
TARGET_LINK_LIBRARIES(libwildmidi-static INTERFACE ${M_LIBRARY})
ENDIF()

# If the static library was not requested, we do not add it to the "all" & "install" targets
IF (WANT_STATIC)
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;

/* Don't retroactively grow approx_total_samples: current_sample is
already at (or very near) the parse-time total by the time EOT
fires, so extending would make the reported percentage regress.
samples_to_mix keeps the tail rendering (see the `+= samples_to_next`
in the GetOutput event loops); the player caps its display at 100. */

return;
}

Expand Down
2 changes: 2 additions & 0 deletions src/player/wildmidi.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,7 @@ int main(int argc, char **argv) {
wm_info = WildMidi_GetInfo(midi_ptr);
perc_play = (wm_info->current_sample * 100)
/ wm_info->approx_total_samples;
if (perc_play > 100) perc_play = 100;
pro_mins = wm_info->current_sample / (rate * 60);
pro_secs = (wm_info->current_sample % (rate * 60)) / rate;
fprintf(stderr,
Expand Down Expand Up @@ -813,6 +814,7 @@ int main(int argc, char **argv) {

perc_play = (wm_info->current_sample * 100)
/ wm_info->approx_total_samples;
if (perc_play > 100) perc_play = 100;
pro_mins = wm_info->current_sample / (rate * 60);
pro_secs = (wm_info->current_sample % (rate * 60)) / rate;
fprintf(stderr,
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