Development: 228 Extensions

From OpenMPT Wiki
Jump to navigation Jump to search

This document is for OpenMPT 1.17.02.48 r192 and newer (cwtv ≥ 0x088D). For older versions, check OpenMPT Format Extensions § Custom Tunings (old).

The MPTM format is nearly identical to the IT format. The only difference is that OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings, and to specify that a file is in the MPTM format in the first place (otherwise it would be detected as IT).

This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions).

The chunk contains settings for these features:

  • Custom tunings.
  • Pattern time signature overrides, and Parameter Control notes in patterns.
  • All sequences and their order lists.

Other MPTM features (e.g. fractional tempos) use regular OpenMPT extensions.

Introduction[edit]

These are the datatypes used in this document (all numbers are stored in little-endian format, even floating-point numbers):

  • uint8, uint16, uint32, uint40: an unsigned integer with the given bit width.
  • int8, int16, int32: a signed integer with the given bit width.
  • float32: a 32-bit (single-precision) IEEE-754 floating-point number.
  • char: a text character (text encoding may vary, so a single character is not necessarily one byte).
  • Brackets ([]) after a datatype specify an array of that datatype.
    • If there is a number between the brackets, it is the number of items in the array.

There are also custom datatypes that are explained below:

Adaptive Integers[edit]

Adaptive integers are unsigned little-endian integer datatypes that can take less bytes to be stored (compared to regular integers), by storing their own length in themselves. In this document, the datatype of adaptive integers is written as auint followed by its bit width (e.g., auint64).

  • In a 16-bit adaptive integer, the least significant bit of the first byte (0 or 1) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.
  • In a 32-bit adaptive integer, the least significant two bits of the first byte (00, 01, 10, or 11) specify whether the integer is stored in 1, 2, 3, or 4 bytes respectively. The remaining 6, 14, 22, or 30 bits store the integer.
  • In a 64-bit adaptive integer, the least significant two bits of the first byte (00, 01, 10, or 11) specify whether the integer is stored in 1, 2, 4, or 8 bytes respectively. The remaining 6, 14, 30, or 62 bits store the integer.

Strings[edit]

Most text strings are stored as follows: the string's length (in bytes, not characters) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a 0x00 byte (null character) is present anywhere in the string, or the string is longer than 255 characters. In this document, the datatype of this type of strings is written as string. If a string is stored in a different format, it will be specified.

Additional Notes[edit]

  • In this document, "Windows codepage" refers to the user's selected ACP codepage in Windows (HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP), which is usually set to 1252, but may be different depending on the system locale.

228 Chunk Structure[edit]

Each 228 chunk contains a header, a set of entries, and a map.

The header contains information about the chunk, such as its number of entries, or the starting position of its map.

The main data section of the chunk can have any number of entries in it. Each entry is a set of bytes that can represent anything, such as an integer, a floating-point number, a string, or even a 228 chunk (a chunk can be an entry of another chunk).

The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.

In the list and table below, features that are never written to files by the current version of OpenMPT are shown in green text (see Default Chunk Settings for more information).

This is the general structure of a 228 chunk:

  • Header
    • Signature bytes (228)
    • Chunk ID
    • "Header byte"
    • Additional header data, including the "flag byte"
    • Numeric form of version number
    • String form of version number
    • Custom ID length for entries
    • Fixed entry size
    • Chunk description
    • Timestamp
    • Number of entries in the chunk
    • Starting position of the map in this chunk
  • Entries
    • (Entry 1)
    • (Entry 2)
    • (Entry 3)
    • (etc.)
  • Map
    • ID of Entry 1
    • Start position of Entry 1
    • Size of Entry 1
    • Description of Entry 1
    • ID of Entry 2
    • Start position of Entry 2
    • Size of Entry 2
    • Description of Entry 2
    • ID of Entry 3
    • Start position of Entry 3
    • Size of Entry 3
    • Description of Entry 3
    • (etc.)

Header Structure[edit]

This is the structure of the header of a chunk:

Datatype Content
char[3] 3-byte signature: 228. Identifies the start of a 228 chunk.
uint8 Length of the chunk's ID (in bytes).
uint8[] The chunk's ID. Usually readable as a string, but can be any set of bytes.
uint8 "Header byte". The bits of this byte specify what is and isn't stored in the chunk.
  • Bits 0 and 1 specify the length of the IDs of this chunk's entries, unless the chunk has a "flag byte" (explained later) and its bit 0 is set.
    • 00: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).
    • 01, 10, 11: all entries in this chunk have IDs with length 1, 2, or 4 respectively.
  • Bit 2: whether this chunk's map stores the starting position of each entry.
  • Bit 3: whether this chunk's map stores the size of each entry.
  • Bit 4: whether this chunk's header stores a numeric form of its version number.
  • Bit 5: whether this chunk's header stores a string (text) form of its version number.
  • Bit 6: whether this chunk's descriptions (explained later) use a fixed 16-bit encoding (e.g. UCS-2) instead of a fixed 8-bit encoding (e.g. ISO-8859-1 / Windows-1252).
  • Bit 7: whether this chunk's map contains descriptions for each entry.
auint32 Size of additional header data.
uint8[] Additional header data.

If the additional header data is at least 2 bytes long, and the first byte is 0x00, the second byte is read as the "flag byte".
The bits of the flag byte contain additional information about the chunk:

  • Bit 0: whether the chunk uses custom ID lengths for its entries.
  • Bit 1: whether all entries in this chunk have a fixed size.
  • Bit 2: whether the chunk contains a description about itself.
  • Bit 3: whether the chunk contains a timestamp.

The flag byte does not need to exist if none of its bits are supposed to be set.

auint64 Numeric form of the version number. Usually contains the same integer stored in the VWSL value in the OpenMPT song extensions, but there are exceptions.

This adaptive integer only exists if bit 4 of the header byte is set.

uint8 Length of the string form of the version number, in bytes.

This byte only exists if bit 5 of the header byte is set.

char[] String form of the version number. It was never used in any version of OpenMPT.

This string only exists if bit 5 of the header byte is set.

uint8 Custom ID length for entries.
  • If bit 0 is set, the length of the IDs of this chunk's entries are not constant, and are stored next to the IDs in the map. In this case, the remaining 7 bits of this byte are ignored.
  • If bit 0 is not set, the length of the IDs of this chunk's entries are stored in the remaining 7 bits of this byte.

This byte only exists if the chunk has a flag byte and its bit 0 is set.

auint32 Fixed entry size. Determines the size of all entries in this chunk.

This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.

auint16 Length of this chunk's description (in characters).

This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.

char[] Chunk description. If bit 6 of the header byte is set, the string uses use a fixed 16-bit encoding (e.g. UCS-2) instead of a fixed 8-bit encoding (e.g. ISO-8859-1 / Windows-1252).

This string only exists if the chunk has a flag byte and its bit 2 is set.

uint40 Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).

This was originally intended to store the Unix time (number of seconds past 1970-01-01 00:00:00 UTC) at the time of saving the file.
This integer only exists if the chunk has a flag byte and its bit 3 is set.

auint64 Number of entries in this chunk.

The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.

auint64 Start position of this chunk's map, relative to the start of this chunk (where the 228 bytes start).

This adaptive integer does not exist if this chunk does not have a map (see the section on maps for an explanation on whether a map exists or not).
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.

Entry Structure[edit]

The entries in a chunk start right where the header ends. Entries are just sets of bytes, and they are stored right after each other.

Entries of a chunk can be chunks themselves, allowing a chunk to be "nested" in another chunk by being one of the outer chunk's entries. Note that a nested chunk is a chunk on its own, and its header, entries, and map have nothing to do with those of the outer chunk that contains it.

Additionally, each entry can have an ID, and if said entry is a chunk, its entry ID when referred to as an entry of the outer chunk is not necessarily related to its chunk ID (which is stored in the inner chunk's header). It can be the same ID or a different one. That is very important to know, because OpenMPT stores a lot of inner chunks as entries of other chunks, so having to deal with their IDs can be quite confusing.

Note: Entries do not need to be stored in a specific order, as long as the chunk that contains them specifies entry IDs in its map. Otherwise, they have to be stored in the same order that OpenMPT reads them.

Map Structure[edit]

Chunks usually have maps. A chunk will not have a map if bits 2, 3, and 7, of the header byte, are not set, and the ID length for entries is fixed to 0. However, chunks written by the current version of OpenMPT do not meet this requirement, so they always have maps. If a chunk does not have a map, its header will also not store the start position of the map.

This is the structure of a section of a map corresponding to a single entry:

Datatype Content
auint16 Length of the entry's ID.

This adaptive integer only exists if the ID length for entries is not fixed (i.e., bit 0 of the flag byte and bit 0 of the custom ID length byte are both set).

uint8[] The entry's ID. Usually readable as a string, but can be any set of bytes.
auint64 Start position of this entry in the chunk, relative to the start of the chunk itself.

This adaptive integer only exists if bit 2 of the header byte is set.

auint64 Size of this entry in the chunk (in bytes).

This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is not set (or if there is no flag byte).

auint16 Length of this entry's description (in characters).

This adaptive integer only exists if bit 7 of the header byte is set.

char[] Description of the entry. If bit 6 of the header byte is set, the string uses a fixed 16-bit encoding (e.g. UCS-2) instead of a fixed 8-bit encoding (e.g. ISO-8859-1 / Windows-1252).

This string only exists if bit 7 of the header byte is set.

An entire map of a chunk is made of several copies of the structure shown in the table above, each copy corresponding to one of the entries of the chunk.

Note: The sections of a chunk's map which each correspond to an entry, do not need to be in the same order as the way the entries themselves are stored in the chunk, as long as the chunk specifies starting positions and sizes of entries in the map.

228 Chunks in MPTM Files[edit]

Reading the previous sections of this document is absolutely necessary to understand the rest of this document!

The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to a 228 chunk with an ID of mptm, which contains all the settings for MPTM features (like custom tunings) in its entries. OpenMPT writes this chunk after the OpenMPT song extensions, and before the last four bytes of the file that specify its position.

Default Chunk Settings[edit]

ALL chunks (and their "sub-chunks", a.k.a. the entries that are chunks themselves) that are written by the current version of OpenMPT have a header byte of 00011111 (0x1F), an additional header data size of 2 (byte 00001000 (0x08)), a flag byte of 00000001 (0x01) and a "custom entry ID length" byte of 00000001 (0x01).

This means that all chunks written by the current version of OpenMPT:

  • Have a map.
  • Have variable ID lengths for their entries, so they have to be stored in the map.
  • Store the starting position of their entries in their maps.
  • Store the size of their entries in their maps.
  • Store the numeric form of their version number in their headers.
  • Do not store a string form of their version number in their headers.
  • Do not store a timestamp in their headers.
  • Do not store descriptions about themselves in their headers.
  • Do not store descriptions about their entries in their maps.
  • Do not have fixed sizes for their entries.

However, OpenMPT does know how to properly read any chunks that were written by older versions of OpenMPT or by modifying a file using some external program, even if the chunks do not have the properties described above, as long as the structure of the chunks are written "correctly".

Files made with really old versions of OpenMPT, especially earlier versions of 1.17, may have differences in their header bytes and flag bytes compared to recent versions, but the chunk structure is always correct.

Additionally, new chunks and entries have been added to many versions, such as the Custom Tuning UTF-8 entry, which specifies that the names of custom tunings are encoded in UTF-8. Files with custom tunings that have been made with OpenMPT 1.29.00.40 or older will not have that entry, causing newer versions of OpenMPT to correctly read the names in the 8-bit Windows codepage.

Main Chunk[edit]

As of OpenMPT 1.17.03.01 r323, the mptm chunk's version number is the same integer stored in the VWSL value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk's version number was 1.

Custom Tunings[edit]

This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (cwtv ≥ 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in OpenMPT Format Extensions § Custom Tunings (old).

Entries containing custom tunings are stored in the mptm chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).

UTF-8 Text Encoding Indicator[edit]

This entry is a single byte with an entry ID of UTF8Tuning, stored as one of the entries of the base mptm chunk. It determines the global text encoding of the names of the tunings (and their note names). However, the tuning collection and each tuning can have their own text encoding indicator that overrides this one.

  • If this entry exists and its byte value is not 0: UTF-8.
  • If this entry does not exist or its byte value is 0: Windows codepage.

Currently, OpenMPT always writes this entry with a value of 1 (UTF-8). It will be written if there are any custom tunings, even if no instruments use them.

Tuning Collection[edit]

Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the Tuning Properties dialog.

In MPTM files, there is only one tuning collection called the "Tune-specific" tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are "local tunings" and "built-in tunings" (which are now discontinued) besides the "tune-specific" ones, they are not stored in the MPTM files themselves.

In MPTM files, the "tune-specific tunings" collection is stored as an entry of the base mptm chunk.

  • The entry ID of the "tune-specific tunings" collection chunk in MPTM files, which is stored in the map of the mptm chunk, is 0.
  • The chunk ID of any tuning collection chunk (regardless of the collection type, or whether it is stored in an MPTM or TC file), which is stored in its own header, is TC.

The chunk's version number is 3.

These are the entries stored in a tuning collection (TC) chunk:

Entry ID Datatype Content
UTF8 uint8 The text encoding of this collection's name, and the name of its tunings.
  • If this entry exists and its byte value is not 0: UTF-8 (override global encoding).
  • If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.

The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).

0 string The collection's name.

In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is Tune specific tunings.

1 uint16 The collection's edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.

Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).

In addition to the three entries listed above, the rest of the entries are all chunks, where each one is a custom tuning. They all have an entry ID of 2.

Tuning[edit]

For each custom tuning:

  • Its entry ID, which is stored in the map of the TC chunk, is 2.
  • Its chunk ID, which is stored in its own header, is CTB244RTI.

The chunk's version number is 67108868 (0x04000004).

These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the Tuning Properties dialog.

These are the entries stored in a custom tuning (CTB244RTI) chunk:

Entry ID Datatype Content
UTF8 uint8 The text encoding of the tuning's name.
  • If this entry exists and its value is not 0: UTF-8 (override collection's encoding).
  • If this entry does not exist or its value is 0: Inherit encoding from collection's encoding.
0 string The custom tuning's name.
1 uint16 The tuning's edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.

Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).

2 uint16 Tuning type.
  • 0 = General
  • 1 = Group-geometric
  • 3 = Geometric

Any other value will result in OpenMPT failing to load the custom tuning data.

3 (custom structure) Note names (see the Tuning Note Name Structure).

If this entry does not exist, OpenMPT will use the "default" note names (the predefined note names when creating a new tuning in OpenMPT).

4 uint32 Finetune steps.
RTI0 (custom structure) Ratio table (see the Ratio Table Structure).
  • For General tunings, the ratio table stores the ratios for all notes.
  • For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.

OpenMPT only writes this entry if the tuning type is General or Group-geometric.

RTI1 int16 First note index.

OpenMPT writes this entry for all types of tunings, and usually with a value of -64.

RTI2 uint16 Group size.

OpenMPT only writes this entry if the tuning type is Geometric.
(For group-geometric tunings, the group size is equal to the size of the ratio table.)

RTI3 float32 Group ratio.

OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.

RTI4 uint16 Number of ratios in the ratio table.

OpenMPT only writes this entry if the tuning type is Geometric or Group-geomtric, with a value of 128 for Geometric tunings, and the group size for Group-geometric tunings.

Tuning Note Name Structure[edit]
Datatype Content
auint64 Number of note names.

OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.

After the adaptive integer above, there are multiple note names that specify the names of notes in the entire table of notes (in Generic tunings) or only the notes of a single group (in Geometric and Group-geometric tunings).

This is the structure of a single note name:

Datatype Content
int16 Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)
uint8 Length of the note name (in bytes, not characters).
char[] Note name. The text encoding is inherited from the custom tuning's text encoding entry.

OpenMPT will stop reading the name if a 0x00 byte (null character) is present anywhere in the name.

The structure above is repeated for every note (or every note in the group if the tuning is Geometric or Group-geometric) that has a custom name.

Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are not a part of the note names.

Tuning Ratio Table Structure[edit]
Datatype Content
auint64 Number of ratios in the ratio table.

OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.

float32[] Ratios.

For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.

Tuning Map[edit]

(Not to be confused with "maps" of chunks!)

The tuning map is one of the entries of the base mptm chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the mptm chunk, is 1.

In a file made using OpenMPT 1.27.00.55 or older, local and built-in tunings are also specified in the tuning map, even though they are not written to the tuning collection chunk. If the file is loaded in newer versions, they will be converted to tune-specific ones and will then be stored in the MPTM file's tune-specific tuning collection chunk.

The first item in the structure is a uint16, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:

Datatype Content
uint16 Number of tunings that are used by instruments, including non-tune-specific tunings.

Following the number of tunings, there are mappings that map each tuning to an index number. This is the structure of a single tuning-to-index mapping:

Datatype Content
uint8 Length of the tuning's name (in bytes, not characters).
char[] The tuning's name.
  • The name of the default IT tuning (called OpenMPT IT behaviour in OpenMPT), is written as ->MPT_ORIGINAL_IT<-.
  • In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as 12TET and 12TET [[fs15 1.17.02.49]].

OpenMPT will stop reading the name if a 0x00 byte (null character) is present anywhere in the name.

uint16 The index that this tuning is mapped to.

The structure shown in the table above is repeated for every tuning.

Finally, there is an array of uint16s, each one corresponding to an instrument of the song, where the value of each one is the index that is mapped to the tuning that the corresponding instrument should use.

Note: Due to the way the tunings are located when a file is loaded, if there are multiple tunings with the same name, some instruments might be loaded with the wrong tunings.

Extended Pattern Data[edit]

Extended pattern data is used to store data for patterns that use features exclusive to the MPTM format: Pattern-specific time signature overrides and Parameter Control notes.

All extended pattern data is stored in a "pattern collection" chunk.

Extended Pattern Collection[edit]

The pattern collection (or "pattern container" according to the source code) is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.

  • Its entry ID, which is stored in the map of the mptm chunk, is mptPc.
  • Its chunk ID, which is stored in its own header, is also mptPc.

The chunk's version number is the same integer stored in the VWSL value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).

The entries stored in the mptPc chunk consist of "extended pattern" chunks, and a uint16 with an entry ID of num which specifies how many patterns will have their extended data read when loading the file. Its recommended value is the number of patterns in the song, but the song will still be loaded correctly if the number is at least bigger than the last pattern number that uses extended data.

If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the num entry containing the number of patterns in the song.

Extended Pattern[edit]

For each pattern:

  • Its entry ID, which is stored in the map of the mptPc chunk, is not readable as a string, but instead, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).
  • Its chunk ID, which is stored in its own header, is mptP.

The chunk's version number is the same integer stored in the VWSL value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).

These are the entries stored in an mptP chunk:

Entry ID Datatype Content
data (custom structure) The extended pattern data, which will be merged onto the IT pattern data when the file is read.

Technically, it can be used for storing any pattern data, but OpenMPT uses it for storing only the Parameter Control notes of each pattern.
The data is stored in the same format as the IT pattern format, but without the first 8 bytes, and with a different format for mask bytes:

  • Bit 0: Include note (OpenMPT only writes PC and PCs)
  • Bit 1: Include plugin number (instrument number if not a PC/PCs note)
  • Bit 2: Include high byte of controller ID (volume command type if not a PC/PCs note)
  • Bit 3: Include low byte of controller ID (volume command parameter if not a PC/PCs note)
  • Bit 4: Include high byte of parameter (effect command type if not a PC/PCs note)
  • Bit 5: Include low byte of parameter (effect command parameter if not a PC/PCs note)
  • Bit 6: Include extra data

The bytes after the mask byte (specifically the ones that need to be written) are written in the same order shown in the list above.
For the note value:

  • PC notes are stored as 0xFC
  • PCs notes are stored as 0xFB

The extra data (enabled via bit 6 of the mask byte) consists of an 8-bit unsigned integer specifying the size, followed by a set of bytes of that size. It is ignored by OpenMPT.
Any data that is specified by the mask byte to not be included will have the same data as the previous PC/PCs note in the channel.
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.

RPB. uint32 Custom "rows per beat" value for this pattern.

OpenMPT only writes this entry for patterns that use a custom time signature.

RPM. uint32 Custom "rows per measure" value for this pattern.

OpenMPT only writes this entry for patterns that use a custom time signature.

SWNG (custom structure) Custom tempo swing for this pattern.

Stored in the same format as the SWNG value in the OpenMPT song extensions.
OpenMPT only writes this entry for patterns that use a custom tempo swing.

Sequences[edit]

Currently, the main way sequences are stored is a "sequence collection" chunk, but there is also an older format that was used when an MPTM file could only have one sequence, which is still used by OpenMPT to make the file somewhat compatible with those old versions. Here is a history of how order lists were stored throughout different versions:

  • 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)
    • Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).
  • 2006-10-02: OpenMPT 1.17.02.45, r168
    • cwtv changed from 0x088A to 0x088B.
    • The order list stored at 0x00C0 now uses a custom structure (documented in OpenMPT Format Extensions § Order list (old)), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.
  • 2008-01-12: OpenMPT 1.17.02.49, r195
    • cwtv changed from 0x088D to 0x088E.
    • The order list stored at 0x00C0 now stores orders like Impulse Tracker again, which is limited up to pattern 253. However, there is now an entry in the mptm chunk that is used to store the order list if there are patterns over 253. If a file has this entry, OpenMPT will read the order list from it, and not from 0x00C0.
  • 2009-09-16: OpenMPT 1.17.03.01, r366
    • MPTM files can now have multiple sequences, where one of them can be the "default sequence". All sequences are now stored in a 228 chunk called the "sequence collection" chunk. A copy of the default sequence will also be stored at 0x00C0, and the old sequence entry if there are patterns over 253. However, in these new files, OpenMPT will ignore the order list at 0x00C0 entirely. This means that if there is no sequence collection or old sequence entry, even if there is an order list at 0x00C0, OpenMPT will load the file without an order list.

In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the "old" sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).

Sequence Collection (r366 and newer)[edit]

The sequence collection is a chunk, stored as one of the entries of the base mptm chunk. It contains the sequences of the MPTM file.

  • Its entry ID, which is stored in the map of the mptm chunk, is mptSeqC.
  • Its chunk ID, which is stored in its own header, is also mptSeqC.

The chunk's version number is the same integer stored in the VWSL value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).

These are the entries stored in the mptSeqC chunk:

Entry ID Datatype Content
n uint8 Number of sequences in the file.
c uint8 The "default sequence" of the file.

Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)
The "default sequence" is the one that is selected (the one shown in the order list) when the file is loaded, or the last time the file was saved.
It is also the one that is stored in the IT order list at 0x00C0 (and the old sequence entry if it contains patterns over 253).

In addition to the two entries listed above, the rest of the entries are all chunks, each one representing a sequence. Each one has an entry ID of the corresponding sequence's number, as a byte, with 0-based numbering.

For example, the ID of the entry corresponding to the first sequence is a 0x00 byte. If a second sequence existed, its entry ID would be 0x01, the next would be 0x02, and so on.

Currently, OpenMPT only allows creating up to 50 (0x32 in hex) sequences, so the limit (0xFF) is never reached (at least without editing the file externally).

Sequence (r366 and newer)[edit]

For each sequence:

  • Its entry ID, which is stored in the map of the mptSeqC chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).
  • Its chunk ID, which is stored in its own header, is mptSeq.

The chunk's version number is the same integer stored in the VWSL value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).

These are the entries stored in an mptSeq chunk:

Entry ID Datatype Content
u uint8 The text encoding of the sequence's name.
  • If this entry exists and its value is not 0: UTF-8.
  • If this entry does not exist or its value is 0: Windows codepage.

The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).

n (custom structure) Sequence name.

Contains the length of the name (in bytes, not characters), followed by the name.
The length is stored similarly to a 32-bit adaptive integer, except that the two bits that specify the size of the adaptive integer are bits 2 and 3 instead of 0 and 1, and bits 0 and 1 are unused. Depending on bits 2 and 3, the remaining 4, 12, 20, or 28 bits store the integer, which in this case, is the length of the name (in bytes).

l uint16 Length of the sequence (in orders).
a uint16[] The sequence's order list. Each order has the pattern number associated with it stored as a uint16.

For special ("non-pattern") orders:

  • +++ (separator) orders are stored as 0xFFFE.
  • --- (end of song) orders are stored as 0xFFFF.
r uint16 Restart position. OpenMPT only writes this entry if the sequence's restart position is not 0.
t uint32 Default tempo. This is a fixed-point number with 4 digits of fractional precision, i.e. divide the value by 10.000 to get the real tempo.
s uint32 Default speed (ticks per row).

"Old" Sequence (r195 and newer)[edit]

The old r195 sequence, which is used to store the default sequence if it has orders corresponding to patterns over 253, is a simple structure stored as one of the entries of the base mptm chunk. Its entry ID, which is stored in the map of the mptm chunk, is 2.

The structure of this entry is as follows:

Datatype Content
uint16 Length of the sequence (in orders).
uint16[] The order list. Each order has the pattern number associated with it stored as a uint16.

For special ("non-pattern") orders:

  • +++ (separator) orders are stored as 0xFFFE.
  • --- (end of song) orders are stored as 0xFFFF.