pocketmod is a small ANSI C library for turning ProTracker MOD files into playable PCM audio. It comes as an STB-style single-file library, with no external dependencies (not even the C standard library). The library has been tested on a wide range of MOD files, and should be fairly accurate. The code is MIT-licensed.
pocketmod.h
is meant to be dropped into your source tree and compiled along
with the rest of your code. To create the library implementation, #define
POCKETMOD_IMPLEMENTATION
before including the header in one source file.
This is the entire public API of the library:
typedef struct pocketmod_context pocketmod_context;
int pocketmod_init(pocketmod_context *c, const void *data, int size, int rate);
int pocketmod_render(pocketmod_context *c, void *buffer, int size);
int pocketmod_loop_count(pocketmod_context *c);
Below is a detailed description of each part.
struct pocketmod_context {
/* ... */
};
This structure holds state used during rendering. It's declared publicly so that you can instantiate it anywhere you like, but its data fields should be considered private. The structure is relatively small (less than 2 KiB), so you can put it on the stack if you want.
int pocketmod_init(pocketmod_context *c, const void *data, int size, int rate);
This function initializes a context and prepares it for rendering from the start
of a song. data
is a buffer containing MOD file data, and size
is the size
of that buffer in bytes. rate
is the desired sample rate in Hertz, for example
44100 for CD-quality audio. The function returns a nonzero value on success, or
zero if it was given an invalid MOD file.
Note that the library reads pattern and instrument data directly out of data
during rendering, so you should make sure that it remains valid until the last
call to pocketmod_render()
.
int pocketmod_render(pocketmod_context *c, void *buffer, int size);
This function renders the next part of the song and writes the rendered PCM
audio data to buffer
, which should be at least size
bytes large. It returns
the number of bytes worth of sample data that was written to buffer
.
Each sample consists of two float
PCM values, first the left channel and then
the right channel. pocketmod_render()
generally writes as many samples as it
can, but it may stop short when reaching the end of a pattern. This is done so
that you can check if the song looped, and decide for yourself if you want to
keep going or not.
int pocketmod_loop_count(pocketmod_context *c);
This function returns the number of times the song has looped. The song is considered to have looped when reaching a previously encountered pattern order position.
There are a few preprocessor symbols that may be #defined before including
pocketmod.h
to change the behavior of the library:
POCKETMOD_MAX_CHANNELS
: The maximum number of channels. The default value is 32 (the highest number for any MOD format). Lowering this value reduces the size of thepocketmod_context
structure. The downside is that it will makepocketmod_init()
fail for any songs that need more channels. This setting is useful if, for example, you know that all of your songs only use four channels.POCKETMOD_MAX_SAMPLES
: Same as the above, but for samples (instruments). The default value is 31 (the highest number for any MOD format).POCKETMOD_NO_INTERPOLATION
: You can define this to disable sample interpolation. This gives the rendered audio a sharper, rougher sound, which is sometimes preferred for chiptunes.
Note that if you define any of the above symbols, you should make sure that
they're defined the same in every source file that includes pocketmod.h
. I
recommend that you use your build system to do this consistently across your
whole project.
There are two small example programs included, to demostrate how the library is used.
This is a simple command-line tool for converting MOD files to WAV files. Here's an example of what building and using it looks like:
$ make converter
cc examples/converter.c -o converter -I.
$ ./converter songs/spacedeb.mod spacedeb.wav
Writing: 'spacedeb.wav' [54.0 MB] [5:05] Press Ctrl + C to stop
This is a command-line MOD player. To build the example, you need to have SDL2 installed. On Debian-based Linux you can get it the usual way:
$ sudo apt-get install libsdl2-dev
And here's what it looks like:
$ make player
cc examples/player.c -o player -I. -lSDL2main -lSDL2
$ ./player songs/king.mod
Playing 'king.mod' [00:03] Press Ctrl + C to stop
A small collection of test songs is included in the songs/
directory. All
credit for these go to their respective authors. I have shortened the filename
of some of the songs, but they are otherwise unaltered.
Filename | Author | License |
---|---|---|
bananasplit.mod | dizzy / cncd | ModArchive license |
chill.mod | Chromag | ModArchive license |
elysium.mod | Jester | CC BY-NC-SA 3.0 |
king.mod | Dreamweaver | ModArchive license |
nemesis.mod | radix | ModArchive license |
overture.mod | Jogeir Liljedahl | ModArchive license |
spacedeb.mod | Markus Kaarlonen | ModArchive license |
stardstm.mod | Jester | CC BY-NC-SA 3.0 |
sundance.mod | Purple Motion | ModArchive license |
sundown.mod | Chromag | ModArchive license |
supernova.mod | radix | ModArchive license |