A small XM (FastTracker II Extended Module) player library. Main features:
-
Small size in mind; many features can be disabled at compile-time, or are optimized out by the compiler if not used.
-
Timing functions for synchronising against specific instruments, samples or channels.
-
Samples can be loaded and altered at run-time, making it possible to use libxm with softsynths or other real-time signal processors.
Written in C11 and released under the WTFPL license, version 2.
The playback routine (assuming the non-portable .libxm
format is
loaded, see libxmize
below) fits in under 7KiB of compressed
machine code.
xzcrush libxmtoau
for x in *.xm; do libxmize $x $x.libxm; done
rename .xm.libxm .libxm *.xm.libxm
ls *.{xm,libxm} | xargs -n 1 -P 16 xz -9ekf
wc -c *.*xm *.*xm.xz libxmtoau.crushed
6810919 an-dream.libxm
5585551 an-dream.xm
109423 cerror-expatarimental.libxm
49240 cerror-expatarimental.xm
282590 drozerix_-_crush.libxm
121346 drozerix_-_crush.xm
581955 heritage.libxm
438340 heritage.xm
2855496 an-dream.libxm.xz
2876184 an-dream.xm.xz
4180 cerror-expatarimental.libxm.xz
4820 cerror-expatarimental.xm.xz
36060 drozerix_-_crush.libxm.xz
37276 drozerix_-_crush.xm.xz
201348 heritage.libxm.xz
201200 heritage.xm.xz
6833 libxmtoau.crushed
Binaries crushed with xzcrush
.
The libxmize
binary can convert a standard .xm
file to a
non-standard, non-portable representation of that module. The file
generated by libxmize
is usually a lot larger than the original
module, but has better compressibility.
In addition, the non-portable format:
-
requires less code to load (
xm_create_context_from_libxmize()
instead ofxm_create_context()
) and thus can be used to produce smaller binaries. (See the size section above.) -
requires significantly less memory to play back modules (only kilobytes thanks to
mmap()
, seelibxmtoau
for an example).
The data generated by libxmize
will not be readable:
- On a different CPU architecture
- On a different libxm commit
- On a libxm compiled with another compiler
- On a libxm compiled with a different compiler version
- On a libxm compiled with different options or CFLAGS
Some example programs are provided.
-
libxm.js is a very simple XM player/visualiser that runs in a browser (emscripten port).
-
xmgl
is a simple music visualiser that uses OpenGL and JACK for very precise audio synchronisation. See a demo here: https://www.youtube.com/watch?v=SR-fSa7J698 -
xmprocdemo
: see README -
xmtoalsa
is a simple player that uses the ALSA library. It producesxmp
-like output while playing. Usexmtoalsa --help
(or check the source) to see the full usage../xmtoalsa --random **/*.xm
-
xmtowav
will play a module and output a.wav
file../xmtowav my_module.xm my_module.wav
-
xmtoau
will play a module and output a.au
file to standard output.mpv <(./xmtoau my_module.xm)
-
libxmtoau
is similar toxmtoau
, except that it loads non-portable files generated bylibxmize
. -
xmbench
is a benchmark program.
Here are some interesting modules, most showcase unusual or advanced tracking techniques (and thus are a good indicator of a player's accuracy):
- Cerror - Expatarimental
- Lamb - Among the stars
- Raina - Cyberculosis
- Raina - Slumberjack
- Strobe - One for all
- Strobe - Paralysicical death
Status |##| Eff | Info | Description
--------+--+-----+------+------------------------------
DONE |00| 0 | | Arpeggio
DONE |01| 1 | (*) | Porta up
DONE |02| 2 | (*) | Porta down
DONE |03| 3 | (*) | Tone porta
DONE |04| 4 | (*) | Vibrato
DONE |05| 5 | (*) | Tone porta+Volume slide
DONE |06| 6 | (*) | Vibrato+Volume slide
DONE |07| 7 | (*) | Tremolo
DONE |08| 8 | | Set panning
DONE |09| 9 | | Sample offset
DONE |10| A | (*) | Volume slide
DONE |11| B | | Position jump
DONE |12| C | | Set volume
DONE |13| D | | Pattern break
DONE |14| E1 | (*) | Fine porta up
DONE |--| E2 | (*) | Fine porta down
|--| E3 | | Set gliss control
DONE |--| E4 | | Set vibrato control
DONE |--| E5 | | Set finetune
DONE |--| E6 | | Set loop begin/loop
UNTESTED|--| E7 | | Set tremolo control
DONE |--| E9 | | Retrig note
DONE |--| EA | (*) | Fine volume slide up
DONE |--| EB | (*) | Fine volume slide down
DONE |--| EC | | Note cut
DONE |--| ED | | Note delay
DONE |--| EE | | Pattern delay
DONE |15| F | | Set tempo/BPM
DONE |16| G | | Set global volume
DONE |17| H | (*) | Global volume slide
DONE |20| K | | Key off (Also note number 97)
DONE |21| L | | Set envelope position
DONE |25| P | (*) | Panning slide
DONE |27| R | (*) | Multi retrig note
DONE |29| T | (*) | Tremor
DONE |33| X1 | (*) | Extra fine porta up
DONE |--| X2 | (*) | Extra fine porta down
Status | Value | Meaning
--------+---------+-----------------------------
DONE | $10-$50 | Set volume (Value-$10)
DONE | $60-$6f | Volume slide down
DONE | $70-$7f | Volume slide up
DONE | $80-$8f | Fine volume slide down
DONE | $90-$9f | Fine volume slide up
DONE | $a0-$af | Set vibrato speed
DONE | $b0-$bf | Vibrato
DONE | $c0-$cf | Set panning
DONE | $d0-$df | Panning slide left
DONE | $e0-$ef | Panning slide right
DONE | $f0-$ff | Tone porta
-
Only loads FastTracker II-compatible XM files.
-
Loading a bogus file (that yet has a valid 60-byte header) will probably result in a segmentation fault.
-
Big endian architectures are not yet supported.
Some test XM files are in the tests
directory. Their goal is to test
a certain feature against regressions. A summary of tests (and what
they are supposed to test) is in the table below.
Test | Status | Tested against | Extras
-------------------------------+----------------+------------------------+------------------------------------------------
amiga.xm | FAIL | MilkyTracker, xmp | Should sound identical.
arp-slow.xm | FAIL | MilkyTracker, OpenMPT | Should sound identical.
autovibrato-turnoff.xm | PASS | MilkyTracker | Same pitches should be heard twice in a row.
fadeout-speed.xm | PASS | MilkyTracker | Should sound identical.
finetune.xm | PASS | MilkyTracker | Left and right channels should sound identical.
ghosts.xm | FAIL | MilkyTracker | Left and right channels should sound identical.
multiretrig-volume.xm | PASS | FT2, OpenMPT | Should sound identical.
note-delay-ghost.xm | PASS | MilkyTracker, FT2 | Should sound identical.
note-delay-retrig.xm | PASS | MilkyTracker | Should sound identical.
panning-law.xm | PASS | MilkyTracker, FT2clone | Should sound identical.
pattern-loop-quirk.xm | PASS | MilkyTracker | Should play the same notes at the same time.
pos_jump.xm | PASS | Milkytracker, OpenMPT | Only one beep should be heard.
ramping.xm | PASS | MilkyTracker | If XM_RAMPING is ON, no loud clicks should be heard.
ramping2.xm | PASS | MilkyTracker | If XM_RAMPING is ON, no loud clicks should be heard.
retrig-vol-fade.xm | PASS | MT, FT2clone, OpenMPT | Should sound identical.
tone-portamento.xm | PASS | MilkyTracker | Should sound identical.
tremolo.xm | PASS | MilkyTracker | Should sound identical.
tremor.xm | PASS | MilkyTracker | Should sound identical.
vibrato.xm | PASS | MilkyTracker | Should sound identical.
vibrato-slow.xm | PASS | OpenMPT | Should sound identical.
vibrato-octave.xm | PASS | FT2clone, OpenMPT | Should sound identical.
Thanks to:
-
Thunder kurttt@sfu.ca, for writing the
modfil10.txt
file; -
Matti "ccr" Hamalainen ccr@tnsp.org, for writing the
xm-form.txt
file; -
Mr.H of Triton and Guru and Alfred of Sahara Surfers, for writing the specification of XM 1.04 files;
-
All the MilkyTracker contributors, for the thorough documentation of effects;
-
All the people that helped on
#milkytracker
IRC; -
All the libxm contributors.