Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions docs/man/man1/wildmidi.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH wildmidi 1 "21 November 2020" "" "WildMidi Player"
.TH wildmidi 1 "12 July 2026" "" "WildMidi Player"
.SH NAME
wildmidi \- example player for libWildMidi
.PP
Expand All @@ -9,7 +9,7 @@ wildmidi \- example player for libWildMidi
.B /etc/wildmidi/wildmidi.cfg
.PP
.SH SYNOPSIS
.B wildmidi [\-bhlvwnst] [\-c \fIconfig\-file\fB] [\-d \fIaudiodev\fB] [\-m \fIvolume\-level\fB] [\-P \fIplayback\-output\fB] [\-o \fIfile\fB] [\-f \fIfrequency\-Hz(MUS)\fB] [\-r \fIsample-rate\fB] [\-g \fIconvert-xmi-type\fB] \fImidifile ...
.B wildmidi [\-0abehlnstvO] [\-c \fIconfig\-file\fB] [\-d \fIaudiodev\fB] [\-m \fIvolume\-level\fB] [\-P \fIplayback\-output\fB] [\-o \fIfile\fB] [\-f \fIfrequency\-Hz(MUS)\fB] [\-r \fIsample-rate\fB] [\-g \fIconvert-xmi-type\fB] [\-x \fIfile\fB] [\-i \fIseconds\fB] [\-j \fIseconds\fB] \fImidifile ...
.PP
.SH DESCRIPTION
This is a demonstration program to show the capabilities of libWildMidi.
Expand All @@ -19,11 +19,17 @@ This is a demonstration program to show the capabilities of libWildMidi.
You can have more than one \fImidifile\fP on the command line and \fBwildmidi\fP will pass them to libWildMidi for processing, one after the other. You can also use wildcards, for example: \fBwildmidi *.mid\fP
.PP
.SH OPTIONS
.IP "\fB\-0\fP"
When converting with \fB\-x\fP, save files detected as type 2 MIDI compatible as type 0 files.
.PP
.IP "\fB\-a\fP | \fB\-\-textaslyric\fP"
Some files store their lyrics in text meta events. Read lyrics from there instead of lyric meta events.
.PP
.IP "\fB\-b\fP | \fB\-\-reverb\fP"
Turns on an 8 point reverb engine that adds depth to the final mix.
.P
.IP "\fB\-c\fP \fIconfig\-file\fP | \fB\-\-config\fP \fIconfig\-file\fP"
Uses the configuration file stated by \fIconfig\-file\fP instead of /etc/wildmidi/wildmidi.cfg
Uses the configuration file stated by \fIconfig\-file\fP instead of /etc/wildmidi/wildmidi.cfg. \fIconfig\-file\fP may also be a SoundFont2 (.sf2) file, or a timidity.cfg style file using the \fBsoundfont\fP directive; the file type is detected by content, not extension.
.PP
.IP "\fB\-d\fP \fIaudiodev\fP | \fB\-\-device=\fIaudiodev\fP"
Send audio to \fIaudiodev\fP instead of the default device.
Expand All @@ -32,6 +38,9 @@ Send audio to \fIaudiodev\fP instead of the default device.
netbsd : defaults to "/dev/audio"
Other environments do not support this option.
.PP
.IP "\fB\-e\fP | \fB\-\-enhanced\fP"
Use enhanced (Gauss) resampling for a richer sound at the cost of extra CPU usage.
.PP
.IP "\fB\-h\fP | \fB\-\-help\fP"
Displays command line options.
.PP
Expand All @@ -43,6 +52,12 @@ Convert XMI: 0 - No Conversion (default)
1 - MT32 to GM
2 - MT32 to GS
.PP
.IP "\fB\-i\fP \fIseconds\fP | \fB\-\-playfrom=\fIseconds\fP"
Begin playback at \fIseconds\fP (fractions allowed) into the file.
.PP
.IP "\fB\-j\fP \fIseconds\fP | \fB\-\-playto=\fIseconds\fP"
Stop playback at \fIseconds\fP (fractions allowed) into the file.
.PP
.IP "\fB\-l\fP | \fB\-\-log_vol\fP"
Some MIDI files have been recorded on hardware that uses a volume curve, making them sound really badly mixed on other MIDI devices. Use this option to use volume curves.
.PP
Expand All @@ -55,6 +70,9 @@ Set \fIplayback\-output\fP as playback output. See \fB\--help\fP output for avai
.IP "\fB\-o\fP \fIfile\fP | \fB\-\-wavout=\fIfile\fP"
Records output to a signed 16 bit stereo format \fIwav file\fP. Implies: \fB\-P wave\fP
.PP
.IP "\fB\-O\fP | \fB\-\-opl3\fP"
Use the built\-in OPL3 FM synthesizer. No configuration file, GUS patch set or SoundFont is needed.
.PP
.IP "\fB\-r\fP \fIsndrate\fP | \fB\-\-rate=\fIsndrate\fP"
Set the audio output rate to \fIsndrate\fP. The default rate is 32072.
.PP
Expand All @@ -67,8 +85,8 @@ Skips any silence at the start of playback.
.IP "\fB\-v\fP | \fB\-\-version\fP"
Display version and copyright information.
.PP
.IP "\fB\-x\fP | \fB\-\-tomidi\fP"
Convert a MUS, XMI, HMP or HMI file to midi and save to file.
.IP "\fB\-x\fP \fIfile\fP | \fB\-\-tomidi=\fIfile\fP"
Convert a MUS, XMI, HMP or HMI file to midi and save it as \fIfile\fP.
.PP
.SH TEST OPTIONS
These options are not designed for general use. Instead these options are designed to make it easier to listen to specific sound samples.
Expand Down Expand Up @@ -128,7 +146,7 @@ Chris Ison <chrisisonwildcode@gmail.com>
Bret Curtis <psi29a@gmail.com>
.PP
.SH COPYRIGHT
Copyright (C) WildMidi Developers 2001\-2024
Copyright (C) WildMidi Developers 2001\-2026
.PP
This file is part of WildMIDI.
.PP
Expand Down
6 changes: 3 additions & 3 deletions docs/man/man3/WildMidi_Init.3
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH WildMidi_Init 3 "10 March 2016" "" "WildMidi Programmer's Manual"
.TH WildMidi_Init 3 "12 July 2026" "" "WildMidi Programmer's Manual"
.SH NAME
WildMidi_Init \- Initialize the library
.PP
Expand All @@ -14,7 +14,7 @@ WildMidi_Init \- Initialize the library
Initializes libWildMidi in preparation for playback. This function only needs to be called once by the program using libWildMidi.
.PP
.IP \fIconfig-file\fP
The file that contains the instrument configuration for the library.
The file that contains the instrument configuration for the library. This may be a Gravis Ultrasound patch configuration (see \fBwildmidi.cfg\fP(5)), a SoundFont2 (.sf2) file, or a timidity.cfg style file naming a SoundFont via the \fBsoundfont\fP directive; the file type is detected by content, not extension. Passing the string \fB"@opl3"\fP selects the built\-in OPL3 FM synthesizer, which needs no configuration file at all.
.PP
.IP \fIrate\fP
The sound rate you want the the audio data output at. Rates accepted by libWildMidi are 11025 \- 65000.
Expand Down Expand Up @@ -58,7 +58,7 @@ Chris Ison <chrisisonwildcode@gmail.com>
Bret Curtis <psi29a@gmail.com>
.PP
.SH COPYRIGHT
Copyright (C) WildMidi Developers 2001\-2016
Copyright (C) WildMidi Developers 2001\-2026
.PP
This file is part of WildMIDI.
.PP
Expand Down
19 changes: 14 additions & 5 deletions docs/man/man5/wildmidi.cfg.5
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH wildmidi.cfg 5 "10 March 2016" "" "WildMidi Config File"
.TH wildmidi.cfg 5 "12 July 2026" "" "WildMidi Config File"
.SH NAME
wildmidi.cfg \- Config file for libWildMidi
.PP
Expand All @@ -8,6 +8,8 @@ wildmidi.cfg \- Config file for libWildMidi
.SH DESCRIPTION
Contains the patch configuration for libWildMidi and location of Gravis Ultrasound compatible patch files.
.PP
Instead of a patch configuration, the file given to libWildMidi may also be a SoundFont2 (.sf2) file, or a timidity.cfg style file that names one via the \fBsoundfont\fP directive. The file type is detected by content, not by extension.
.PP
.nf
dir ~/guspats/

Expand All @@ -24,9 +26,7 @@ drumset 0
.PP
.SH SYNTAX
.IP "\fBguspat_editor_author_cant_read_so_fix_release_time_for_me\fP"
Some patch file editors switch the 4th and 5th envelopes around making the sound play much longer than intended in players that stuck to the Gravis Ultrasound patch standard. Including this option in the config enables a fix that detects this oversight, playing the sound samples as if they were correct.
.IP
NOTE: This is a global setting. If it is found to affect good patch samples it will be moved to a per patch setting in a future version.
Some patch file editors switch the 4th and 5th envelopes around making the sound play much longer than intended in players that stuck to the Gravis Ultrasound patch standard. A fix that detects this oversight is applied automatically since WildMidi 0.4.3; this option is accepted for backwards compatibility and has no effect.
.PP
.IP "\fBauto_amp\fP"
Forces WildMIDI to amplify samples to their maximum level ignoring the amp=% in the patch lines of the config.
Expand All @@ -40,6 +40,9 @@ Change the search path for config and patch files to \fIdir\-name\fP. This is sp
.IP "\fBsource\fP \fIinclude\-confg\fP"
Include the settings from \fIinclude\-config\fP. Any patch already set will be over\-ridden by the included config file.
.PP
.IP "\fBsoundfont\fP \fIsf2\-file\fP"
Render using the SoundFont2 file \fIsf2\-file\fP instead of Gravis Ultrasound patches. Relative paths are resolved against the config file directory, the same as \fBsource\fP. This allows an existing timidity.cfg that names a SoundFont to be used as\-is.
.PP
.IP "\fBbank\fP \fIN\fP"
The patches following this setting belong to MIDI instrument bank \fIN\fP.
.PP
Expand Down Expand Up @@ -98,6 +101,12 @@ Set the room length for the reverb engine in meters. \fIfval\fP is a float value
.IP
Example: set room length to 40 meters \- \fBreverb_room_length 40\fP
.PP
.IP "\fBreverb_listener_posx\fP \fIfval\fP"
Set the listener position across the room width for the reverb engine. \fIfval\fP is a float value in meters between 0.0 and \fBreverb_room_width\fP; values outside the room reset to the room centre. Default is half the room width.
.PP
.IP "\fBreverb_listener_posy\fP \fIfval\fP"
Set the listener position along the room length for the reverb engine. \fIfval\fP is a float value in meters between 0.0 and \fBreverb_room_length\fP; values outside the room reset to 3/4 of the room length. Default is 3/4 of the room length.
.PP

.SH SEE ALSO
.BR wildmidi (1)
Expand All @@ -108,7 +117,7 @@ Bret Curtis <psi29a@gmail.com>
.PP
.SH COPYRIGHT
Copyright (C) Chris Ison 2001\-2010
Copyright (C) Bret Curtis 2013\-2016
Copyright (C) Bret Curtis 2013\-2026
.PP
This file is part of WildMIDI.
.PP
Expand Down
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
Loading
Loading