This is a 32-bit protected mode
for PMI applications
- Optimized 16-bit mixers
- Variable amplification with clipping
- Various sample interpolation methods
- Stereo crossfade for hard panned (Amiga) MODs
- Multichannel support
- Features
- API
- Configure and build
- ProTracker MOD format (
M.K.
,M!K!
,FLT4
) - 8-channel MOD formats (
OCTA
,CD81
) - 1-32 channel MOD formats (
TDZx
,xCHN
,xxCH
) - ProTracker 2.3 effects
- Panning effects
8xx
andE8x
Not supported:
- Sound Tracker modules (15-instrument)
- MOD files without embedded samples
- Some uncommon Amiga-specific playback/ProTracker quirks such as sample swap
- Effects
E0x
(set filter) andEFx
(funk it / invert loop)
- No sound (keeps the player running without actually playing anything)
- PC speaker up to 29 kHz sample rate
- LPT DAC variants (single, dual, stereo) up to 44.1 kHz sample rate
- Sound Blaster, Pro and 16 up to 22/44.1 kHz sample rate (depending on actual model)
- 2 extra octaves above/below standard ProTracker note range.
- Up to 32 channels (can be extended when necessary).
- 16-bit mixing all the way across the mixer chain.
- Variable output amplification between 0.0 - 4.0x.
- All-integer/fixed point mixer code (no FPU required).
- Stereo output (when supported by device) with hard panning (Amiga-style), 75% crossfade or real stereo supporting 8xx and E8x channel pan commands.
- Nearest neighbor / zero order hold interpolation (also referred to as no interpolation, although this is technically incorrect) for Amiga-like sound quality without multiplications in the audio mixer code.
- Fast 8-bit linear interpolation for Gravis Ultrasound-like sound quality without multiplications in the audio mixer code.
- High quality 16-bit trilinear interpolation (Jon Watte algorithm) with only 2 multiplications (4 in real stereo mode) per sample.
The API is defined in src\mod\api\mod.inc
. Most procedures return the carry flag (CF) set if the operation failed along with an error code in EAX. The error code may come from the MOD player itself or from a PMI. Possible error codes from the player are:
value | name | description |
---|---|---|
0x0100 | MOD_ERR_INVALID |
Invalid MOD file format (file corrupted, unsupported or not a MOD file). |
0x0101 | MOD_ERR_DEV_UNK |
Unknown output device or output device type provided. |
0x0102 | MOD_ERR_NB_CHN |
MOD has too many or no channels (possibly corrupted file format). |
0x0103 | MOD_ERR_STATE |
The MOD player cannot process the operation in its current state (eg. mod_load was called before mod_setup .) |
0x0104 | MOD_ERR_DEVICE |
The output device is not responding to the initialization request. |
The bare minimum sequence for MOD playback:
- Call
mod_setup
to initialize the library - Call
mod_load
to load the MOD file - Call
mod_play
to start playback - Call
mod_shutdown
to shutdown the library and stop playback
Link all .obj
files of the MOD library produced by wmake
or wmake build=release
(see chapter on building the library) to the final executable. The library also requires the following runtime library modules from PMI to be linked to the final executable:
env_arg
string
irq
timer
systimer
profiler
ifMOD_USE_PROFILER
is enabled in configurationlog
for the debug builds
For a complex example please refer to tmodplay, a standalone DOS MOD player.
Attempts to detect the presence of a Sound Blaster card by parsing the BLASTER
environment variable.
Inputs:
- EBX: Pointer to
mod_dev_params
structure (seemod_setup
for structure definition).
Outputs:
- CF: Set if a Sound Blaster card was not detected.
- AL: Device type when Sound Blaster was detected (see
MOD_SB_*
constants inmod_setup
). - EBX:
mod_dev_params
structure filled with card-specificport
,irq
anddma
settings.
Initialize the MOD player and selected output device.
Inputs:
AH
: Output device, see output device table constants below.AL
: Output device type, see output device table constants below.EBX
: Pointer tomod_dev_params
structure.CH.CL
: Initial amplification in 8.8 bit fixed point format. Refer tomod_set_amplify
for details.EDX
: Requested output mixing sample rate.
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set) or actual output mixing sample rate.
Supported output devices:
value | output device | device type | description |
---|---|---|---|
0 / 0 | MOD_OUT_NONE |
MOD_NONE |
Keeps the player running without rendering any audio output. |
1 / 0 | MOD_OUT_DAC |
MOD_DAC_SPEAKER |
Mono 5.3 - 6 bit playback on the PC speaker. Maximum sample rate is 29 kHz. Fixed configuration, does not need port , irq or dma configuration in mod_dev_params . |
1 / 1 | MOD_OUT_DAC |
MOD_DAC_LPT |
Mono 8 bit playback on a parallel port D/A converter (Covox). Maximum sample rate is 44.1 kHz. Requires port to be specified in mod_dev_params . |
1 / 2 | MOD_OUT_DAC |
MOD_DAC_LPTST |
Stereo 8 bit playback on a stereo-on-1 parallel port D/A converter. Maximum sample rate is 44.1 kHz. Requires port to be specified in mod_dev_params . |
1 / 3 | MOD_OUT_DAC |
MOD_DAC_LPTDUAL |
Stereo 8 bit playback on two parallel port D/A converters. Maximum sample rate is 44.1 kHz. Requires two I/O ports to be specified in mod_dev_params.port . |
2 / 0 | MOD_OUT_SB |
MOD_SB_1 |
Mono 8 bit playback on original Sound Blaster (no auto-init DMA). Maximum sample rate is 22 kHz. Requires port , irq and dma to be set in mod_dev_params.port . |
2 / 1 | MOD_OUT_SB |
MOD_SB_2 |
Mono 8 bit playback on Sound Blaster 2.0. Maximum sample rate is 44 kHz. Requires port , irq and dma to be set in mod_dev_params.port . |
2 / 2 | MOD_OUT_SB |
MOD_SB_PRO |
Stereo 8 bit playback on Sound Blaster Pro. Maximum sample rate is 22 kHz in stereo or 44 kHz in mono mode. Requires port , irq and dma to be set in mod_dev_params.port . |
2 / 3 | MOD_OUT_SB |
MOD_SB_16 |
Stereo 16 bit playback on Sound Blaster 16. Maximum sample rate is 44.1 kHz. Requires port , irq and both 8-bit and 16-bit DMA channels in dma to be set in mod_dev_params.port . 8-bit and 16-bit dma may contain the same value (some clone cards may not support 16-bit DMA channels, set the 8-bit DMA channel number for the 16-bit DMA entry in this case). |
MOD_OUT_NONE
andMOD_OUT_DAC
use the timer interrupt (IRQ 0) for audio playback or to keep the player running.MOD_OUT_SB
uses the Sound Blaster's IRQ and a 16 or 8-bit DMA channel for audio playback and to keep the player running.- For
MOD_DAC_LPTST
, the strobe and auto linefeed pins are used to select the output channel the following way:- Strobe (pin 1): output on left channel when high
- Auto line feed (pin 14): output on right channel when high
- Essentially the auto line feed pin is low when strobe is high and vice versa.
The mod_dev_params
structure defines additional parameters for the output device:
offset | name | size | description |
---|---|---|---|
0x00 | buffer_size |
4 | Requested size of the output buffer in microseconds. Refer to mod_render on details about how to set the buffer size to keep the MOD player from interrupting your rendering process. |
0x04 | port |
2 x 2 | Base I/O port(s) of the device. |
0x08 | irq |
2 x 1 | IRQ(s) used by the device. |
0x0a | dma |
2 x 1 | 8-bit (low) and 16-bit (high) DMA channels used by the device. |
0x0c | stereo_mode |
1 | Stereo panning mode for stereo output devices. See MOD_PAN_* constants below. |
0x0d | initial_pan |
1 | Set initial panning for real stereo mode. Set to 0x80 to pan all channels to center (mono) on start, 0x0 to hard pan left/right or any value in-between for crossfade panning. Actual panning will be changed by 8xx and E8x MOD effects. |
0x0e | interpolation |
1 | Set the initial interpolation method. See MOD_IPOL_* constants below. |
0x0f | flags |
1 | Player behavior control flags. See MOD_FLG_* constants below. |
The following values are supported for stereo panning mode on stereo output devices:
value | name | description |
---|---|---|
0 | MOD_PAN_MONO |
Force mono output. |
1 | MOD_PAN_HARD |
Pan channels to hard left/right as on the Amiga. True to the original but not very enjoyable unless the MOD was especially crafted for hard panning. MOD_PAN_MONO or MOD_PAN_CROSS usually provide a more enjoyable listening experience for MODs that don't use panning effects. |
2 | MOD_PAN_CROSS |
Pan channels to hard left/right and apply a 75% amplitude cross-mixing between channels. This is a nice compromise that adds some fake sense of space to the music with only minimal CPU overhead. |
3 | MOD_PAN_REAL |
Pan channels according to 8xx and E8x effects in the MOD file. Channels are initially panned as specified in mod_dev_params.initial_pan . This uses significantly more CPU than the others (around 1.4x compared to hard panning). |
When mono playback is requested:
MOD_DAC_LPTST
andMOD_DAC_LPTDUAL
will output the same sample on both channels/DACs.MOD_SB_PRO
andMOD_SB_16
are setup for mono playback.
The following values are available to select the interpolation method:
value | name | description |
---|---|---|
0 | MOD_IPOL_NN |
Nearest neighbor or zero-order hold or incorrectly also known as no interpolation. This method sustains the sample value until the next one and produces horrible aliasing artifacts. However, several MOD files - especially older ones with lower quality samples - rely on these artifacts and will sound dull with better interpolation methods. |
1 | MOD_IPOL_LINEAR |
Fast 8-bit linear interpolation. This method generates samples in-between by using a simple weighted average. It is similar to the mixing quality of the Gravis Ultrasound, although that has 16-bit interpolation which reduces the noise level. It is a big step forward in quality that leaves some of the artifacts of nearest neighbor interpolation so that even old MODs can remain somewhat enjoyable. It uses about 2x CPU as nearest neighbor on a Pentium MMX. |
2 | MOD_IPOL_WATTE |
High quality 16-bit trilinear interpolation implementing Jon Watte's algorithm from Olli Niemitalo's "Polynomial Interpolators for High-Quality Resampling of Oversampled Audio" paper (deip.pdf). It does an excellent job to cut off aliasing artifacts while also preserving most frequencies at the passband, but can render MODs with low quality samples completely unenjoyable. It uses about 3.7x CPU as nearest neighbor on a Pentium MMX. |
The following flags are available for controlling player behavior:
value | name | description |
---|---|---|
0x01 | MOD_FLG_FMT_CHG |
Enable on-the-fly bitstream format change during playback. This allows switching between mono and stereo output on devices where this results in a device reinitialization. The player will allocate a stereo output/render buffer for stereo output devices even when mono output is forced using MOD_PAN_MONO . |
0x02 | MOD_FLG_SR_CHG |
Enable on-the-fly sample rate changes during playback. The player will allocate an output/render buffer that is large enough to contain samples up to the highest supported sample rate of the device. |
These flags are for advanced player usage by standalone players. For normal embedded usage as a background music player in your application you usually don't need to set any of them.
Shuts down the MOD playback system. Any pending playback is terminated and the sound device is deinitialized.
Inputs:
None.
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set).
Load a MOD file from disk to memory.
Inputs:
EBX
: File handle of the MOD opened for (at least) read access. The caller is responsible to open the file and set the current file pointer at the start of the MOD binary. (This is useful if the MOD is packaged along with other files for easier distribution.)
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set).
The MOD will be loaded into extended memory when possible.
Remove the previously loaded MOD file from the memory and release allocated memory blocks.
Inputs:
None.
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set).
Start playback of the currently loaded MOD file.
Inputs:
None.
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set).
Set amplification level between 0.0 - 4.0x. At level 4x, a single channel can saturate the entire output range and playback in multiple channels may cause severe clipping. Level 1.0x is a good default value which avoids most clipping even with multichannel MODs (at this level, a channel can only saturate up to 25% of the total output). Experiment with the music you want to play and set the amplification level accordingly so the volume remains constant throughout your application without producing clipping.
This function can be called before or during playback to change the output level. It does 16384 multiplications to recalculate the volume table, so be aware that it can take a while on low-end CPUs. The change becomes effective at the next audio rendering pass (~ 2 * render buffer size latency).
Inputs:
AH.AL
: Amplification as 8.8 bit fixed point number.
Outputs:
AH.AL
: Actual amplification level as 8.8 bit fixed point number.
Set AX to 0x0100
for 1x, 0x0180
for 1.5x 0x0200
for 2.0x amplification, and so on. Please refer to Wikipedia if you are not familiar with fixed point artihmetics.
Set the interpolation method. This function can be called before or during playback. The change becomes effective at the next audio rendering pass (~ 2 * render buffer size latency).
Inputs:
AL
: Sample interpolation method. SeeMOD_IPOL_*
constants.
Outputs:
None.
Set the stereo panning method for stereo output devices. The function does nothing if the device is mono. This function can be called before or during playback. The change becomes effective at the next audio rendering pass (~ 2 * render buffer size latency).
Switching between mono and stereo on DAC and Sound Blaster devices during playback is only possible when the MOD_FLG_FMT_CHG
flag was set during device setup. On these devices, switching between mono and any stereo mode will flush the audio buffer and reinitialize the output device.
Inputs:
AL
: Stereo panning method. SeeMOD_PAN_*
constants.
Outputs:
AL
: Actual stereo panning method (alwaysMOD_PAN_MONO
for mono devices).
Change the sample rate. This is only allowed on DAC and Sound Blaster devices if the MOD_FLG_SR_CHG
flag was set during device setup. This operation will flush the audio buffer and reinitialize the output device.
Inputs:
EAX
: Requested new sample rate.
Outputs:
EAX
: Actual sample rate.
Get the closest sample rate relative to current sample rate for the selected output device. Some devices (all DACs, the original Sound Blaster and Pro) are limited to a limited set of possible sample rates.
For example, DAC devices which use the timer interrupt can sample at 44192 Hz or 42614 Hz, but not in between. When a sample rate is specified during device initialization or via mod_set_sample_rate
, the device will use the nearest possible value. This is one step in the example, so if the current sample rate is 44192 Hz and this function is called with EAX
= -1
, the function will return 42614
in EAX
.
Sound Blaster 16 in contrast can use any sample rate, so if the current sample rate is 44100 Hz and this function is called with EAX
= -1
, the function will return 44099
in EAX
.
Inputs:
EAX
: Number of steps relative to current sample rate. Use negative amount for lower, positive for higher sample rates.
Outputs:
EAX
: Nearest possible sample rate.
Set the position of the playroutine. The change becomes effective at the next audio rendering pass (~ 2 * render buffer size latency). This function can be called during playback only.
Inputs:
AH
: Sequence entry number, starting at 0. Adjusted to last sequence entry when out of range.AL
: Row within the current pattern, 0 - 63. Clipped to 63 if a higher value is given.DL
: Set to 1 to stop playback of samples in channels before changing the position, 0 to keep them playing.
Outputs:
AH
: Actual sequence entry number, starting at 0.AL
: Actual row within the current pattern, 0 - 63.
Stop MOD playback.
Inputs:
None.
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set).
Render audio into the output buffer when needed. This function is provided so you can prevent the player from interrupting your application for a longer period of time.
Inputs:
None.
Outputs:
None.
The player uses triple buffering and renders audio into the buffer when a part has been played completely. This rendering can take a noticable amount of time (depending on number of channels, interpolation and stereo mode) and it can introduce jerkiness if it interrupts your render loop at an inconvenient time.
To prevent this from happening, follow the strategy below:
- Call
mod_render
in your render loop when the application finished all other important tasks. - Set the buffer size so that it covers the time needed for the render loop plus audio rendering.
Applications where this matters usually run in a vsync-locked render loop. Let's assume you use 320x240 VGA resolution and you want to update the screen in each frame (targetting 60 fps).
- 320x240 runs at 60 Hz, so the MOD player buffer size should be set to 1 / 60 * 1000000 = 16667 microseconds. Actual refresh rates may vary, so to be safe, let's round it up to 17000 microseconds.
- In the render loop, once you are finished with other tasks (flipping, rendering, input processing), call
mod_render
to update the output buffer. - Design the application so that it can sustain the target framerate on the targeted hardware.
- There will be a few frames when
mod_render
won't do anything, since the buffer is a bit larger, than a frame. - If the render loop does not finish within the frame and the buffer gets exhausted, the player will interrupt your application and render within its interrupt handler, so audio won't stutter unless the CPU is underpowered for the song/mixer settings.
Return information about the current MOD file. This function can be called when a MOD is loaded by the player.
Inputs:
None.
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set) or linear address ofmod_info
structure.
The mod_info
structure is static and depends only on the MOD currently loaded by the player. It can be freed by the caller using the mem_free
PMI service when the data is no longer needed.
offset | name | size | description |
---|---|---|---|
0x00 | title |
21 | ASCIIZ title of the song. |
0x15 | num_channels |
1 | Number of channels in the song. |
0x16 | num_samples |
1 | Number of samples used by the song. |
0x17 | length |
1 | Number of entries in the pattern sequence. |
0x18 | num_patterns |
1 | Number of patterns in the song. |
0x19 | restart_pos |
1 | Song restart position. |
0x1c | flags |
4 | Song flags (see MOD_FLG_* constants below) |
0x20 | sequence_addr |
4 | Linear address of 128-byte sequence entries. |
0x24 | pattern_addr |
4 | Linear address of start of pattern data. |
0x28 | samples |
N | Start of mod_sample_info entries for each sample of the MOD file. |
Structure of mod_sample_info
:
offset | name | size | description |
---|---|---|---|
0x00 | name |
23 | ASCIIZ name of the sample. |
0x18 | addr |
4 | Pointer to linear address of sample start. |
0x1c | length |
4 | Length of the sample in bytes. |
0x20 | rpt_start |
4 | Start offset of the sample loop (repeat) in bytes. Set to 0 when there is no loop. |
0x24 | rpt_len |
4 | Length of the sample loop in bytes. Set to 0 when there is no loop. |
The player may not retain the original contents of the sample after the end of the loop (may overwrite memory with unrolled loop data or discard it since it is not necessary for playback).
Return information on current MOD player channels. This function can be called during MOD playback. The information is captured for each render buffer and the one belonging to the currently played buffer is returned by this call.
Inputs:
ESI
: Pointer to memory area for an array ofmod_channel_info
data for each channel used by the MOD file. The buffer must be large enough to contain information for all channels (seemod_info.num_channels
).
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set).ESI
: Populated with an array ofmod_channel_info
structures.
Each mod_channel_info
structure contains the following data:
offset | name | size | description |
---|---|---|---|
0x00 | period |
4 | Current playback MOD period * 16. MOD period is a number representing the playback speed of a sample on the Amiga. |
0x04 | sample_pos_int |
4 | Current playback position of the sample being played in the channel. |
0x08 | sample_pos_fr |
2 | Current playback position fraction of the sample being played in the channel. sample_pos_int and sample_pos_fr form a 32.16 bit fixed point number representing the current sample position. |
0x0a | sample |
1 | Number of the sample being played in the channel, between 0 - 32. 0 means the channel is not playing anything. |
0x0b | volume |
1 | Volume of the sample currently being played, between 0 - 64. The volume is linear, 0 stands for silence and 64 for full volume. |
0x0c | pan |
1 | Current panning position of the channel, between 0 - 255, where 0 stands for full left and 255 stands for full right. |
When the output device is MOD_OUT_NONE
, the sample_pos_int
and sample_pos_fr
members of the structure won't be updated since there is no actual audio rendering.
Get information about the output device's current status. This function can be called during MOD playback.
Inputs:
ESI
: Pointer to memory area for amod_output_info
structure.
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set).ESI
: Populated withmod_output_info
structure data.
When the output device is MOD_OUT_NONE
, this function is not doing anything since there is no actual audio rendering.
The mod_output_info
structure contains the following data:
offset | name | size | description |
---|---|---|---|
0x00 | sample_rate |
4 | Actual playback (output) sample rate. |
0x04 | buffer_addr |
4 | Linear address of the output buffer. |
0x08 | buffer_size |
4 | Size of the output buffer in bytes. |
0x0c | buffer_pos |
4 | Current playback position within the buffer. |
0x10 | buffer_format |
1 | Audio data / sample format within the buffer. See MOD_BUF_* constants below. |
The type of the output buffer is represented by the following values:
value | name | description |
---|---|---|
0x03 | MOD_BUF_DEPTH |
Bitmask to extract audio bitdepth from format byte. |
0x00 | MOD_BUF_8BIT |
8-bit samples, 1 byte each. |
0x01 | MOD_BUF_16BIT |
16-bit samples, 2 bytes each. |
0x02 | MOD_BUF_1632BIT |
16-bit samples, 4 bytes each, may overflow 16-bit range. |
0x0c | MOD_BUF_CHANNEL |
Bitmask to extract number of channels from format byte. |
0x00 | MOD_BUF_1CHN |
1 channel (mono). |
0x04 | MOD_BUF_2CHN |
2 channels (stereo). |
0x08 | MOD_BUF_2CHNL |
2 channels, but only left channel contains audio data (mono). |
0x10 | MOD_BUF_RANGE |
Bitmask to extract sample data range from format byte. |
0x00 | MOD_BUF_INT |
Sample data is signed integer (-128 - 127 or -32768 - 32767). |
0x10 | MOD_BUF_UINT |
Sample data is unsigned integer (0 - 255 or 0 - 65535). |
Return the current position of the playroutine. This can be off by several ticks, depending on the size of the render buffer. Use mod_get_position_info
for a more accurate reading that accounts for the buffer. The purpose of this method is to get current information for relative position jumps via mod_set_position
.
Inputs:
None.
Outputs:
AH
: Sequence entry number, starting at 0.AL
: Row within the current pattern, 0 - 63.DL
: Current tick within the row, starting at 0.
Get information about the song position currently played. This function can be called during MOD playback. The information is captured for each render buffer and the one belonging to the currently played buffer is returned by this call.
Inputs:
ESI
: Pointer to memory area for amod_position_info
structure.
Outputs:
CF
: Set if failed.EAX
: Error code if failed (CF
is set).ESI
: Populated withmod_position_info
structure data.
The mod_position_info
structure contains the following data:
offset | name | size | description |
---|---|---|---|
0x00 | position |
1 | Song position within the pattern sequence (0 - 127). |
0x01 | pattern |
1 | Number of pattern being played (0 - 255). |
0x02 | row |
1 | Row within pattern (0 - 63). |
0x03 | tick |
1 | Current tick within the row. |
0x04 | speed |
1 | Number of ticks within a row. |
0x05 | bpm |
1 | Beats per minute (32 - 255). |
A 32-bit counter that increments by the number of performance ticks spent with audio mixing and playroutine handling. You can read and reset this at any time. Compare this with the amount of performance counter ticks that elapsed in a known timeframe to calculate the relative amount of time spent with MOD playback.
The MOD library supports a few compilation-time parameters defined in src\mod\config.inc
.
-
MOD_USE_PROFILER
: Enables performance profiling of the audio mixer/MOD playroutine via PMIprofiler
library. Default value is1
. The application must callprofiler_start
before starting MOD playback. -
MOD_MAX_CHANS
: Set the maximum number of channels supported by the MOD player. Default value is32
, maximum is255
. This has no effect on CPU usage, but additional channels use a little amount of extra RAM (even if the MOD does not use these extra channels). -
UNROLL_COUNT
: Number of samples rendered by the audio mixer at one shot. This has a direct impact on memory usage as it expands the generated code size significantly. The default value is20
which seems to be the sweet spot. Since the audio mixer code also has self-modifying code, increasing the number of unrolls also adds overhead to the setup code which will negate the benefits of the unroll itself. You can reduce it down to about4
if code size and memory usage is extremely important for your use case. The number of unrolls also has an impact on memory used for samples. -
UNROLL_MAX_SPD
: Maximum sample playback speed which is supported by the unrolled audio mixer. Default value is17
which is a safe value for all supported MOD notes and output sample rates. The maximum supported unroll speed also has an impact on memory used for samples. -
LIN_IPOL_EXP
: Maximum linear interpolation oversampling exponent. The actual oversampling is 2 ^LIN_IPOL_EXP
. Default value is5
, which results in 32x oversampling (2 ^ 5 = 32). This is enough for up to 46.4 kHz sample rate for all supported MOD notes. Keep in mind that each additional oversampling requires 1024 bytes of memory for the interpolation lookup table. You can reduce this value to3
(8x oversampling) if you only want to play standard ProTracker MODs. -
WATTE_IPOL_EXP
: Maximum oversampling exponent for Watte trilinear interpolation. The actual oversampling is 2 ^WATTE_IPOL_EXP
. Default value is5
, which results in 32x oversampling (2 ^ 5 = 32). This is enough for up to 46.4 kHz sample rate for all supported MOD notes. Keep in mind that each additional oversampling requires 2 additional clock cycles on the 386 and 486 due to larger numbers being multiplied. You can reduce this value to3
(8x oversampling) if you only want to play standard ProTracker MODs.
The library can be built under DOS and Windows. The build uses the following toolchain:
- NASM to compile assembly source code to linkable objects.
- Open Watcom to make the project and link the executable binary.
The build toolchain is also available for Linux, but the build system only supports DOS and Windows.
Download and install the dependencies, then:
- Copy
makeinit.sam
tomakeinit
and set the following parameters:nasm_dir
: Path to directory containing nasm.exe (NASM binary).watcom_dir
: Path to directory containing Open Watcom platform-dependent binaries.- If both of them are added to system
PATH
, you don't need to create amakeinit
file.
- Download PMI, extract it into the same parent as of
mod
and runwmake dist
in the PMI folder. The folder structure should look like this:
|
+-- pmi
| |
| +-- build
| +-- dist
| +-- emu
| +-- lib
| +-- src
| ...
|
+-- mod
|
+-- src
...
In the project root directory, run wmake
to create a debug build to build\debug\mod
. Run wmake build=release
to create a release build to build\release\mod
The following wmake
targets are also available (append after wmake
or wmake build=release
):
wmake clean
: Remove compiled binaries inbuild\debug
orbuild\release
directory.wmake full
: Force a full recompilation (compilation by default is incremental, only changed source code is recompiled).wmake dist
: Create a binary distribution package todist
directory.