IMF Format
Format type | Music |
---|---|
Notation type | OPL |
Instruments | OPL |
Max channel count | 9 or 11 |
Max track count | 1 |
Max pattern count | Unknown |
Max order count | Unknown |
Tags? | Unofficial: Title, Composer, Remarks, Program name |
Games |
The id Software Music Format (IMF) is a raw music format that stores the actual bytes sent to the Adlib's OPL2 chip. For this reason it is a very simple format to process.
File format
There are two versions of the IMF format: Type-0 format and Type-1 format. In a Type-0 file, the whole file is Adlib data that is played until the end of the file is reached. Type-1 files are actually ripped chunks from an AudioT Format file. No game ever actually used Type-1 IMFs that were not stored inside an AudioT file. The two initial bytes contain the size of the Adlib data (not including the two bytes themselves), so only this much data is played. This means it's possible to store arbitrary data in a Type-1 IMF file after the song data (see #Tag Data below.)
As a matter of luck, the first two data bytes in a Type-0 files are almost always 0x00 0x00, so this can be used to detect the file format version. If the first two bytes match the length of the file it is likely Type-1, but be aware that trailing data will mean this is not always true. Otherwise the only other way is to parse all the register/value pairs in the file and ensure the register is within range (e.g. registers 0xA0 to 0xA9 are valid, but 0xAA to 0xAF should never be used.) Note that 0x00 is actually an invalid register, but must be treated as valid since the files usually begin by writing 0x00 to register 0x00.
Another way to detect the type of an IMF file is to examine the first few instructions in the IMF file. The idea is that the first few IMF commands set up the AdLib registers and therefore should have no delay. Even if there is a delay, it would normally be relatively low compared to the combined 16-bit value of the (register, value) pair.
UINT16 ReadInt16LE(FILE* in)
{
UINT8 buf[2];
fread(buf, 1, 2, in);
return (buf[0] | (buf[1] << 8));
}
int IMF_IsChunk(FILE* in)
{
UINT16 chunksize, buff, i=42;
UINT32 sum1=0, sum2=0;
if(!in)
return 0;
if (!feof(in))
{
chunksize = ReadInt16LE(in);
if ((chunksize == 0) || (chunksize & 3))
return 0;
while(!feof(in) && i)
{
buff = ReadInt16LE(in);
sum1 += buff;
buff = ReadInt16LE(in);
sum2 += buff;
i--;
}
fseek(in, 0, SEEK_SET);
return (sum1 > sum2);
}
return 0;
}
In the code given above, if the file is a chunk (Type-1), then sum1 contains the sum of all (register, value) pairs and sum2 contains the sum of all delays. If it's a plain IMF file (Type-0), the sums are swapped.
The only case in which this detection would fail is IMF data that writes a bunch of zeroes to register zero (which would be pointless since that register is undefined) and/or has very large delays (which would be pointless because it would lead to delays of up to a minute before the next IMF command would be processed, resulting in multiple minutes of silence before the song actually starts playing notes).
Data type | Name | Description |
---|---|---|
UINT16LE | iLength | Song data length in bytes (Type-1 format only) |
BYTE[iLength] | cAdlibData | Song data (see below) - iLength bytes long if Type-1, or until EOF if Type-0
|
BYTE[] | cExtraData | Arbitrary data/tags (Type-1 format only, see #Tag Data below) |
The earliest version of the IMF data in the AudioT Format actually starts with a UINT32LE length value. The Commander Keen 4 Demo uses that early version. Just extracting the IMF chunk from the AUDIOT.CK4 file will most likely confuse programs, since the file does not start with two 0's. Programs that only check the first two bytes will assume that the file is a ripped chunk, but will swap the delays and register/data pairs because of the length value being stored in the first four bytes instead of just the first two. That means the song will not play the intended notes. Programs that use the detection code given above will identify the file as plain IMF data and treat the length value as an IMF command. That means the song will play correctly at first, but any trailing data present in the file will also be interpreted as IMF data, most likely leading to long delays at the end of the song.
Note that for Type-1 files, the initial two bytes (the "song data length") are likely to be the filesize minus two, as the two initial bytes aren't counted. The obvious exception to this is if there is trailing data at the end of the OPL data, such as an info tag.
The song data is composed of four-byte "units":
Data type | Description |
---|---|
BYTE | Adlib register |
BYTE | Adlib data |
UINT16LE | Delay |
The data byte is sent to the specified register on the Adlib card, followed by a delay for the specified number of cycles. For a 560Hz IMF file, there are 560 cycles in one second (see #Timing below), so a delay of 560 would result in one second of silence (and likewise in a 700Hz IMF the delay value would need to be 700 to produce one second of silence.) A delay of 1 would wait for a single cycle, and a delay of zero means the next register/data pair should be sent immediately (so in a single 'cycle', data would be sent continuously until the next non-zero delay value is reached.)
Timing
IMF files exist at three known speeds. Unfortunately this is determined by the game, not the IMF file, so tempo cannot be determined from the music files alone. Extracted IMFs can be compared to discern their speeds. The known speeds are:
Speed | Game |
---|---|
280Hz | Duke Nukem II |
560Hz | Bio Menace, Commander Keen, Cosmo's Cosmic Adventures, Monster Bash, Major Stryker |
700Hz | Blake Stone, Operation Body Count, Wolfenstein 3-D, Corridor 7 |
The easiest method to tell the files apart is to treat all files with a .WLF extension as 700Hz and all .IMF files as 560Hz. Since Duke II is the odd one out, it is usually ignored since doubling the value of all the delay bytes conveniently turns it into a 560Hz .IMF.
Restrictions
As IMF files contain Adlib music for games that may also have Adlib sound effects, care must be taken to ensure that IMF music and any sound effects can share the OPL chip without conflict. This is done by reserving the OPL's first channel for sound effects, leaving eight remaining channels available for use in IMF files. This has been confirmed by automated inspection of the IMF files from the following games, all of which have no data on OPL channel #0 beyond 2-3 initialisation commands: Bio Menace, Blake Stone, Commander Keen 4-6, Cosmo's Cosmic Adventures, Duke Nukem II, Major Stryker, Monster Bash, Operation Body Count, Wolfenstein 3-D.
In situations where channel #0 is not reserved and is used by the IMF file, when it is placed back into the game it interferes with the sound effects causing distortion, transposition, and otherwise resulting in broken sound effects. This can happen when an IMF file is created using a utility that does not take into account the fact that channel #0 must be left unused. See the end of this page for a list of utilities that can create IMF files and whether they treat channel #0 correctly.
It is worth noting that channel #0 is unused even in games such as Cosmo and Monster Bash, which do not use Adlib sound effects (Cosmo has PC speaker effects only and Monster Bash has PC speaker and digitised PCM audio.) It is also worth mentioning that some IMF songs from Monster Bash make use of the OPL's rhythm-mode, which trades three note-producing channels for five percussion channels. The IMF songs from the Keen 4 Demo also use rhythm-mode.
Tag Data
In a Type-1 IMF file it's possible to store data after the end of a song (as per the length given in the first two bytes of the file.) There are a few uses for this - some games store additional (unused) data there generated when the files were added to the game's group file, and others have repurposed this area to store information about the song itself (title, artist, etc.)
The tag data was originally written to the AudioT files by Id Software's tool Muse and was probably only processed by that tool. The Wolfenstein 3-D source code reads the entire chunk from the AudioT file (including any tag data), but it only ever uses the song length and the song data.
Official data
For those files which were distributed with additional data in this area, it is not entirely clear what the purpose of this data is. It was apparently added when the source IMF files were compiled into a group audio file by Muse. (They appear not to be part of the source IMF files as there are occurrences where a file consists solely of tag data.) The format appears to be the same in all games that use it (such as Bio Menace or Wolfenstein 3-D) but it is not supported by any IMF players.
Data type | Name | Description |
---|---|---|
UINT16LE | Unknown | |
char[16] | strTitle | Song title |
char[64] | strRemarks | Song comment/message, usually source file name. |
char[6] | cProg | Data from the compiler? |
Unofficial uses
It is also possible to store tags there, and this simple format is supported by most IMF players:
Data type | Name | Description |
---|---|---|
BYTE | cSignature | 0x1A |
char[256] | strTitle | Song title |
char[256] | strComposer | Song composer |
char[256] | strRemarks | Song comment/message |
char[9] | cProg | Name of the first program that added these tags (eight bytes + terminating NULL, pad out with NULLs if necessary.) |
Note that the char[256] strings are variable-length NULL-terminated strings. Their maximum length is 256 bytes *including* the terminating NULL, meaning the string will only ever contain 255 characters or less, plus the terminating-NULL. Of course the string will normally be much shorter, and an empty string will consist of a single 0x00 byte.
This tag format is supported by AdPlug when playing IMFs. The tag format can also be used with .raw files, but no players officially support it yet.
Note that the tags should begin directly after the IMF data, so in other words reading in the first two bytes of the file (the "song length") and then seeking forward that many bytes, should put the file pointer at the start of the tag block (so the next byte that will be read in should be 0x1A, if the tags are present.)
Tools
The following tools are able to work with files in this format.
Name | Platform | Play? | Create new? | Modify? | Convert/export to other? | Import from other? | Access hidden data? | Edit metadata? | Notes |
---|---|---|---|---|---|---|---|---|---|
AdPlug | All | Yes | No | No | Yes; .raw | No | No | No | |
Camoto | Linux/Win | Yes | No | No | Yes; many | Yes; many | No | Yes | |
CMF2IMF | Linux/Win | No | No | No | No | Yes; .cmf | No | No | Doesn't leave channel 0 clear for SFX |
DRO2IMF | Linux/Win | No | No | No | No | Yes; .dro | No | No | Doesn't leave channel 0 clear for SFX |
DRO2MIDI | Linux/Win | No | No | No | Yes; .mid | No | No | No | |
IMFCreator | Windows | No | No | No | No | Yes; .mid | No | No | |
MUS2IMF | DOS? | No | No | No | No | Yes; .mus | No | No | |
OPL3 Bank Editor | Linux, Windows, macOS | No | No | No | Yes; many | No | No | No | OPL3 Bank Editor can import FM instruments from IMF files |
- Pages using deprecated source tags
- All file formats
- All music formats
- OPL music
- Music with OPL instruments
- Bio Menace
- Blake Stone
- Catacomb 3-D
- Commander Keen 4-6
- Corridor 7 Alien Invasion
- Cosmo's Cosmic Adventures
- Duke Nukem II
- Hocus Pocus
- Major Stryker
- Monster Bash
- Operation Body Count
- Realms of Chaos
- Wolfenstein 3-D