/robex/ - standalone XM

Standalone XM playback in Windows using ft2play

By /robex/, March 2018. Back to Articles and Guides

Table of contents [expand all] [collapse all]

Abstract

In this guide I will demonstrate how to create a very basic XM player in C on Windows and compile it into a single executable, for convenience and ease of distribution.

As a bit of background info, here are some other options that you might use, although I find them a bit problematic:

What we'll use

The playing library that we'll use for this tutorial is ft2play.c by 8bitbubsy (16-bits.org), who is also the author of an awesome FT2 clone for Windows (it also seems to work flawlessly on Linux using Wine).

You can find the raw (and updated) file here, although I will provide all the necessary files for this tutorial down below. ft2play's aim is to provide an accurate FastTracker II playback, but I find its single-file structure easy to use in my own projects.

In order to compile the player under Windows I will use gcc, installed with MinGW. Installation instructions are available on their website, however it's quite straightforward to install. I recommend you to add C:\MinGW\bin, or wherever you installed it, to the PATH variable (PC > Properties > Advanced system settings > Environment variables), for ease of use in the command prompt later.

Getting started

Compiling ft2play

The file provided by the author contains the contents of the header file as a comment, so the first thing that we have to do is create ft2play.h:

#ifndef FT2_H
#define FT2_H

#include <stdint.h>

int8_t ft2play_LoadModule(const uint8_t *moduleData, uint32_t dataLength);
int8_t ft2play_Init(uint32_t outputFreq, int8_t lerpMixFlag, int8_t volRampFlag);
void ft2play_FreeSong(void);
void ft2play_Close(void);
void ft2play_PauseSong(int8_t pause);
void ft2play_PlaySong(void);
#endif

Afterwards we can already compile the code into an object file with the following gcc options (you can play with these if you want, just make sure to link the libraries stated):

gcc -c ft2play.c -lmingw32 -lwinmm -lm -Wall -mno-ms-bitfields -Wno-unused-result -Wno-char-subscripts -Wno-strict-aliasing -Wno-misleading-indentation -Winit-self -Wextra -Wunused -Wunreachable-code -Wswitch-default -O3 -s -o ft2play.o

If everything went right, you should now have a file called ft2play.o wherever you compiled the code.

The player

The basic source code for a minimal player consists of the following lines:

#include <stdio.h>
#include <windows.h>
#include <conio.h>

#include "ft2play.h"
#include "modbytes.c"

int main(int argc, char **argv)
{
	// initialize all the internal tables and structs used by ft2play
	// with frequency 48KHz, sampling interpolation and volume ramping
	if (!ft2play_Init(48000, 1, 1)) {
		printf("error opening song\n");
		return 0;
	}
	// load the module contained in modbytes
	if (!ft2play_LoadModule(modbytes, modbytes_len)) {
		printf("error loading module\n");
		return 0;
	}

	ft2play_PlaySong();

	unsigned char key;
	// while p key is not pressed
	while (!_kbhit()) {
		key = _getch();
		if (key == 'p') break;
		Sleep(100);
	}

	//free resources and exit
	ft2play_FreeSong();
	return 1;
}

Now you're probably wondering, what is modbytes.c and where did you get it from? Well, it is simply the mod file converted into an array of unsigned chars (that was hard to guess huh?), an easy way of accomplishing this under linux is by running the following command:

xxd -i file.xm > modbytes.c

...which will generate a file that looks something like this:

const unsigned char modbytes[] = {
	0x45,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,0x20,0x4d,0x6f,0x64,
	...,
}
unsigned int modbytes_len = ...;

You can then include this file in the player and load the raw bytes upon calling ft2play_LoadModule(), in order to avoid needing the .xm file shipped with your exe separately.

If you dont have access to UNIX tools or you'd rather have a more convenient alternative, I have created a simple (and non-thoroughly error-checking) program that does exactly this task: mod2bytes.c. You could of course also just open a FILE pointer and load the bytes into a buffer at runtime.

You can try to reduce the xm file size without losing quality by using a tool like shrinkxm or xmstrip, from the creator of uFMOD. You can find documentation about xmstrip here.

Afterwards compile the player simply like this:

gcc -o modplay.exe modplay.c ft2play.o -lwinmm

The end

And we're done! Enjoy your awesome tracker music while your program is running :). Here are all the files used in this tutorial, the MOD used is the_notebook.xm by lamb.


/robex/ - Last edited: 2020-09-28 04:29:04