XMrsPlayer — a safe, no_std soundtracker music player
XMrsPlayer plays real soundtracker modules, on desktops and on tiny embedded targets alike. The crate is 100% safe Rust (#![forbid(unsafe_code)]) and builds on no_std; it reuses the data structures defined by the companion xmrs crate.
It does not aim for bit-exact compatibility with every tracker ever written — that target is unreachable given the historical and ever-shifting nature of the demo scene — but it aims to be close enough to amaze you. :-)
Supported formats
| Format | Status |
|---|---|
| Amiga Module (MOD) | Works |
| FastTracker XM | Works |
| ScreamTracker S3M | Works |
| Impulse Tracker IT | WIP — loader mostly done, playback in progress |
| SID (C64) | Experimental — reverse-engineered from Rob Hubbard's 6510 player |
A word on SID: tracks and effects can already be extracted from several of Hubbard's hits and played back through the generic module engine. One thing is still needed to go further — working per-track to reconstruct patterns (some tracks change length, which defeats a naive pattern builder), The module engine is already generic enough; the rest is a matter of time (and motivated contributors — Rust speakers welcome!).
FM instruments are supported by the underlying xmrs data structures and are ready for future formats.
Using it as a library
Minimal example (desktop, std):
use *;
use *;
let bytes = read?;
let module = load?;
let mut player = new;
player.set_amplification; // lower to avoid clipping on busy modules
player.set_max_loop_count; // 0 = loop forever
// The player is an Iterator<Item = f32> producing interleaved L/R samples.
for sample in player.by_ref.take
See the examples/ directory for complete players built on cpal and rodio.
The player also exposes a subscription API — hook into row/tick changes with PlayerObserver, or into the produced audio stream with MixObserver / ChannelsObserver (VU-meters, WAV recorders, visualisers). See OBSERVERS.md.
Cargo features
xmrsplayer has opt-in features so you only pay for what you use.
Default: ["std", "import"] — the common desktop/server case.
Runtime
| Feature | Effect |
|---|---|
std |
Enable the standard library and use f32's inherent methods for float math. Forwarded to xmrs. |
libm |
no_std float backend via num-traits + libm. |
micromath |
no_std float backend via micromath (smaller, slightly less precise). |
demo |
Everything needed to build the example CLI players: pulls in std, import, clap, console, cpal, hound, rodio. |
When std is disabled you must pick exactly one of libm or micromath; otherwise the crate emits a compile_error!.
Format importers (propagated to xmrs)
| Feature | Format |
|---|---|
import |
Umbrella — all of the below |
import_mod |
Amiga MOD |
import_xm |
FastTracker XM |
import_s3m |
ScreamTracker S3M |
import_it |
Impulse Tracker IT |
import_sid |
C64 SID |
Build examples:
# Tiny no_std build, XM only, libm backend
# no_std with micromath instead
# Desktop build (default)
Installing the CLI player
The demo feature ships a standalone CLI player (xmrsplayer) built on cpal.
From crates.io:
From a local checkout:
Run it directly from the git repo:
Typical invocation:
Interactive keys while playing: Space to pause, ←/→ to move, Enter/i for info, Esc or q to quit.
Design notes
- Safety first. Both this crate and its dependency
xmrsare#![forbid(unsafe_code)]. - Dependencies are lean, and gated behind features — this matters not only for embedded.
- FT2/XM quirks are format-driven. Setting
module.format = ModuleFormat::Xmactivates the canonical FT2 reference behaviour (arpeggio LUT,E60pattern-loop bug, arpeggio period clamp, portamento-down signed-overflow,K00-eats-note, vol-colBxadvancing vibrato). There is no separateft2_quirksflag — the format is the switch. - Embedded-friendly. The code should be progressively degradable to older processors through successive optimizations, and it would be a lot of fun to see what LLVM can do with it on float-less architectures like the Z80, the MOS 6502 family, or on the 68k target.
Contributing
The project was written with extension and sharing in mind — feel free to use it for your own projects. If you do, an issue on the codeberg repository mentioning it would be lovely (but not mandatory).
License
MIT — see LICENSE.