If you have ever wondered how to add XM music to a retro game project, you are in the right place. XM stands for Extended Module, a tracker music file format created in 1994 by Fredrik Huss and the Triton demogroup for the DOS tracker FastTracker II. The format stores note patterns, instrument samples, and effect commands in a compact package that game developers love because it delivers authentic chiptune sound at a fraction of the file size of MP3 or OGG.
Before we go any further, an important clarification: this guide is about the XM tracker format, not SiriusXM satellite radio. Tracker music is the heart of the demoscene and classic game audio, and it is making a strong comeback in modern indie game development. I have spent the last decade composing tracker music, integrating it into Unity, Godot, and custom engines, and helping small teams get authentic retro sound into their games. In this guide, I will walk you through the whole pipeline, from composing in a tracker to exporting the XM file and wiring it into your game engine so it plays cleanly.
By the end, you will know which tracker to pick, how to export production-ready XM files, how to integrate them into Unity, Godot, GameMaker, or Unreal Engine, and how to write a custom player if your engine of choice does not speak the language natively.
IN THIS ENTRYTable of Contents
- 1How to Add XM Music to a Retro Game Project
- 2The History and Origins of the XM Format
- 3The XM Format Explained: Patterns, Samples, Instruments, and Channels
- 4Choosing a Tracker to Create XM Music
- 5My recommendation for game developers
- 6How to Export XM Files Correctly for Game Use
- 7Game Engine Integration Overview: Unity, Godot, GameMaker, and Unreal Engine
- 8Writing a Custom XM Player or Using a Library
- 9Tips for Optimizing XM Music for Games
- 10XM vs MOD vs S3M vs IT: Tracker Format Comparison
- 11Step-by-Step: Setting Up MilkyTracker for Game Music Composition
- 12Unity Integration: Built-In Import and Custom Player Setup
- 13Godot Integration: ModPlayer Asset and GDNative Approach
- 14Per-Channel Audio Control: The Hidden Power of Tracker Music
- 15Building Adaptive Music With Tracker Modules
- 16Common XM Playback Issues and Troubleshooting
- 17Where to Find Free XM Music for Retro Games
- 18FAQs
- 19What is the XM music format?
- 20What is the best tracker software for game music?
- 21Can I use XM files in Unity?
- 22Does Godot support XM files?
- 23What is the difference between XM and MOD formats?
- 24Is tracker music copyright free?
- 25How small are XM files compared to MP3?
- 26Final Thoughts: Bringing XM Music Into Your Game
How to Add XM Music to a Retro Game Project
This guide covers the full pipeline for integrating XM tracker music into your retro game project. We will start with the history and technical structure of the XM format, move through tracker selection and export best practices, and then walk through integration for Unity, Godot, GameMaker, and Unreal Engine. You will also learn how to use libraries like libxmp for custom playback, apply per-channel control for adaptive music, and troubleshoot common issues that arise during implementation.
The History and Origins of the XM Format
The XM format was born in 1994 when the Swedish demogroup Triton wanted a better tracker than the Amiga-based ProTracker could offer. Fredrik Huss (known as “Mr. H”) and his team built FastTracker II for DOS, and along with it defined the Extended Module specification. The goal was to keep the spirit of MOD files while adding features that modern 1990s hardware could exploit: more channels, multi-sample instruments, and basic sample compression.
XM quickly became the dominant tracker format for PC demoscene productions and was adopted by classic games like Worms, Second Reality, and a long list of PlayStation, Nintendo 64, and Game Boy Advance titles. The format’s tight file sizes (often under 60 KB per song) and its support for perfect sample looping made it a natural fit for cartridge-based consoles and early CD-ROM releases where every kilobyte mattered.
Three decades later, XM is still alive and well. Modern trackers like OpenMPT and MilkyTracker can write and play XM files, dozens of playback libraries exist for almost every platform, and there is a thriving community of composers continuing the tradition. If you want authentic retro sound for your game, XM is often the smartest choice available.
The XM Format Explained: Patterns, Samples, Instruments, and Channels
Before you start composing, it helps to understand what is actually inside an XM file. The format is structured around four core building blocks: patterns, samples, instruments, and channels. Each plays a specific role in how the music is reconstructed at runtime.
Patterns are the heart of any tracker module. A pattern is a grid of note data, typically 64 rows by a number of channels. Each cell in the grid holds a note (like C-4 or A#3), an instrument number, a volume value, and an effect command. Patterns are the “score” of the song: they tell the player what to play and when.
The order list defines the sequence in which patterns are played. A song might start with pattern 0 (the intro), jump to pattern 4 (the verse), then 2 (the chorus), and so on. Order lists let you arrange short musical ideas into a full song structure without duplicating pattern data.
Samples are the raw audio snippets (usually 8-bit or 16-bit PCM) that the tracker triggers when a note plays. A single sample might be a single drum hit, a sustained bass note, or a one-shot synth stab. XM samples are stored in the file itself, so unlike MIDI, the player does not need any external soundfont.
Instruments are higher-level definitions that bundle multiple samples together with envelope settings, default volume, panning, and loop points. XM’s support for multi-sample instruments is one of the key advantages over the older MOD format, which is limited to one sample per “instrument slot.”
Channels are the simultaneous voices the tracker mixes together. XM supports up to 32 channels, though most retro songs use 4 to 16. Each channel is independent, which is exactly what makes per-channel control possible in games: you can mute a channel, change its volume, or jump to a different pattern on a single channel while the rest of the song keeps playing.
Finally, the effect commands (sometimes called “hex effects” or just “effects”) are per-row instructions that change how a note plays. Common effects include volume slides, vibrato, arpeggio, portamento, and sample offset. These are what give tracker music its characteristic sound and its ability to change in real time.
Choosing a Tracker to Create XM Music
To create XM files, you need a tracker. A tracker is a specialized music editor that combines a piano-roll style pattern view with sample management and effect commands. The good news is that there are several excellent free and paid options. Here is what I recommend for game developers.
MilkyTracker is the top choice for most beginners. It is free, open-source, cross-platform (Windows, macOS, Linux), and it uses the same interface as the original FastTracker II. If you want to learn tracker music on a modern operating system and write proper XM files, MilkyTracker is the place to start. The community is active, there are plenty of tutorials, and the preserved FastTracker II compatibility means your files will be compatible with classic players.
OpenMPT (Open ModPlug Tracker) is the most powerful Windows tracker. It is free, supports far more features than the original XM format (including IT, S3M, MPTM, and full VST plugin support), and it has advanced export options that let you control sample compression, instrument count, and compatibility flags. If you need maximum control over your XM export, OpenMPT is the safer choice.
Renoise is a paid (with discounted indie license) modern tracker that supports its own XRNS format but can also load and export XM files. Renoise’s interface is slicker and more DAW-like, and it has built-in effects and a strong community. I use Renoise when I want to compose quickly with a modern workflow, but for shipping pure XM files into games, I usually finish in OpenMPT or MilkyTracker.
FastTracker II clone projects exist (like the FT2 clone for Windows and the original DOS binary under emulation) for purists who want absolute authenticity. They are fun for nostalgia but not necessary for most game projects.
My recommendation for game developers
Start with MilkyTracker if you have never used a tracker before. It is the easiest to learn, has the smallest download, and produces clean XM files. Move to OpenMPT once you need advanced effects or precise export control. Consider Renoise if you want a modern workflow and do not mind paying for a license.
How to Export XM Files Correctly for Game Use
Exporting XM files for game use is not quite the same as saving them for general playback. Game engines have specific expectations: they want small files, predictable channel counts, and clean loop points. Here is the workflow I use.
Step 1: Finalize the song in your tracker. Make sure all patterns are written, the order list is set, and the song loops cleanly. I usually add a custom “loop” jump effect at the end of the final pattern so the player knows exactly where to restart.
Step 2: Trim your samples. Go through each sample and trim silence at the head and tail. Samples are the biggest contributor to XM file size, and even a few seconds of unused silence multiplies across your song. In MilkyTracker, you can use the sample editor’s “Trim” function. In OpenMPT, use the sample editor’s “Resize” tool.
Step 3: Enable sample compression if your tracker supports it. XM has an optional delta-value compression that roughly halves the size of 16-bit samples. OpenMPT can apply this on export. Keep in mind that some older players do not support compressed samples, so test with your target player.
Step 4: Save as .xm (not .xmz or any other extension). Filename extensions matter. The .xmz extension is sometimes used for compressed XM files and is not universally supported by game engines. Save as .xm to be safe.
Step 5: Verify in a clean player. Open the saved file in a different player (like XMPlay or foobar2000 with the right plugin) to make sure it sounds exactly as intended. If the file sounds different in your target engine, you have a compatibility issue.
Step 6: Check the file size. A typical XM track with decent samples should land between 30 KB and 200 KB. If yours is much larger, you probably have unused samples or uncompressed 16-bit samples that could be trimmed.
Game Engine Integration Overview: Unity, Godot, GameMaker, and Unreal Engine
Now that you have a clean XM file, it is time to integrate it into your game engine. The level of native support varies dramatically between engines, and this is the area where most game developers get stuck. Here is the honest breakdown.
Unity has built-in support for importing tracker modules (XM, MOD, IT, S3M) as audio assets. You can drag an .xm file directly into the project window, and Unity will treat it as an AudioClip. The catch is that Unity’s built-in player only exposes the final mixed audio, not the individual channels. For per-channel control or adaptive music, you need a custom player built on libxmp or a similar library. There are several community-made Unity packages that use libxmp and expose channel data.
Godot removed native tracker module support in version 3.0, and as of Godot 4, you still need a third-party solution. The most popular option is the “Godot Mod Player” asset by TheBonefin, which uses libxmp under the hood and exposes per-channel control. For more advanced setups, you can build a GDNative module around libxmp yourself. This is more work, but it gives you full control over the player.
GameMaker Studio 2 has very limited native tracker support. The built-in audio functions expect WAV, MP3, or OGG files. For tracker music, you typically have two options: pre-render the XM to OGG using OpenMPT’s render-to-WAV feature and import the OGG, or use a third-party extension like the XMP extension by samueldellavecchia. The pre-render approach is simpler but loses the per-channel control and dynamic music benefits of tracker music.
Unreal Engine 5 does not ship with native tracker support, but a community plugin called soundmod fills the gap. Once enabled, you can drag .xm files directly into the Content Browser and play them like any other sound asset. This is the easiest path for Unreal developers.
Custom engines and frameworks (LÖVE, SDL2, raylib, custom C/C++) benefit from libxmp, which has bindings for nearly every language and platform. If you are building a custom engine, libxmp is the right starting point.
Writing a Custom XM Player or Using a Library
For most game projects, the cleanest path is to use an existing playback library rather than writing your own XM parser from scratch. The format is well-documented, but implementing correct playback that handles all the edge cases (effects, sample loops, envelope timing) takes weeks of work. Here are the libraries I trust.
libxmp is the gold standard for C/C++ projects. It supports MOD, XM, S3M, IT, and many other formats, and it is the library most tracker developers and demoscene tools rely on. It is actively maintained, well-documented, and has a strict accuracy mode that matches original playback. The downside is file size: libxmp is around 100 KB compiled, which can be a lot for embedded projects.
libxmp-lite is a stripped-down version of libxmp designed for games and embedded systems. It removes the less common formats and bulky features to keep the binary footprint small (often under 30 KB). If you only need XM and a few other formats, libxmp-lite is the better choice.
DUMB (Dynamic Universal Music Bibliotheque) is another popular C library for tracker module playback. It is older than libxmp but has solid XM support and is used in several commercial games. It is a good fallback if libxmp is not available for your platform.
xmp.js is a JavaScript port of libxmp that works in the browser via the Web Audio API. If you are building an HTML5 game and want authentic tracker sound, xmp.js is the easiest path. You can load an XM file with fetch(), decode it, and play it directly from JavaScript with full per-channel access.
For Unity, community packages like “XM Module Player for Unity” or “UniXM” wrap libxmp and expose channel data to your C# scripts. For Godot, the Godot Mod Player asset does the same thing.
Writing a custom player from scratch is a fun project but not usually worth the time for a shipping game. Use libxmp or a wrapper around it unless you have a specific reason to roll your own.
Tips for Optimizing XM Music for Games
Once your music is in the game, you want it to perform well. Here are the optimization tips I apply to every project.
Keep file size under 200 KB per track. Most XM files are tiny compared to MP3 or OGG, but a poorly managed XM with full-length uncompressed samples can balloon past 1 MB. Trim samples and use compression where supported.
Set explicit loop points. XM supports forward and ping-pong loops on samples. Always set loops on sustained samples (bass, pads, leads) so the player does not have to guess where to loop.
Test on your target hardware. Tracker music is CPU-cheap to decode, but per-channel mixing does require some work. Always benchmark on the lowest-spec device you plan to support.
Use stereo width strategically. Panning channels slightly left or right creates a wider mix without adding CPU cost. Most tracker interfaces let you set per-channel default panning.
Prefer 16-bit samples with compression. 16-bit samples give you better dynamic range than 8-bit, and XM’s delta compression keeps file size reasonable.
Stream long tracks from disk if memory is tight. Some libraries (libxmp and DUMB) let you stream the pattern data from disk while keeping samples in memory. For very long tracks, this can save significant RAM.
XM vs MOD vs S3M vs IT: Tracker Format Comparison
You have probably seen MOD, S3M, and IT files alongside XM. Here is how they compare and why XM is usually the right choice for retro game projects.
MOD is the original Amiga format from the late 1980s. It supports up to 4 or 8 channels, 8-bit samples only, and one sample per “instrument.” It is the most universally compatible format but has the most limitations. Use MOD only if you need maximum compatibility with very old hardware.
S3M (Scream Tracker 3 Module) was created in 1991 by Future Crew. It supports up to 32 channels, 16-bit samples, and proper stereo panning. It is widely supported and is a good choice for older demoscene-style music.
XM (Extended Module, 1994) is the format we have been discussing. It supports up to 32 channels, multi-sample instruments, envelopes, and sample compression. It is the sweet spot for retro game audio: more capable than MOD, more compact than IT, and broadly supported.
IT (Impulse Tracker Module, 1995) is the most advanced of the four. It supports new effects, advanced sample editing, and some unique features like NNA (New Note Action). IT is the best for fast-paced modern tracker music but is overkill for most retro game projects.
For a retro game project, XM is almost always the right choice. It is compact, well-supported, easy to author, and has the rich features most composers need.
Step-by-Step: Setting Up MilkyTracker for Game Music Composition
Here is the exact workflow I follow when starting a new XM track in MilkyTracker for a game project.
Step 1: Download and install MilkyTracker. It is free from the official MilkyTracker website. The installer is small and runs on Windows, macOS, and Linux.
Step 2: Set the project tempo and BPM. For a typical chiptune track, I start with 125 BPM and a speed of 6 ticks per row. This gives a punchy, energetic feel that works well for action games.
Step 3: Configure the number of channels. For game music, 8 to 16 channels is plenty. Click the channel count selector and choose 8 channels for a minimal style or 16 for a fuller mix.
Step 4: Build your drum kit in the instrument editor. Most retro game music starts with a solid drum kit. Create one instrument per drum (kick, snare, hi-hat, etc.) and assign a short sample to each.
Step 5: Lay down a beat in pattern 0. Use the pattern editor to enter your drum hits. In MilkyTracker, you click a cell, type the note (like C-4 for kick), and press Enter. Repeat for each beat.
Step 6: Add bass and lead instruments. Once the beat is in, add a bassline on a lower channel and a lead melody on a higher channel. Use volume columns and effects to give each instrument character.
Step 7: Arrange the song using the order list. Click the order list panel and create your song structure: intro, verse, chorus, bridge, and outro. Reuse patterns where the music loops.
Step 8: Save and test the XM file. Use File > Save Module and save as .xm. Open it in XMPlay or another player to verify the result.
For more advanced techniques like echo, reverb, and filters, the indie game music tutorial at indiegamemusic.com has detailed examples of how to chain effects entirely within the tracker.
Unity Integration: Built-In Import and Custom Player Setup
Unity makes it easy to get started with XM files. Here is the simplest path.
Step 1: Drop the .xm file into your Unity project. Drag the file into the Assets folder. Unity will import it as an AudioClip.
Step 2: Add an AudioSource component to a GameObject. Create an empty GameObject (call it “MusicManager”), add an AudioSource component, and assign your XM AudioClip to it.
Step 3: Set the AudioSource to loop and play on awake. In the AudioSource settings, check “Loop” and “Play On Awake.” Press play and you should hear your XM track in the Unity editor.
For per-channel control, you need a custom player. The most popular community packages wrap libxmp and expose channel data, volume, and mute controls through C# scripts. Install one via the Unity Asset Store or via the Package Manager, then enable its component to control channels directly from your game code.
Godot Integration: ModPlayer Asset and GDNative Approach
Godot does not support tracker modules natively, so you have two choices.
Option 1: Godot Mod Player asset. Search for “Godot Mod Player” in the Godot Asset Library. Install the plugin, then add a ModPlayer node to your scene, assign your XM file as the “song” property, and call play() to start the music. The plugin exposes per-channel volume and mute controls.
Option 2: GDNative with libxmp. If you want full control, build a GDNative module that wraps libxmp. This is more work but lets you read pattern events, sample-accurate timing, and any other libxmp feature directly from GDScript or C#.
For most indie projects, the ModPlayer asset is the right choice. You get working XM playback in about five minutes.
Per-Channel Audio Control: The Hidden Power of Tracker Music
Tracker music’s biggest advantage over MP3 or OGG is that every channel is independent. A Unity forum user named JoeStrout built an open-source mod player precisely to take advantage of this. He wanted to mute specific channels during gameplay, like turning off the bass channel when the player is sneaking. That kind of reactive audio is impossible with a pre-rendered MP3.
To use per-channel control with libxmp or a wrapper library, you call a function like set_channel_volume(channel, volume) during playback. Your game code can respond to events: when the player takes damage, mute the lead channel; when entering a boss fight, boost the drums. This is exactly how demoscene composers have been authoring interactive music for decades.
Building Adaptive Music With Tracker Modules
Adaptive music is music that changes in response to player actions. With tracker modules, you have several ways to do this.
Pattern jumps. Most libxmp wrappers let you jump to a specific pattern at any time. You can have a “calm” pattern set and a “combat” pattern set, and switch between them based on game state.
Channel muting. Use the per-channel control mentioned above to add or remove layers dynamically. A calm exploration track with the bass muted, then unmute the bass when combat starts.
Volume automation. Gradually fade channels up or down based on game events. Slowly bring the drums in as the player approaches a boss, or fade everything out when the player pauses.
These techniques are what make tracker music feel alive in a way that streamed audio cannot match. The Reddit gamedev community has long threads about how dynamic music in games is one of the most underused tools for player immersion.
Common XM Playback Issues and Troubleshooting
When your XM file refuses to play correctly, here are the usual suspects.
Wrong file format. Make sure the file is actually .xm and not .xmz or any other variant. Some engines are strict about extensions.
Sample data missing. If a sample was deleted but a pattern still references it, you will hear silence. Open the file in OpenMPT and look for missing samples in the sample list.
Loop point problems. If a sustained sample has no loop point, the player will play it once and then silence. Set forward or ping-pong loops on all sustained samples.
Channel count mismatch. Some engines cap channel count. If your XM has 32 channels but the engine supports only 16, the extra channels will be silently dropped.
Drift over time. If your tracker and the engine interpret BPM slightly differently, the music will go out of sync over long periods. Use a tool that supports precise timing, and test long tracks end-to-end.
Where to Find Free XM Music for Retro Games
If you do not want to compose your own music, there are several archives of free XM and tracker music. KeygenMusic.net, the site hosting this guide, has thousands of classic chiptune and tracker tracks from the demoscene. OpenGameArt.org has Creative Commons licensed tracker music suitable for indie games. The ModArchive is one of the largest collections of tracker modules in the world, though licensing varies by track. Always check the individual license before using a track in a commercial project.
FAQs
What is the XM music format?
XM (Extended Module) is a tracker music file format created in 1994 by Fredrik Huss for FastTracker II. It stores note patterns, instrument samples, and effect commands in a compact file format that supports up to 32 channels, multi-sample instruments, and basic sample compression. XM is widely used for retro game audio because it provides authentic chiptune sound at a fraction of the file size of MP3 or OGG.
What is the best tracker software for game music?
For most game developers, MilkyTracker is the best starting point because it is free, cross-platform, easy to learn, and produces clean XM files. OpenMPT is the most powerful Windows tracker with advanced export options. Renoise is a paid option with a modern DAW-like interface. All three can export XM files for use in retro game projects.
Can I use XM files in Unity?
Yes. Unity has built-in support for importing XM, MOD, S3M, and IT files as AudioClip assets. Drag the .xm file into your project, attach it to an AudioSource, and it will play. For per-channel control or adaptive music, install a community package like XM Module Player for Unity that wraps libxmp and exposes channel data to C# scripts.
Does Godot support XM files?
Godot does not support tracker modules natively as of Godot 4. The most popular workaround is the Godot Mod Player asset from the Godot Asset Library, which uses libxmp under the hood and supports XM, MOD, S3M, and IT files with per-channel control. For full control, you can also build a GDNative module around libxmp yourself.
What is the difference between XM and MOD formats?
MOD is the original Amiga format from the late 1980s with 8-bit samples only and up to 8 channels. XM (Extended Module) was created in 1994 to add multi-sample instruments, 16-bit sample support, envelopes, and sample compression. XM is more capable and is the preferred format for most modern retro game projects while still being widely supported on legacy hardware.
Is tracker music copyright free?
Tracker music is not automatically copyright free. Music is owned by its composer regardless of format. However, many tracker music archives like KeygenMusic.net host music with permissive licenses, and Creative Commons licensed tracks are available from sites like OpenGameArt.org. Always verify the license of any track before using it in a commercial game project.
How small are XM files compared to MP3?
A typical XM track with full samples lands between 30 KB and 200 KB, while the same music compressed as MP3 at 128 kbps would be 3 to 5 MB. XM files are 10 to 100 times smaller than MP3 for equivalent music, which is why tracker music was the standard for cartridge-based consoles and remains a great choice for modern mobile and embedded games.
Final Thoughts: Bringing XM Music Into Your Game
Knowing how to add XM music to a retro game project opens up a world of authentic, dynamic audio that streamed formats cannot match. The end-to-end workflow is straightforward once you understand each step: choose a tracker, compose your songs carefully, export clean XM files with proper loop points and sample compression, and integrate them into your game engine using built-in support or a library like libxmp.
For most indie developers, the practical path is MilkyTracker to compose, OpenMPT to verify and optimize, and Unity’s built-in support (or Godot’s ModPlayer asset) to play the music. If you want per-channel control or adaptive music, install a community package that wraps libxmp and exposes channel data to your game code.
The XM format has been around for over three decades and it is still relevant because it does something no other format can do as efficiently: deliver interactive, looping, multi-channel music in a tiny file. If you are building a retro game in 2026, there is no better time to bring tracker music back into your toolkit. Start with a simple chiptune beat, save it as XM, drop it into your engine, and hear the difference for yourself.