This manual documents the MikMod Sound Library, version 3.1.10.
The MikMod sound library is an excellent way for a programmer to add music and sound effects to an application. It is a powerful and flexible library, with a simple and easy-to-learn API.
Besides, the library is very portable and runs under a lot of Unices, as well as under OS/2, MacOS and Windows. Third party individuals also maintain ports on other systems, including MS-DOS, and BeOS.
MikMod is able to play a wide range of module formats, as well as digital sound files. It can take advantage of particular features of your system, such as sound redirection over the network. And due to its modular nature, the library can be extended to support more sound or module formats, as well as new hardware or other sound output capabilities, as they appear.
This chapter will describe how to quickly incorporate MikMod's power into your programs. It doesn't cover everything, but that's a start and I hope it will help you understand the library philosophy.
If you have a real tutorial to put here, you're welcome ! Please send it to me....
MikMod's sound output is composed of several sound voices which are mixed, either in software or in hardware, depending of your hardware configuration. Simple sounds, like sound effects, use only one voice, whereas sound modules, which are complex arrangements of sound effects, use several voices.
MikMod's functions operate either globally, or at the voice level. Differences in the handling of sound effects and modules are kept minimal, at least for the programmer.
The sound playback is done by a sound driver. MikMod provides several sound drivers: different hardware drivers, and some software drivers to redirect sound in a file, or over the network. You can even add your own driver, register it to make it known by the library, and select it (this is exactly what the module plugin of xmms does).
To use MikMod in your program, there are a few steps required:
mikmod.h
in your program.
Here's a program which meets all those conditions:
/* MikMod Sound Library example program: a skeleton */ #include <mikmod.h> main() { /* register all the drivers */ MikMod_RegisterAllDrivers(); /* initialize the library */ MikMod_Init(""); /* we could play some sound here... */ /* give up */ MikMod_Exit(); }
This program would be compiled with the following command line:
cc -o example example.c `libmikmod-config --cflags` `libmikmod-config --libs`
Although this programs produces no useful result, many things happen when you
run it. The call to MikMod_RegisterAllDrivers
registers all the drivers
embedded in the MikMod library. Then, MikMod_Init
chooses the more
adequate driver and initializes it. The program is now ready to produce sound.
When sound is not needed any more, MikMod_Exit
is used to relinquish
memory and let other programs have access to the sound hardware.
Our program is not really useful if it doesn't produce sound. Let's suppose
you've got this good old module, "Beyond music", in the file
beyond music.mod
. How about playing it ?
To do this, we'll use the following code:
/* MikMod Sound Library example program: a simple module player */ #include <unistd.h> #include <mikmod.h> main() { MODULE *module; /* register all the drivers */ MikMod_RegisterAllDrivers(); /* register all the module loaders */ MikMod_RegisterAllLoaders(); /* initialize the library */ md_mode |= DMODE_SOFT_MUSIC; if (MikMod_Init("")) { fprintf(stderr, "Could not initialize sound, reason: %s\n", MikMod_strerror(MikMod_errno)); return; } /* load module */ module = Player_Load("beyond music.mod", 64, 0); if (module) { /* start module */ Player_Start(module); while (Player_Active()) { /* we're playing */ usleep(10000); MikMod_Update(); } Player_Stop(); Player_Free(module); } else fprintf(stderr, "Could not load module, reason: %s\n", MikMod_strerror(MikMod_errno)); /* give up */ MikMod_Exit(); }
What's new here ? First, we've not only registered MikMod's device driver, but also the module loaders. MikMod comes with a large choice of module loaders, each one for a different module type. Since every loader is called to determine the type of the module when we try to load them, you may want to register only a few of them to save time. In our case, we don't matter, so we happily register every module loader.
Then, there's an extra line before calling MikMod_Init
. We change the
value of MikMod's variable md_mode
to tell the library that we want the
module to be processed by the software. If you're the happy owner of a GUS-type
card, you could use the specific hardware driver for this card, but in this
case you should not set the DMODE_SOFT_MUSIC
flag.
We'll ensure that MikMod_Init
was successful. Note that, in case of
error, MikMod provides the variable MikMod_errno
, an equivalent of
the C library errno
for MikMod errors, and the function
MikMod_strerror
, an equivalent to strerror
.
Now onto serious business ! The module is loaded with the Player_Load
function, which takes the name of the module file, and the number of voices
afforded to the module. In this case, the module has only 4 channels, so 4
voices, but complex Impulse Tracker modules can have a lot of voices (as they
can have as many as 256 virtual channels with so-called "new note actions").
Since empty voices don't cost time to be processed, it is safe to use a big
value, such as 64 or 128. The third parameter is the "curiosity" of the
loader: if nonzero, the loader will search for hidden parts in the module.
However, only a few module formats can embed hidden or non played parts, so
we'll use 0 here.
Now that the module is ready to play, let's play it. We inform the player that
the current module is module
with Player_Start
. Playback starts,
but we have to update it on a regular basis. So there's a loop on the result
of the Player_Active
function, which will tell us if the module has
finished. To update the sound, we simply call MikMod_Update
.
After the module has finished, we tell the player its job is done with
Player_Stop
, and we free the module with Player_Free
.
MikMod is not limited to playing modules, it can also play sound effects, that is, module samples. It's a bit more complex than playing a module, because the module player does a lot of things for us, but here we'll get more control over what is actually played by the program. Let's look at an example:
/* MikMod Sound Library example program: sound effects */ #include <unistd.h> #include <mikmod.h> main() { int i; /* sound effects */ SAMPLE *sfx1, *sfx2; /* voices */ int v1, v2; /* register all the drivers */ MikMod_RegisterAllDrivers(); /* initialize the library */ md_mode |= DMODE_SOFT_SNDFX; if (MikMod_Init("")) { fprintf(stderr, "Could not initialize sound, reason: %s\n", MikMod_strerror(MikMod_errno)); return; } /* load samples */ sfx1 = Sample_Load("first.wav"); if (!sfx1) { MikMod_Exit(); fprintf(stderr, "Could not load the first sound, reason: %s\n", MikMod_strerror(MikMod_errno)); return; } sfx2 = Sample_Load("second.wav"); if (!sfx2) { Sample_Free(sfx1); MikMod_Exit(); fprintf(stderr, "Could not load the second sound, reason: %s\n", MikMod_strerror(MikMod_errno)); return; } /* reserve 2 voices for sound effects */ MikMod_SetNumVoices(-1, 2); /* get ready to play */ MikMod_EnableOutput(); /* play first sample */ v1 = Sample_Play(sfx1, 0, 0); for(i = 0; i < 5; i++) { MikMod_Update(); usleep(100000); } /* half a second later, play second sample */ v2 = Sample_Play(sfx2, 0, 0); do { MikMod_Update(); usleep(100000); } while (!Voice_Stopped(v2)); MikMod_DisableOutput(); Sample_Free(sfx2); Sample_Free(sfx1); MikMod_Exit(); }
As in the previous example, we begin by registering the sound drivers and
initializing the library. We also ask for software mixing by modifying the
variable md_mode
.
It's time to load our files, with the Sample_Load
function. Don't forget
to test the return value -- it looks ugly here on such a small example, but
it's a good practice....
Since we want to play two samples, we have to use at least two voices for this,
so we reserve them with a MikMod_SetNumVoices
call. The first parameter
sets the number of module voices, and the second parameter the number of sound
effect voices. We don't want to set the number of module voices here (it's part
of the module player's duty), so we use the value -1
to keep the current
value, and we reserve two sound effect voices.
Now we're ready to play, so we call MikMod_EnableOutput
to make the
driver ready. Sound effects are played by the Sample_Play
function.
You just have to specify which sample you want to play, the offset from which
you want to start, and the playback flags. More on this later. The function
returns the number of the voice associated to the sample.
We play the first sample for half a second, then we start to play the second
sample. Since we've reserved two channels, both samples play simultaneously. We
use the Voice_Stopped
function to stop the playback: it returns the
current status of the voice argument, which is zero when the sample plays and
nonzero when it has finished. So the do
loop will stop exactly when
the second sample is finished, regardless of the length of the first sample.
To finish, we get rid of the samples with Sample_Free
.
Sound effects have some attributes that can be affected to control the playback.
These are speed, panning, and volume. Given a voice number, you can affect these
attributes with the Voice_SetFrequency
, Voice_SetPanning
and
Voice_SetVolume
functions.
In the previous example, we'll replace the actual sound code, located between
the calls to MikMod_EnableOutput
and MikMod_DisableOutput
, with
the following code:
Sample_Play(sfx1, 0, 0); for(i = 0; i < 5; i++) { MikMod_Update(); usleep(100000); } v2 = Sample_Play(sfx2, 0, SFX_CRITICAL); i = 0; do { MikMod_Update(); usleep(100000); v1 = Sample_Play(sfx1, 0, 0); Voice_SetVolume(v1, 160); Voice_SetFrequency(v1, (sfx1->speed * (100 + i)) / 100); Voice_SetPanning(v2, (i++ & 1) ? PAN_LEFT : PAN_RIGHT); } while (!Voice_Stopped(v2));
The first thing you'll notice, is the SFX_CRITICAL
flag used to play the
second sample. Since the do
loop will add another sample every 100
milliseconds, and we reserved only two voices, the oldest voice will be
cut each time this is necessary. Doing this would cut the second sample in the
second iteration of the loop. However, since we flagged this sound as
"critical", it won't be cut until it is finished or we stop it with a
Voice_Stop
call. So the second sample will play fine, whereas the first
sample will be stopped every loop iteration.
Then, we choose to play the first sample a bit lower, with
Voice_SetVolume
. Volume voices range from 0 (silence) to 256. In
this case we play the sample at 160. To make the sound look weird, we also
change its frequency with Voice_SetFrequency
. The computation in the
example code makes the frequency more and more high (starting from the sample
frequency and then increasing from 1% each iteration).
And to demonstrate the Voice_SetPanning
function, we change the panning
of the second sample at each iteration from the left to the right. The argument
can be one of the standard panning PAN_LEFT
, PAN_RIGHT
,
PAN_CENTER
and PAN_SURROUND
1, or a numeric value between 0 (PAN_LEFT
) and
255 (PAN_RIGHT
).
This chapter describes the various parts of the library and their uses.
If your program is dynamically linked with the MikMod library, you should check which version of the library you're working with. To do this, the library defines a few constants and a function to help you determine if the current library is adequate for your needs or if it has to be upgraded.
When your program includes mikmod.h
, the following constants are
defined:
LIBMIKMOD_VERSION_MAJOR
is equal to the major version number of
the library.
LIBMIKMOD_VERSION_MINOR
is equal to the minor version number of
the library.
LIBMIKMOD_REVISION
is equal to the revision number of the library.
LIBMIKMOD_VERSION
is the sum of LIBMIKMOD_VERSION_MAJOR
shifted 16 times, LIBMIKMOD_VERSION_MINOR
shifted 8 times, and
LIBMIKMOD_REVISION
.
So your program can tell with which version of the library it has been compiled this way:
printf("Compiled with MikMod Sound Library version %ld.%ld.%ld\n", LIBMIKMOD_VERSION_MAJOR, LIBMIKMOD_VERSION_MINOR, LIBMIKMOD_REVISION);
The library defines the function MikMod_GetVersion
which returns the
value of LIBMIKMOD_VERSION for the library. If this value is greater than or
equal to the value of LIBMIKMOD_VERSION for your program, your program will
work; otherwise, you'll have to inform the user that he has to upgrade the
library:
{ long engineversion = MikMod_GetVersion(); if (engineversion < LIBMIKMOD_VERSION) { printf("MikMod library version (%ld.%ld.%ld) is too old.\n", (engineversion >> 16) & 255, (engineversion >> 8) & 255, (engineversion) & 255); printf("This programs requires at least version %ld.%ld.%ld\n", LIBMIKMOD_VERSION_MAJOR, LIBMIKMOD_VERSION_MINOR, LIBMIKMOD_REVISION); puts("Please upgrade your MikMod library."); exit(1); } }
MikMod defines several data types to deal with modules and sample data. These types have the same memory size on every platform MikMod has been ported to.
These types are:
CHAR
is a printable character. For now it is the same as the
char
type, but in the future it may be wide char (Unicode) on some
platforms.
SBYTE
is a signed 8 bit number (can range from -128 to 127).
UBYTE
is an unsigned 8 bit number (can range from 0 to 255).
SWORD
is a signed 16 bit number (can range from -32768 to 32767).
UWORD
is an unsigned 16 bit number (can range from 0 to 65535).
SLONG
is a signed 32 bit number (can range from -2.147.483.648 to
2.147.483.647).
ULONG
is an unsigned 32 bit number (can range from 0 to
4.294.967.296).
BOOL
is a boolean value. A value of 0 means false, any other value
means true.
Although MikMod does its best to do its work, there are times where it can't. For example, if you're trying to play a corrupted file, well, it can't.
A lot of MikMod functions return pointers or BOOL
values. If the pointer
is NULL
or the BOOL
is 0 (false), an error has occurred.
MikMod errors are returned in the variable MikMod_errno
. Each possible
error has a symbolic error code, beginning with MMERR_
. For example, if
MikMod can't open a file, MikMod_errno
will receive the value
MMERR_OPENING_FILE
.
You can get an appropriate error message to display from the function
MikMod_strerror
.
There is a second error variable named MikMod_critical
. As its name
suggests, it is only set if the error lets the library in an unstable state.
This variable can only be set by the functions MikMod_Init
,
MikMod_SetNumVoices
and MikMod_EnableOutput
. If one of these
functions return an error and MikMod_critical
is set, the library is left
in the uninitialized state (i.e. it was not initialized, or MikMod_Exit
was called).
If you prefer, you can use a callback function to get notified of errors. This
function must be prototyped as void MyFunction(void)
. Then, call
MikMod_RegisterHandler
with your function as argument to have it notified
when an error occurs. There can only be one callback function registered, but
MikMod_RegisterHandler
will return you the previous handler, so you can
chain handlers if you want to.
To initialize the library, you must register some sound drivers first. You can
either register all the drivers embedded in the library for your platform with
MikMod_RegisterAllDrivers
, or register only some of them with
MikMod_RegisterDriver
. If you choose to register the drivers manually,
you must be careful in their order, since MikMod_Init
will try them in
the order you registered them. The MikMod_RegisterAllDrivers
function
registers the network drivers first (for playing sound over the network), then
the hardware drivers, then the disk writers, and in last resort, the nosound
driver. Registering the nosound driver first would not be a very good
idea....
You can get some printable information regarding the registered drivers with
MikMod_InfoDriver
; don't forget to call free
on the returned
string when you don't need it anymore.
After you've registered your drivers, you can initialize the sound playback
with MikMod_Init
, passing specific information to the driver if
necessary. If you set the variable md_device
to zero, which
is its default value, the driver will be autodetected, that is, the first driver
in the list that is available on the system will be used; otherwise only
the driver whose order in the list of the registered drivers is equal to
md_device
will be tried. If your playback settings, in the variables
md_mixfreq
and md_mode
, are not supported by the device,
MikMod_Init
will fail.
You can then choose the number of voices you need with
MikMod_SetNumVoices
, and activate the playback with
MikMod_EnableOutput
.
Don't forget to call MikMod_Update
as often as possible to process the
sound mixing. If necessary, fork a dedicated process to do this, or if the
library is thread-safe on your system, use a dedicated thread.
If you want to change playback settings, most of them can't be changed on the
fly. You'll need to stop the playback and reinitialize the driver. Use
MikMod_Active
to check if there is still sound playing; in this case,
call MikMod_DisableOutput
to end playback. Then, change your settings
and call MikMod_Reset
. You're now ready to select your number of voices
and restart playback.
When your program ends, don't forget to stop playback and call
MikMod_Exit
to leave the sound hardware in a coherent state.
On systems that have pthreads, libmikmod is thread-safe2. You can check this in your programs with the
MikMod_InitThreads
function. If this function returns 1, the library is
thread-safe.
The main benefit of thread-safety is that MikMod_Update
can be called
from a separate thread, which often makes application design easier. However,
several libmikmod global variables are accessible from all your threads, so
when more than one thread need to access libmikmod variables, you'll have to
protect these access with the MikMod_Lock
and MikMod_Unlock
functions. If libmikmod is not thread-safe, these functions are no-ops.
Currently, MikMod only supports uncompressed mono WAV files as samples. You can
load a sample by calling Sample_Load
with a filename, or by calling
Sample_LoadFP
with an open FILE*
pointer. These functions return
a pointer to a SAMPLE
structure, or NULL
in case of error.
The SAMPLE
structure has a few interesting fields:
speed
contains the default frequency of the sample.
volume
contains the default volume of the sample, ranging from 0 (silence)
to 64.
panning
contains the default panning position of the sample.
Altering one of those fields will affect all voices currently playing the
sample. You can achieve the same result on a single voice with the functions
Voice_SetFrequency
, Voice_SetVolume
and Voice_SetPanning
.
Since the same sample can be played with different frequency, volume and panning
parameters on each voice, you can get voice specific information with
Voice_GetFrequency
, Voice_GetVolume
and Voice_GetPanning
.
You can also make your sample loop by setting the fields loopstart
and
loopend
and or'ing flags
with SF_LOOP
. To compute your loop
values, the field length
will be useful. However, you must know that
all the sample length are expressed in samples, i.e. 8 bits for an 8 bit sample,
and 16 bit for a 16 bit sample... Test flags
for the value
SF_16BITS
to know this.
Speaking of flags, if you're curious and want to know the original format of the
sample on disk (since libmikmod does some work on the sample data internally),
refer to the inflags
field.
If the common forward loop isn't enough, you can play with some other flags:
SF_BIDI
will make your sample loop "ping pong" (back and forth), and
SF_REVERSE
will make it play backwards.
To play your sample, use the Sample_Play
function. This function
will return a voice number which enable you to use the Voice_xx
functions.
The sample will play until another sample takes over its voice (when you play
more samples than you reserved sound effect voices), unless it has been flagged
as SFX_CRITICAL
. You can force it to stop with Voice_Stop
, or you
can force another sample to take over this voice with Voice_Play
;
however Voice_Play
doesn't let you flag the new sample as critical.
Non looping samples will free their voice channel as soon as they are finished;
you can know the current playback position of your sample with
Voice_GetPosition
. If it is zero, either the sample has finished playing
or it is just beginning; use Voice_Stopped
to know.
When you don't need a sample anymore, don't forget to free its memory with
Sample_Free
.
As for the sound drivers, you have to register the module loaders you want to
use for MikMod to be able to load modules. You can either register all the
module loaders with MikMod_RegisterAllLoaders
, or only a few of them with
MikMod_RegisterLoader
. Be careful if you choose this solution, as the
15 instrument MOD loader has to be registered last, since loaders are called in
the order they were register to identify modules, and the detection of this
format is not fully reliable, so other modules might be mistaken as 15
instrument MOD files.
You can get some printable information regarding the registered loaders with
MikMod_InfoLoader
; don't forget to call free
on the returned
string when you don't need it anymore.
Note that, contrary to the sound drivers, you can register module loaders at any time, it doesn't matter.
For playlists, you might be interested in knowing the module title first, and
Player_LoadTitle
will give you this information. Don't forget to
free
the returned text when you don't need it anymore.
You can load a module either with Player_Load
and the name of the
module, or with Player_LoadFP
and an open FILE*
pointer. These
functions also expect a maximal number of voices, and a curiosity flag. Unless
you have excellent reasons not to do so, choose a big limit, such as 64 or even
128 for complex Impulse Tracker modules. Both functions return a pointer to an
MODULE
structure, or NULL
if an error occurs.
You'll find some useful information in this structure:
numchn
contains the number of module "real" channels.
numvoices
contains the number of voices reserved by the player for
the real channels and the virtual channels (NNA).
numpas
and numpat
contain the number of song positions and
song patterns.
numins
and numsmp
contain the number of instruments and
samples.
songname
contains the song title.
modtype
contains the name of the tracker used to create the song.
comment
contains the song comment, if it has one.
sngtime
contains the time elapsed in the module, in
2^-10 seconds (not exactly a millisecond).
sngspd
and bpm
contain the song speed and tempo.
realchn
contains the actual number of active channels.
totalchn
contains the actual number of active virtual channels,
i.e. the sum of realchn
and the number of NNA virtual channels.
Now that the module is loaded, you need to tell the module player that you want
to play this particular module with Player_Start
(the player can only
play one module, but you can have several modules in memory). The playback
begins. Should you forget which module is playing, Player_GetModule
will
return it to you.
You can change the current song position with the functions
Player_NextPosition
, Player_PrevPosition
and
Player_SetPosition
, the speed with Player_SetSpeed
and
Player_SetTempo
, and the volume (ranging from 0 to 128) with
Player_SetVolume
.
Playback can be paused or resumed with Player_TogglePause
. Be sure to
check with Player_Paused
that it isn't already in the state you want !
Fine player control is achieved by the functions Player_Mute
,
Player_UnMute
and Player_ToggleMute
which can silence or resume
a set of module channels. The function Player_Muted
will return the
state of a given channel. And if you want even more control, you can get the
voice corresponding to a module channel with Player_GetChannelVoice
and
act directly on the voice.
Modules play only once, but can loop indefinitely if they are designed to do so.
You can change this behavior with the wrap
and loop
of the
MODULE
structure; the first one, if set, will make the module restart
when it's finished, and the second one, if set, will prevent the module from
jumping backwards.
You can test if the module is still playing with Player_Active
, and you
can stop it at any time with Player_Stop
. When the module isn't needed
anymore, get rid of it with Player_Free
.
If you need to load modules or sound effects from other places than plain
files, you can use the MREADER
and MWRITER
objects to achieve
this.
The MREADER
and MWRITER
structures contain a list of function
pointers, which emulate the behaviour of a regular FILE *
object. In
fact, all functions which take filenames or FILE *
as arguments are only
wrappers to a real function which takes an MREADER
or an MWRITER
argument.
So, if you need to load a module from memory, or for a multi-file archive, for
example, all you need is to build an adequate MREADER
object, and use
Player_LoadGeneric
instead of Player_Load
or
Player_LoadFP
. For samples, use Sample_LoadGeneric
instead of
Sample_Load
or Sample_LoadFP
.
This chapter describes in more detail all the functions and variables provided by the library. See Type Definitions, for the basic type reference.
The following variables are set by the library to return error information.
int MikMod_errno
BOOL MikMod_critical
MikMod_errno
is different from zero.
If the value of MikMod_critical
is zero, the error wasn't fatal and the
library is in a stable state. However, if it is nonzero, then the library can't
be used and has reseted itself to the uninitialized state. This often means
that the mixing parameters you choose were not supported by the driver, or that
it doesn't has enough voices for your needs if you called
MikMod_SetNumVoices
.
The following variables control the sound output parameters and their changes take effect immediately.
UBYTE md_musicvolume
UBYTE md_pansep
UBYTE md_reverb
UBYTE md_sndfxvolume
UBYTE md_volume
The following variables control more in-depth sound output parameters. Except
for some md_mode
flags, their changes do not have any effect until you
call MikMod_Init
or MikMod_Reset
.
UWORD md_device
MDRIVER* md_driver
MikMod_Init
and
after MikMod_Exit
). This variable is for information only, you should
never attempt to change its value. Use md_driver
and MikMod_Init
(or MikMod_Reset
) instead.
UWORD md_mixfreq
UWORD md_mode
DMODE_INTERP
DMODE_REVERSE
DMODE_SURROUND
DMODE_16BIT
DMODE_HQMIXER
DMODE_SOFT_xx
flag is set.
DMODE_SOFT_MUSIC
DMODE_SOFT_SNDFX
DMODE_STEREO
DMODE_STEREO | DMODE_SURROUND |
DMODE_16BITS | DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX
.
Only the useful fields are described here; if a structure field is not described, you must assume that it's an internal field which must not be modified.
The MDRIVER
structure is not meant to be used by anything else than the
core of the library, but its first four fields contain useful information for
your programs:
CHAR* Name
CHAR* Description
UBYTE HardVoiceLimit
UBYTE SoftVoiceLimit
CHAR* Alias
The MODULE
structure gathers all the necessary information needed to
play a module file, regardless of its initial format.
The fields described in this section contain general information about the module and should not be modified.
CHAR* songname
CHAR* modtype
CHAR* comment
UWORD flags
UF_ARPMEM
UF_BGSLIDES
UF_HIGHBPM
UF_INST
UF_LINEAR
UF_NNA
numvoices
field is
valid.
UF_NOWRAP
UF_S3MSLIDES
UF_XMPERIODS
UF_FT2QUIRKS
UF_PANNING
UBYTE numchn
UBYTE numvoices
maxchan
parameter
of the Player_Loadxx
functions.
UWORD numpos
UWORD numpat
UWORD numins
UWORD numsmp
INSTRUMENT* instruments
SAMPLE* samples
UBYTE realchn
UBYTE totalchn
ULONG sngtime
The fields described here control the module playback and can be modified at any time, unless otherwise specified.
UBYTE initspeed
UBYTE inittempo
UBYTE initvolume
UWORD panning[]
numchn
values are
defined.
UBYTE chanvol[]
numchn
values are defined.
UWORD bpm
Player_SetTempo
to change its value.
UBYTE sngspd
Player_SetSpeed
to change its value.
UBYTE volume
Player_SetVolume
to change its value.
BOOL extspd
BOOL panflag
BOOL wrap
UBYTE reppos
BOOL loop
BOOL fadeout
UWORD patpos
SWORD sngpos
Player_NextPosition
, Player_PrevPosition
or
Player_SetPosition
instead.
SWORD relspd
Although the INSTRUMENT
structure is intended for internal use, you
might need to know its name:
CHAR* insname
The SAMPLE
structure is used for sound effects and module samples as
well. You can play with the following fields:
SWORD panning
ULONG speed
UBYTE volume
UWORD flags
Format flags:
SF_16BITS
SF_BIG_ENDIAN
SF_DELTA
SF_ITPACKED
SF_SIGNED
SF_STEREO
SF_BIDI
SF_LOOP
SF_REVERSE
UWORD inflags
ULONG length
ULONG loopstart
ULONG loopend
The MREADER
contains the following function pointers:
BOOL (*Seek)(struct MREADER*, long offset, int whence)
fseek
, with offset 0
meaning the start of the object (module, sample) being loaded.
long (*Tell)(struct MREADER*)
ftell
, with offset 0
meaning the start of the object being loaded.
BOOL (*Read)(struct MREADER*, void *dest, size_t length)
length
bytes of data into dest
, and
return zero if an error occured, and any nonzero value otherwise. Note that an
end-of-file condition will not be considered as an error in this case.
int (*Get)(struct MREADER*)
fgetc
.
BOOL (*Eof)(struct MREADER*)
feof
.
For an example of how to build an MREADER
object, please refer to the
MFILEREADER
object in file mmio/mmio.c
in the library sources.
The MREADER
contains the following function pointers:
BOOL (*Seek)(struct MWRITER*, long offset, int whence);
fseek
, with offset 0
meaning the start of the object being written.
long (*Tell)(struct MWRITER*);
ftell
, with offset 0
meaning the start of the object being written.
BOOL (*Write)(struct MWRITER*, void *dest, size_t length);
length
bytes of data from dest
, and
return zero if an error occured, and any nonzero value otherwise.
BOOL (*Put)(struct MWRITER*, int data);
fputc
.
For an example of how to build an MWRITER
object, please refer to the
MFILEWRITER
object in file mmio/mmio.c
in the library sources.
The following errors are currently defined:
MMERR_DYNAMIC_LINKING
MMERR_OPENING_FILE
xx_Loadxx
function, or for write access from the disk writer drivers.
MMERR_OUT_OF_MEMORY
setrlimit
function to do this if it needs to load very huge
samples.
MMERR_SAMPLE_TOO_BIG
MMERR_OUT_OF_MEMORY
.
MMERR_OUT_OF_HANDLES
MMERR_UNKNOWN_WAVE_TYPE
MMERR_ITPACK_INVALID_DATA
MMERR_LOADING_HEADER
MMERR_LOADING_PATTERN
MMERR_LOADING_SAMPLEINFO
MMERR_LOADING_TRACK
MMERR_MED_SYNTHSAMPLES
MMERR_NOT_A_MODULE
MMERR_NOT_A_STREAM
MMERR_16BIT_ONLY
MMERR_8BIT_ONLY
MMERR_DETECTING_DEVICE
MMERR_INITIALIZING_MIXER
MMERR_INVALID_DEVICE
md_device
) is out of range.
MMERR_NON_BLOCK
MMERR_OPENING_AUDIO
MMERR_STEREO_ONLY
MMERR_ULAW
MMERR_AF_AUDIO_PORT
MMERR_AIX_CONFIG_CONTROL
MMERR_AIX_CONFIG_INIT
MMERR_AIX_CONFIG_START
MMERR_GUS_RESET
MMERR_GUS_SETTINGS
MMERR_GUS_TIMER
MMERR_HP_AUDIO_DESC
MMERR_HP_AUDIO_OUTPUT
MMERR_HP_BUFFERSIZE
MMERR_HP_CHANNELS
MMERR_HP_SETSAMPLESIZE
MMERR_HP_SETSPEED
MMERR_OSS_SETFRAGMENT
MMERR_OSS_SETSAMPLESIZE
MMERR_OSS_SETSPEED
MMERR_OSS_SETSTEREO
MMERR_SGI_MONO
MMERR_SGI_SPEED
MMERR_SGI_STEREO
MMERR_SGI_16BIT
MMERR_SGI_8BIT
MMERR_SUN_INIT
MMERR_OS2_MIXSETUP
MMERR_OS2_SEMAPHORE
MMERR_OS2_THREAD
MMERR_OS2_TIMER
MMERR_DS_BUFFER
MMERR_DS_EVENT
MMERR_DS_FORMAT
MMERR_DS_NOTIFY
MMERR_DS_PRIORITY
MMERR_DS_THREAD
MMERR_DS_UPDATE
MMERR_WINMM_ALLOCATED
MMERR_WINMM_DEVICEID
MMERR_WINMM_FORMAT
MMERR_WINMM_HANDLE
MMERR_WINMM_UNKNOWN
MMERR_MAC_SPEED
MMERR_MAC_START
BOOL MikMod_Active(void)
MikMod_Update
will be ignored when sound output is disabled.
MikMod_DisableOutput
, MikMod_EnableOutput
.
void MikMod_DisableOutput(void)
MikMod_Update
will be ignored when sound output is disabled.
MikMod_Active
, MikMod_EnableOutput
.
BOOL MikMod_EnableOutput(void)
MikMod_Update
will be ignored when sound output is disabled.
MikMod_Active
, MikMod_DisableOutput
.
void MikMod_Exit(void)
MikMod_Init
, MikMod_Reset
.
long MikMod_GetVersion(void)
(maj<<16)|(min<<8)|(rev)
,
where maj
is the major version number, min
is the minor version
number, and rev
is the revision number.
CHAR* MikMod_InfoDriver(void)
NULL
if no drivers are registered.
malloc
; the caller must free it when it is
no longer necessary.
MikMod_RegisterDriver
, MikMod_RegisterAllDrivers
.
CHAR* MikMod_InfoLoader(void)
NULL
if no loaders are registered.
malloc
; the caller must free it when it is
no longer necessary.
MikMod_RegisterLoader
, MikMod_RegisterAllLoaders
.
BOOL MikMod_Init(CHAR *parameters)
md_device
is zero (autodetection).
MikMod_Exit
, MikMod_InitThreads
, MikMod_Reset
.
BOOL MikMod_InitThreads(void)
MikMod_Lock
or
MikMod_Unlock
is made.
MikMod_Lock
, MikMod_Unlock
.
void MikMod_Lock(void)
MikMod_Unlock
call should be associated to a MikMod_Lock
call. To be sure this is the case, we advise you to define and use the
following macros:#define MIKMOD_LOCK MikMod_Lock();{
#define MIKMOD_UNLOCK }MikMod_Unlock();
MikMod_InitThreads
must have been invoked before any call
to MikMod_Lock
in made.MikMod_InitThreads
, MikMod_Unlock
.
void MikMod_RegisterAllDrivers(void)
MikMod_InfoDriver
, MikMod_RegisterDriver
.
void MikMod_RegisterAllLoaders(void)
MikMod_InfoLoader
, MikMod_RegisterLoader
.
void MikMod_RegisterDriver(struct MDRIVER* newdriver)
MDRIVER
structure identifying the driver.
MikMod_Init
.
If you want to register all the available drivers, use
MikMod_RegisterAllDrivers
instead.
MikMod_InfoDriver
, MikMod_RegisterAllDrivers
.
MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t newhandler)
NULL
if there was none.
MikMod_handler_t
is defined as void(*function)(void)
, this means
your error function has the following prototype:
void MyErrorHandler(void)
void MikMod_RegisterLoader(struct MLOADER* newloader)
MLOADER
structure identifying the loader.
Player_Load
or Player_LoadFP
. If you want to register all the available module
loaders, use MikMod_RegisterAllLoaders
instead.load_m15
) should always be registered
last.
MikMod_InfoLoader
, MikMod_RegisterAllLoaders
.
MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t newplayer)
MikMod_player_t
is defined as void(*function)(void)
, this means
your player function has the following prototype:
void MyPlayer(void)
bpm
value is the tempo of the module and can
change from its initial value when requested by the module.MikMod_player_t oldroutine; void MyPlayer(void) { oldroutine(); /* your stuff here */ ... } main() { ... /* Register our player */ oldroutine = MikMod_RegisterPlayer(MyPlayer); ... }
BOOL MikMod_Reset(CHAR *parameters)
md_device
to zero (autodetect), these parameters are ignored.
md_device
and md_mixfreq
, or one of the md_mode
flags
which require sound reinitialization. Sound playback will continue as soon as
the driver is ready.
MikMod_Exit
, MikMod_Init
.
BOOL MikMod_SetNumVoices(int musicvoices, int samplevoices)
-1
for any of the parameters will retain the current number
of reserved voices.MikMod_Init
, MikMod_Reset
.
void MikMod_Unlock(void)
MikMod_Unlock
call should be associated to a MikMod_Lock
call. To be sure this is the case, we advise you to define and use the
following macros:#define MIKMOD_LOCK MikMod_Lock();{
#define MIKMOD_UNLOCK }MikMod_Unlock();
MikMod_InitThreads
must have been invoked before any call
to MikMod_Unlock
in made.MikMod_InitThreads
, MikMod_Lock
.
void MikMod_Update(void)
Voice_xx
functions,
you should do this before calling MikMod_Update
.
char* MikMod_strerror(int errno)
BOOL Player_Active(void)
Player_Paused
, Player_TogglePause
, Player_Start
, Player_Stop
void Player_Free(MODULE* module)
Player_Load
, Player_LoadFP
.
int Player_GetChannelVoice(UBYTE channel)
Voice_SetPanning
, Voice_SetVolume
, Player_Mute
, Player_ToggleMute
, Player_Unmute
.
MODULE* Player_GetModule(void)
MODULE
being played, or NULL
if no module is
playing.
Player_Stop
, Player_Start
.
MODULE* Player_Load(CHAR* filename, int maxchan, BOOL curious)
MODULE
structure, or NULL
if an error occurs.
MMERR_MED_SYNTHSAMPLES
, and synthsounds are mapped to an empty sample.
Player_Free
, Player_LoadFP
, Player_LoadTitle
,
Player_LoadTitleFP
, Player_Start
.
MODULE* Player_LoadFP(FILE* file, int maxchan, BOOL curious)
MODULE
structure, or NULL
if an error occurs.
MMERR_MED_SYNTHSAMPLES
, and synthsounds are mapped to an empty sample.
Player_Free
, Player_Load
, Player_LoadTitle
,
Player_LoadTitleFP
, Player_Start
.
MODULE* Player_LoadTitle(CHAR* filename)
NULL
if either the module has no title
or an error has occurred.
malloc
; the caller must free it when it
is no longer necessary.
Player_Load
, Player_LoadFP
, Player_LoadTitleFP
.
MODULE* Player_LoadTitleFP(FILE* file)
NULL
if either the module has no title
or an error has occurred.
malloc
; the caller must free it when it
is no longer necessary.
Player_Load
, Player_LoadFP
, Player_LoadTitle
.
void Player_Mute(SLONG operation, ...)
MUTE_INCLUSIVE
, the two channel numbers delimit the
range and are part of the range ; otherwise, if the operation is
MUTE_EXCLUSIVE
, they are outside of the range.
/* mute channel 10 */ Player_Mute(10); /* mute channels 2 to 5 */ Player_Mute(MUTE_INCLUSIVE, 2, 5); /* mute channels 7 to 9 */ Player_Mute(MUTE_EXCLUSIVE, 6, 10);
Player_Muted
, Player_ToggleMute
, Player_Unmute
.
BOOL Player_Muted(UBYTE channel)
Player_Mute
, Player_ToggleMute
, Player_Unmute
.
void Player_NextPosition(void)
Player_PrevPosition
, Player_SetPosition
.
BOOL Player_Paused(void)
Player_TogglePause
.
void Player_PrevPosition(void)
Player_NextPosition
, Player_SetPosition
.
void Player_SetPosition(UWORD position)
Player_NextPosition
, Player_PrevPosition
.
void Player_SetSpeed(UWORD speed)
Player_SetTempo
.
void Player_SetTempo(UWORD tempo)
Player_SetSpeed
.
void Player_SetVolume(SWORD volume)
void Player_Start(MODULE* module)
Player_Stop
.
void Player_Stop(void)
Player_Start
.
void Player_ToggleMute(SLONG operation, ...)
MUTE_INCLUSIVE
, the two channel numbers delimit the
range and are part of the range ; otherwise, if the operation is
MUTE_EXCLUSIVE
, they are outside of the range.
/* toggle mute on channel 10 */ Player_ToggleMute(10); /* toggle mute on channels 2 to 5 */ Player_ToggleMute(MUTE_INCLUSIVE, 2, 5); /* toggle mute on channels 7 to 9 */ Player_ToggleMute(MUTE_EXCLUSIVE, 6, 10);
Player_Mute
, Player_Muted
, Player_Unmute
.
void Player_TogglePause(void)
Player_xx
functions still have effect when the module is paused.
Player_Paused
, Player_Start
, Player_Stop
.
void Player_Unmute(SLONG operation, ...)
MUTE_INCLUSIVE
, the two channel numbers delimit the
range and are part of the range ; otherwise, if the operation is
MUTE_EXCLUSIVE
, they are outside of the range.
/* unmute channel 10 */ Player_Unmute(10); /* unmute channels 2 to 5 */ Player_Unmute(MUTE_INCLUSIVE, 2, 5); /* unmute channels 7 to 9 */ Player_Unmute(MUTE_EXCLUSIVE, 6, 10);
Player_Mute
, Player_Muted
, Player_ToggleMute
.
void Sample_Free(SAMPLE* sample)
Sample_Load
, Sample_LoadFP
.
SAMPLE* Sample_Load(CHAR* filename)
SAMPLE
structure, or NULL
if an error has occurred.
Sample_Free
, Sample_LoadFP
.
SAMPLE* Sample_LoadFP(FILE* file)
SAMPLE
structure, or NULL
if an error has occurred.
Sample_Free
, Sample_Load
.
SBYTE Sample_Play(SAMPLE* sample, ULONG start, UBYTE flags)
SFX_CRITICAL
, for critical
sound effects which must not be interrupted.
Voice_Stop
to force the end of a critical sample.
MikMod_SetNumVoices
, Voice_Play
, Voice_SetFrequency
, Voice_SetPanning
, Voice_SetVolume
, Voice_Stop
.
ULONG Voice_GetFrequency(SBYTE voice)
Voice_SetFrequency
.
ULONG Voice_GetPanning(SBYTE voice)
PAN_CENTER
if no sample is currently playing on the voice.
Voice_SetPanning
.
SLONG Voice_GetPosition(SBYTE voice)
-1
.
Sample_Play
, Voice_Play
.
UWORD Voice_GetVolume(SBYTE voice)
Voice_RealVolume
, Voice_SetVolume
.
void Voice_Play(SBYTE voice, SAMPLE* sample, ULONG start)
Sample_Play
, Voice_SetFrequency
, Voice_SetPanning
, Voice_SetVolume
.
ULONG Voice_RealVolume(SBYTE voice)
Voice_SetVolume
.
Sample_Play
, Voice_GetVolume
, Voice_Play
, Voice_SetVolume
.
void Voice_SetFrequency(SBYTE voice, ULONG frequency)
Sample_Play
, Voice_GetFrequency
, Voice_Play
, Voice_SetPanning
, Voice_SetVolume
, Voice_Stop
.
void Voice_SetPanning(SBYTE voice, ULONG panning)
PAN_LEFT
) and 255 (PAN_RIGHT
). Center
is 127 (PAN_CENTER
. Surround sound can be enabled by specifying the
special value PAN_SURROUND
.
Sample_Play
, Voice_GetPanning
, Voice_Play
, Voice_SetFrequency
, Voice_SetVolume
, Voice_Stop
.
void Voice_SetVolume(SBYTE voice, UWORD volume)
Sample_Play
, Voice_GetVolume
, Voice_Play
, Voice_SetFrequency
, Voice_SetPanning
, Voice_Stop
.
void Voice_Stop(SBYTE voice)
Voice_Stop
, the function Voice_Stopped
will
return nonzero (true) for the voice. If you want to silence the voice without
stopping the playback, use Voice_SetVolume(voice, 0)
instead.
Sample_Play
, Voice_Play
, Voice_SetFrequency
, Voice_SetPanning
, Voice_SetVolume
.
BOOL Voice_Stopped(SBYTE voice)
Voice_Stop
.
MikMod presents a large choice of module loaders, for the most common formats as well as for some less-known exotic formats.
load_669
load_amf
load_dsm
load_far
load_gdm
load_imf
load_it
load_med
load_m15
load_mod
load_mtm
load_okt
load_stm
load_stx
load_s3m
load_ult
load_uni
load_xm
Currently, the only file type than can be loaded as a sample is the RIFF WAVE file. Stereo or compressed WAVE files are not supported yet.
These drivers send the generated sound over the network to a server program, which sends the sound to the real sound hardware. The server program can be on the same machine than your program, but MikMod does not have access to the hardware. Network drivers only support software mixing.
drv_AF
AUDIOFILE
environment variable, and MikMod is ready to send it sound.
drv_esd
ESPEAKER
environment variable, and MikMod is ready to send it sound.
These drivers access to the sound hardware of the machine they run on. Depending on your Unix flavor, you'll end with one or more drivers from this list:
drv_aix
drv_alsa
drv_dart
drv_hp
drv_os2
drv_oss
drv_sam9407
drv_sgi
drv_sun
drv_ultra
These drivers work on any machine, since the generated sound is not sent to hardware, but written in a file. Disk writer drivers only support software mixing.
drv_raw
music.raw
in the current directory. The file has no header and only contains the sound
output.
drv_wav
music.wav
in the current directory.
These drivers are of little interest, but are handy sometimes.
drv_stdout
drv_raw
disk writer.drv_pipe
MikMod_Init
).drv_nos
MikMod_Active
: Library Core Functions
MikMod_DisableOutput
: Library Core Functions
MikMod_EnableOutput
: Library Core Functions
MikMod_Exit
: Library Core Functions
MikMod_GetVersion
: Library Core Functions
MikMod_InfoDriver
: Library Core Functions
MikMod_InfoLoader
: Library Core Functions
MikMod_Init
: Library Core Functions
MikMod_InitThreads
: Library Core Functions
MikMod_Lock
: Library Core Functions
MikMod_RegisterAllDrivers
: Library Core Functions
MikMod_RegisterAllLoaders
: Library Core Functions
MikMod_RegisterDriver
: Library Core Functions
MikMod_RegisterErrorHandler
: Library Core Functions
MikMod_RegisterLoader
: Library Core Functions
MikMod_RegisterPlayer
: Library Core Functions
MikMod_Reset
: Library Core Functions
MikMod_SetNumVoices
: Library Core Functions
MikMod_strerror
: Library Core Functions
MikMod_Unlock
: Library Core Functions
MikMod_Update
: Library Core Functions
Player_Active
: Module Player Functions
Player_Free
: Module Player Functions
Player_GetChannelVoice
: Module Player Functions
Player_GetModule
: Module Player Functions
Player_Load
: Module Player Functions
Player_LoadFP
: Module Player Functions
Player_LoadTitle
: Module Player Functions
Player_LoadTitleFP
: Module Player Functions
Player_Mute
: Module Player Functions
Player_Muted
: Module Player Functions
Player_NextPosition
: Module Player Functions
Player_Paused
: Module Player Functions
Player_PrevPosition
: Module Player Functions
Player_SetPosition
: Module Player Functions
Player_SetSpeed
: Module Player Functions
Player_SetTempo
: Module Player Functions
Player_SetVolume
: Module Player Functions
Player_Start
: Module Player Functions
Player_Stop
: Module Player Functions
Player_ToggleMute
: Module Player Functions
Player_TogglePause
: Module Player Functions
Player_Unmute
: Module Player Functions
Sample_Free
: Sample Functions
Sample_Load
: Sample Functions
Sample_LoadFP
: Sample Functions
Sample_Play
: Sample Functions
Voice_GetFrequency
: Voice Functions
Voice_GetPanning
: Voice Functions
Voice_GetPosition
: Voice Functions
Voice_GetVolume
: Voice Functions
Voice_Play
: Voice Functions
Voice_RealVolume
: Voice Functions
Voice_SetFrequency
: Voice Functions
Voice_SetPanning
: Voice Functions
Voice_SetVolume
: Voice Functions
Voice_Stop
: Voice Functions
Voice_Stopped
: Voice Functions
INSTRUMENT
: Structure Reference
md_device
: Variable Reference
md_driver
: Variable Reference
md_mixfreq
: Variable Reference
md_mode
: Variable Reference
md_musicvolume
: Variable Reference
md_pansep
: Variable Reference
md_reverb
: Variable Reference
md_sndfxvolume
: Variable Reference
md_volume
: Variable Reference
MDRIVER
: Structure Reference
MikMod_critical
: Variable Reference
MikMod_errno
: Variable Reference
MODULE
: Structure Reference
MREADER
: Structure Reference
MWRITER
: Structure Reference
SAMPLE
: Structure Reference
PAN_SURROUND
will be
mapped to PAN_CENTER
if the library is initialized without surround
sound, that is, if the variable md_mode
doesn't have the bit
DMODE_SURROUND
set.
Unless you explicitely choose to create a non thread-safe version of libmikmod at compile-time.
You can force libmikmod to
load the module (without the synthsounds, of course) by setting the
curious
parameter to 1
when invoking Player_Loadxx
.