<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.openmpt.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=CS127</id>
	<title>OpenMPT Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.openmpt.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=CS127"/>
	<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/Special:Contributions/CS127"/>
	<updated>2026-05-01T14:59:44Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4976</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4976"/>
		<updated>2025-09-05T17:09:41Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Extended Pattern */ remove non-PC note info, since non-PC notes are now removed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). For older versions, check [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&amp;lt;!-- Impulse Tracker 8 lol --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions).&lt;br /&gt;
&lt;br /&gt;
The chunk contains settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
Other MPTM features (e.g. fractional tempos) use [[Development:_OpenMPT_Format_Extensions|regular OpenMPT extensions]].&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format, &#039;&#039;&#039;even floating-point numbers&#039;&#039;&#039;):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit (single-precision) IEEE-754 floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character (text encoding may vary, so a single character is not necessarily one byte).&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, &amp;quot;Windows codepage&amp;quot; refers to the user&#039;s selected ACP codepage in Windows (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to [[Wikipedia:Windows-1252|1252]], but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether this chunk&#039;s descriptions (explained later) use a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for each entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, the string uses use a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;. Otherwise, they have to be stored in the same order that OpenMPT reads them.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, the string uses a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt;, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Windows codepage.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection (or &amp;quot;pattern container&amp;quot; according to the source code) is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data, which will be merged onto the IT pattern data when the file is read.&amp;lt;br/&amp;gt;&lt;br /&gt;
Technically, it can be used for storing any pattern data, but OpenMPT uses it for storing only the Parameter Control notes of each pattern.&amp;lt;/br&amp;gt;&lt;br /&gt;
The data is stored in the same format as the [https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT#impulse-pattern-format IT pattern format], but without the first 8 bytes, and with a different format for mask bytes:&amp;lt;br/&amp;gt;&lt;br /&gt;
* Bit 0: Include note (PC: &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;, PCs: &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Bit 1: Include plugin number&lt;br /&gt;
* Bit 2: Include high byte of controller ID&lt;br /&gt;
* Bit 3: Include low byte of controller ID&lt;br /&gt;
* Bit 4: Include high byte of parameter&lt;br /&gt;
* Bit 5: Include low byte of parameter&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: Include extra data&amp;lt;/span&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: Windows codepage.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;t&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| 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.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Default speed (ticks per row).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
first version completed: 2022-02-28&lt;br /&gt;
last edit:               2023-02-28&lt;br /&gt;
&lt;br /&gt;
1 year!&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_Formats/IT&amp;diff=4958</id>
		<title>Development: Formats/IT</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_Formats/IT&amp;diff=4958"/>
		<updated>2025-07-11T01:27:14Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* ModPlug Tracker */ more precise upper limit, see https://modarchive.org/module.php?165622&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;General information concerning the IT file format. Any variable names in this document refer to the original variable names from [https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT ITTECH.TXT]. Variable names and hexadecimal numbers (in little-endian formats) are indicated by a &amp;lt;tt&amp;gt;monospace font&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note: Impulse tracker is now open source! You can grab the [https://github.com/jthlim/impulse-tracker source code] at GitHub.&lt;br /&gt;
&lt;br /&gt;
== Tracker IDs ==&lt;br /&gt;
&lt;br /&gt;
The IT header contains a field, &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, which is used to identify the application that was used to create the file.&lt;br /&gt;
The following custom tracker IDs (read as little-endian hexadecimal numbers) are known to be found in the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;0xyy&amp;lt;/tt&amp;gt; - Impulse Tracker x.yy - Many other trackers, like ModPlug Tracker, disguise as various versions of Impulse Tracker, so this is &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; a reliable way to tell if a file was really made with Impulse Tracker. See [[#Detecting other trackers|below]] for detecting such trackers.&lt;br /&gt;
* &amp;lt;tt&amp;gt;1xyy&amp;lt;/tt&amp;gt; - Schism Tracker x.yy up to Schism Tracker v0.50, later versions encode a timestamp in the version number - see Schism Tracker’s &amp;lt;tt&amp;gt;[https://github.com/schismtracker/schismtracker/blob/master/schism/version.c version.c]&amp;lt;/tt&amp;gt; or OpenMPT’s &amp;lt;tt&amp;gt;[https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/soundlib/Load_it.cpp Load_it.cpp]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;4xyy&amp;lt;/tt&amp;gt; - pyIT x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;5xyy&amp;lt;/tt&amp;gt; - OpenMPT x.yy - lower two bytes of version number are stored in the &amp;quot;reserved&amp;quot; header field starting from OpenMPT 1.29.10.00 in compatible mode (otherwise OpenMPT song extensions are used as before).&lt;br /&gt;
* &amp;lt;tt&amp;gt;6xyy&amp;lt;/tt&amp;gt; - BeRoTracker x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;7xyz&amp;lt;/tt&amp;gt; - ITMCK x.y.z (N.B. the user can override the value of the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; header by the &amp;lt;tt&amp;gt;-w&amp;lt;/tt&amp;gt; command-line switch or the &amp;lt;tt&amp;gt;#TRACKER-VERSION&amp;lt;/tt&amp;gt; command in the input file)&lt;br /&gt;
* &amp;lt;tt&amp;gt;7FFF&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt = 0215&amp;lt;/tt&amp;gt;: munch.py&lt;br /&gt;
* &amp;lt;tt&amp;gt;8xyy&amp;lt;/tt&amp;gt; - Tralala x.yy; prealpha versions, built from svn, before the first release identify as version 0.00 (i.e. Cwt/v=8000)&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cxyy&amp;lt;/tt&amp;gt; - ChickDune ChipTune Tracker x.yy (currently non-public alpha version)&lt;br /&gt;
* &amp;lt;tt&amp;gt;DAEB&amp;lt;/tt&amp;gt; - spc2it (after commit d3d1b524032f668be8ee20d25339e1c635fb9bcf)&lt;br /&gt;
* &amp;lt;tt&amp;gt;D1CE&amp;lt;/tt&amp;gt; - [https://github.com/chr15m/itwriter itwriter] JavaScript library (user can change this default)&lt;br /&gt;
&lt;br /&gt;
Are you a tracker developer and your tracker can save IT files? Please add your Tracker ID to this list!&lt;br /&gt;
&lt;br /&gt;
Once we run out of tracker IDs, a more sophisticated approach will have to be found. For example, the ID &amp;lt;tt&amp;gt;0FFF&amp;lt;/tt&amp;gt; could be reserved, and a pointer to extended tracker information could be placed in the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; header field.&lt;br /&gt;
&lt;br /&gt;
== Detecting other trackers ==&lt;br /&gt;
&lt;br /&gt;
Some trackers disguise as Impulse Tracker 2, but there are ways to uncover this disguise:&lt;br /&gt;
&lt;br /&gt;
=== BeRoTracker ===&lt;br /&gt;
&lt;br /&gt;
Earlier versions of BeRoTracker, which did not use the tracker ID described above, can be identified by the four byte &amp;lt;tt&amp;gt;MODU&amp;lt;/tt&amp;gt; magic which can be found after the Edit History / MIDI Macro / ModPlug extension block. &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0217&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt; (overlaps with ModPlug Tracker). The edit history flag is set and there are always 0 entries in the edit history.&lt;br /&gt;
&lt;br /&gt;
=== CheeseTracker ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are both &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Instrument mode flag is always set. The only other flags that can be optionally set are: Stereo Mode, Linear Slides, Old Effects, Compatible Gxx.&lt;br /&gt;
* The only &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag ever set is the song message flag (even though row highlights are always written).&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;&lt;br /&gt;
* All sample and instrument filenames read &amp;lt;tt&amp;gt;XXXXXXXX.YYY&amp;lt;/tt&amp;gt; (obviously this should not be used as a stand-alone detection criterion, as files re-saved with other trackers will still use these filenames).&lt;br /&gt;
&lt;br /&gt;
=== ChibiTracker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are both &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; reads &amp;lt;tt&amp;gt;CHBI&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Further interesting criteria: Sample data is stored directly after header. All sample and instrument filenames read &amp;lt;tt&amp;gt;-DEPRECATED-&amp;lt;/tt&amp;gt; (obviously this should not be used as a stand-alone detection criterion, as files re-saved with other trackers will still use these filenames). ChibiTracker also uses a line feed character (&amp;lt;tt&amp;gt;0A&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt;) instead of a carriage return (&amp;lt;tt&amp;gt;0D&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\r&amp;lt;/tt&amp;gt;) in the song message.&lt;br /&gt;
&lt;br /&gt;
=== ModPlug Tracker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 pre-alpha 4 (and possibly earlier) - 1.0 alpha 4&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0202&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, row highlights are both 0. These attributes alone are not enough to fingerprint these ModPlug Tracker versions, but luckily it also stores the remaining data in a very peculiar order: patterns first, then instrument headers, and then interleaves sample headers and their corresponding sample data. These versions also do not optimize empty 64-row patterns with a 0 parapointer, so they can be identified by checking if the first pattern parapointer is not 0 and less than the first sample parapointer.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 alpha 5&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Pattern highlights and edit history flags are not set. Instruments are 560 bytes apart.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 alpha 6 / beta 1 / beta 2&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Pattern highlights and edit history flags are set. Instruments are 560 bytes apart up to and including beta 1, in beta 2 they are 557 bytes apart.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 beta 3.2 - 1.09 build 66 (possibly up to build 77)&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0202&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Instruments are 557 bytes apart.&lt;br /&gt;
* Newer versions of &#039;&#039;&#039;ModPlug Tracker&#039;&#039;&#039;, &#039;&#039;&#039;OpenMPT 1.17 in compatible mode&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0217&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. If there are any instruments in the file, the instrument &amp;lt;tt&amp;gt;TrkVers&amp;lt;/tt&amp;gt; field is &amp;lt;tt&amp;gt;0211&amp;lt;/tt&amp;gt; for ModPlug Tracker and &amp;lt;tt&amp;gt;0220&amp;lt;/tt&amp;gt; for OpenMPT. ModPlug Tracker writes &amp;lt;tt&amp;gt;FF&amp;lt;/tt&amp;gt; for unused channels in the panning map, OpenMPT never does this. When an IT file uses all 64 channels (so the panning map cannot be used for distinction), the presence of ModPlug extensions (channel names, plugin chunks, etc.) can help telling MPT 1.16 and OpenMPT 1.17 compatibility export apart. The latter also does not save a final &amp;quot;---&amp;quot; order list item, while MPT 1.16 does.&lt;br /&gt;
&lt;br /&gt;
=== OpenMPT ===&lt;br /&gt;
&lt;br /&gt;
* OpenMPT 1.17.02.20 to OpenMPT 1.17.02.25 wrote the value &amp;lt;tt&amp;gt;0300&amp;lt;/tt&amp;gt; in both the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; fields.&lt;br /&gt;
* OpenMPT 1.17.02.26 to OpenMPT 1.18 wrote the value &amp;lt;tt&amp;gt;0888&amp;lt;/tt&amp;gt; in both the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; fields.&lt;br /&gt;
* Later versions of OpenMPT use the tracker ID provided above. In that case, the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; field reads &amp;lt;tt&amp;gt;OMPT&amp;lt;/tt&amp;gt; if the file was saved in normal mode, and is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (or the lower two bytes of version information starting from OpenMPT 1.29.10.00) if it was saved in compatible mode.&lt;br /&gt;
&lt;br /&gt;
=== OpenSPC conversions ===&lt;br /&gt;
&lt;br /&gt;
OpenSPC is a tool to convert SNES music from the SPC format to the IT format. If all the following conditions are true, you can be fairly sure that a module was written with OpenSPC:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;09&amp;lt;/tt&amp;gt; (Linear Slides, Stereo Playback).&lt;br /&gt;
* &amp;lt;tt&amp;gt;Special&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Both pattern highlight values are &amp;lt;tt&amp;gt;00&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* No instruments are used.&lt;br /&gt;
* &amp;lt;tt&amp;gt;PatNum&amp;lt;/tt&amp;gt; + 1 == &amp;lt;tt&amp;gt;OrdNum&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Global volume is 128 decimal.&lt;br /&gt;
* Master volume is 100 decimal.&lt;br /&gt;
* Initial Speed is 1.&lt;br /&gt;
* Pan Separation is 128 decimal.&lt;br /&gt;
* Pitch wheel depth is 0.&lt;br /&gt;
* There is no song message, i.e. message length and offset are 0.&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is 0.&lt;br /&gt;
&lt;br /&gt;
Earlier versions of spc2it (before commit d3d1b524032f668be8ee20d25339e1c635fb9bcf) will be mis-identified as OpenSPC, as the tool closely follows the way its predecessor writes out IT files.&lt;br /&gt;
&lt;br /&gt;
=== Unknown XM to IT conversion tool ===&lt;br /&gt;
&lt;br /&gt;
There is a currently unknown XM to IT conversion tool which can be identified easily by the fact that it writes unsigned samples (which was the default only until Impulse Tracker 2.01). However, only sample slots with actual sample data should be considered for this test, as re-saving such a file in Impulse Tracker will not reset the unsigned flag for empty slots. If the following conditions are true, you can be fairly sure that a module was written with the unknown converter:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0204&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt;: Stereo Playback, Instrument Mode, Old Effects are always set, Linear Slides are optional.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Special&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Both pattern highlight values are &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Global volume is 128 decimal.&lt;br /&gt;
* Master volume is 48 decimal.&lt;br /&gt;
* Pan Separation is 128 decimal.&lt;br /&gt;
* Pitch wheel depth is 0.&lt;br /&gt;
* There is no song message, i.e. message length and offset are 0.&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is 0.&lt;br /&gt;
* Song title is no longer than 20 characters.&lt;br /&gt;
* All channels are panned centre (32) or muted, and their volume is 64 decimal.&lt;br /&gt;
&lt;br /&gt;
To be extra sure, you can check all of these properties, but just checking &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; and unsigned sample data is probably enough.&lt;br /&gt;
&lt;br /&gt;
=== UNMO3 ===&lt;br /&gt;
&lt;br /&gt;
UNMO3 is a tool to convert an MO3-compressed module file back into its original format.&lt;br /&gt;
&lt;br /&gt;
In IT files created with UNMO3, the following are always true:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;pwd&amp;lt;/tt&amp;gt; is 0&lt;br /&gt;
* Both row highlights are 0&lt;br /&gt;
* Flags: Use MIDI Pitch Controller (bit 6) and Request embedded MIDI configuration (bit 7) are never set&lt;br /&gt;
&lt;br /&gt;
This partially overlaps with Impulse Tracker 2.14 and CheeseTracker fingerprints, however:&lt;br /&gt;
* CheeseTracker should write non-zero row highlights, even when resaving an UNMO3-ed file.&lt;br /&gt;
* It is highly unlikely that Impulse Tracker 2.14 writes a &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; value of &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. If it writes zero row highlights, the row highlight &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag is set.&lt;br /&gt;
* Impulse Tracker 2.14 never writes an empty edit history (see below).&lt;br /&gt;
* CheeseTracker always uses instrument mode.&lt;br /&gt;
&lt;br /&gt;
Some older versions of UNMO3 write out IT files that are malformed in some way or another, but it is easy to detect and work around. Some UNMO3-ed IT files are floating around in the wild, so it may be worthwile to implement those work-arounds:&lt;br /&gt;
&lt;br /&gt;
==== Special flags prior UNMO3 2.4.0.2 ====&lt;br /&gt;
&lt;br /&gt;
* UNMO3 2.4 (released in 2008) and older sets the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag bits 1 (edit history) and 2 (row highlights) whenever bit 3 (MIDI macros) is set as well.&lt;br /&gt;
* UNMO3 2.4.0.1 (January 2011) always sets the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag bit 1 (edit history), but the behaviour for bit 2 (row highlights) remains as in previous versions.&lt;br /&gt;
* UNMO3 2.4.0.2 (July 2011) never sets the row highlights flag.&lt;br /&gt;
&lt;br /&gt;
==== Sample mode prior to UNMO3 2.4.0.1 ====&lt;br /&gt;
&lt;br /&gt;
UNMO3 2.4 and older reserves space for the instrument parapointers (as many as there are samples) even when the IT file is in sample mode. This can be detected by the fact that 4 * &amp;lt;tt&amp;gt;SmpNum&amp;lt;/tt&amp;gt; zero bytes follow after the pattern parapointers. These bytes need to be skipped in order to be able to read MIDI macros and ModPlug plugin settings which may potentially follow.&lt;br /&gt;
&lt;br /&gt;
UNMO3 2.4.0.1 fixes this problem.&lt;br /&gt;
&lt;br /&gt;
==== Edit History prior to UNMO3 2.4.0.1 ====&lt;br /&gt;
&lt;br /&gt;
As mentioned above, UNMO3 older than version 2.4.0.1 may or may not set the edit history flag, but they always write two edit history length bytes (zeroes) in the file anyway. Keep this in mind, as MIDI Macros and ModPlug plugin settings will not load properly if you don’t.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Edit history flag is set&#039;&#039;&#039;: Nothing needs to be done. We can still use this for identifying UNMO3-saved IT files, because Impulse Tracker never writes an edit history of length 0.&lt;br /&gt;
* &#039;&#039;&#039;Edit history flag is not set&#039;&#039;&#039;: This is the troublesome case due to MIDI macros and plugin settings. However, a reliable way to detect such malformed IT files would be to try to read the edit history length if all of the above detection criteria for UNMO3 are fulfilled. For those old UNMO3 versions, you should read two zero bytes. If that is the case, it means that the first MIDI macro would be empty (if MIDI macros are embedded) or the first plugin chunk ID starts with two zero bytes (impossible). Since UNMO3 writes out default values for the nine global MIDI macros, the first MIDI macro would have to start with “FF” (MIDI Start) and not be empty, so it is clear that the two zero bytes belong to the (empty) edit history.&lt;br /&gt;
&lt;br /&gt;
Later version of UNMO3 set the correct header flag for the edit history and write the two zero length bytes.&lt;br /&gt;
&lt;br /&gt;
== Special Header Flags ==&lt;br /&gt;
&lt;br /&gt;
The following &amp;quot;Special&amp;quot; flags are not documented:&lt;br /&gt;
&lt;br /&gt;
* Bit 1 (&amp;lt;tt&amp;gt;02&amp;lt;/tt&amp;gt;): If set, edit history information (see [[#Edit History|below]]) is present.&lt;br /&gt;
* Bit 2 (&amp;lt;tt&amp;gt;04&amp;lt;/tt&amp;gt;): If set, the row highlights (at offset &amp;lt;tt&amp;gt;1E&amp;lt;/tt&amp;gt; - &amp;lt;tt&amp;gt;1F&amp;lt;/tt&amp;gt;) should be read. If not set, they should be ignored.&lt;br /&gt;
&lt;br /&gt;
== Edit History ==&lt;br /&gt;
    &lt;br /&gt;
It is little known that Impulse Tracker 2.08 and later keep track of when an IT file is opened and how long it is left open.&lt;br /&gt;
The edit history can be found directly after the IT header and before the possibly present MIDI macro configuration.&lt;br /&gt;
&lt;br /&gt;
A 16-Bit integer &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; tells how many edit history blocks are present. Every block is 8 bytes long, so the 16-bit integer is followed by &amp;lt;tt&amp;gt;8 * num&amp;lt;/tt&amp;gt; bytes of edit history information.&lt;br /&gt;
&lt;br /&gt;
Each history block consists of a 16-Bit FAT date, a 16-Bit FAT time and a 32-Bit DOS timer, which contains the time how long the file was open in the editor, in 1/18.2th seconds.&lt;br /&gt;
Information on how to decode the FAT date and time stamps can be found on the [https://msdn.microsoft.com/en-us/library/windows/desktop/ms724247%28v=vs.85%29.aspx MSDN].&lt;br /&gt;
&lt;br /&gt;
Note: Many programs don’t write an edit history, but they set the edit history flag in the header and write the two zero bytes for the history length. Many of them also ignore the edit history flag when loading files and always read the two &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; num bytes (ignoring the special flag), so if you want to write out an IT file that does not have an edit history and do not mind about the two extra bytes, the safest (most compatible) way is to set the edit history flag and write two zero bytes for &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Also note that none of this is really relevant if you are sure that you never write out the MIDI macro configuration or ModPlug extensions, since these are the only two things that could normally follow the edit history. So if you have no MIDI macros and no ModPlug extensions, it is always safe to not set the special flag and not write the two extra bytes.&lt;br /&gt;
&lt;br /&gt;
== Edit Timer ==&lt;br /&gt;
&lt;br /&gt;
Before the addition of the full Edit History, a simple Edit Timer was stored in the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; field of the file header. Starting from Impulse Tracker 2.07, this field contains the total edit time as a 32-Bit DOS timer (same resolution as in the Edit History). Starting from Impulse Tracker 2.08, the timer is encrypted. To decrypt:&lt;br /&gt;
&lt;br /&gt;
 editTime = editTime XOR &#039;ITRK&#039;&lt;br /&gt;
 editTime = editTime RoR 7&lt;br /&gt;
 editTime = -editTime&lt;br /&gt;
 editTime = editTime RoL 4&lt;br /&gt;
 editTime = editTime XOR &#039;JTHL&#039;&lt;br /&gt;
&lt;br /&gt;
== Proposed way to store compressed stereo samples ==&lt;br /&gt;
&lt;br /&gt;
Since Impulse Tracker itself does not support stereo samples, a common way of how to decode compressed stereo samples had to be found - After all, it is possible to just treat them as one continuous stream (not stopping the encoding / decoding process after the end of the left channel), or to treat them as two separate, consecutive streams. XMPlay was probably the only player that could handle compressed stereo samples even before there was a single implementation for saving compressed stereo samples. GreaseMonkey has decided to follow [https://www.un4seen.com/forum/?topic=12448.msg86479#msg86479 XMPlay&#039;s way] of decoding compressed stereo samples by treating them as two streams of the same length, so OpenMPT follows this example. If you intend to add IT sample compression support in your application, you should do the same to ensure compatibility across as many applications as possible.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Hacks ==&lt;br /&gt;
&lt;br /&gt;
For a list of all the file format hacks that ModPlug Tracker / OpenMPT added to the IT format over the years, see the [[Development: OpenMPT Format Extensions|OpenMPT Format Extensions]] article.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Formats/IT]]&lt;br /&gt;
[[Category:IT Format|Format Specification]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_Formats/IT&amp;diff=4957</id>
		<title>Development: Formats/IT</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_Formats/IT&amp;diff=4957"/>
		<updated>2025-07-11T01:21:50Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* ModPlug Tracker */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;General information concerning the IT file format. Any variable names in this document refer to the original variable names from [https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT ITTECH.TXT]. Variable names and hexadecimal numbers (in little-endian formats) are indicated by a &amp;lt;tt&amp;gt;monospace font&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note: Impulse tracker is now open source! You can grab the [https://github.com/jthlim/impulse-tracker source code] at GitHub.&lt;br /&gt;
&lt;br /&gt;
== Tracker IDs ==&lt;br /&gt;
&lt;br /&gt;
The IT header contains a field, &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, which is used to identify the application that was used to create the file.&lt;br /&gt;
The following custom tracker IDs (read as little-endian hexadecimal numbers) are known to be found in the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;0xyy&amp;lt;/tt&amp;gt; - Impulse Tracker x.yy - Many other trackers, like ModPlug Tracker, disguise as various versions of Impulse Tracker, so this is &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; a reliable way to tell if a file was really made with Impulse Tracker. See [[#Detecting other trackers|below]] for detecting such trackers.&lt;br /&gt;
* &amp;lt;tt&amp;gt;1xyy&amp;lt;/tt&amp;gt; - Schism Tracker x.yy up to Schism Tracker v0.50, later versions encode a timestamp in the version number - see Schism Tracker’s &amp;lt;tt&amp;gt;[https://github.com/schismtracker/schismtracker/blob/master/schism/version.c version.c]&amp;lt;/tt&amp;gt; or OpenMPT’s &amp;lt;tt&amp;gt;[https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/soundlib/Load_it.cpp Load_it.cpp]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;4xyy&amp;lt;/tt&amp;gt; - pyIT x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;5xyy&amp;lt;/tt&amp;gt; - OpenMPT x.yy - lower two bytes of version number are stored in the &amp;quot;reserved&amp;quot; header field starting from OpenMPT 1.29.10.00 in compatible mode (otherwise OpenMPT song extensions are used as before).&lt;br /&gt;
* &amp;lt;tt&amp;gt;6xyy&amp;lt;/tt&amp;gt; - BeRoTracker x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;7xyz&amp;lt;/tt&amp;gt; - ITMCK x.y.z (N.B. the user can override the value of the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; header by the &amp;lt;tt&amp;gt;-w&amp;lt;/tt&amp;gt; command-line switch or the &amp;lt;tt&amp;gt;#TRACKER-VERSION&amp;lt;/tt&amp;gt; command in the input file)&lt;br /&gt;
* &amp;lt;tt&amp;gt;7FFF&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt = 0215&amp;lt;/tt&amp;gt;: munch.py&lt;br /&gt;
* &amp;lt;tt&amp;gt;8xyy&amp;lt;/tt&amp;gt; - Tralala x.yy; prealpha versions, built from svn, before the first release identify as version 0.00 (i.e. Cwt/v=8000)&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cxyy&amp;lt;/tt&amp;gt; - ChickDune ChipTune Tracker x.yy (currently non-public alpha version)&lt;br /&gt;
* &amp;lt;tt&amp;gt;DAEB&amp;lt;/tt&amp;gt; - spc2it (after commit d3d1b524032f668be8ee20d25339e1c635fb9bcf)&lt;br /&gt;
* &amp;lt;tt&amp;gt;D1CE&amp;lt;/tt&amp;gt; - [https://github.com/chr15m/itwriter itwriter] JavaScript library (user can change this default)&lt;br /&gt;
&lt;br /&gt;
Are you a tracker developer and your tracker can save IT files? Please add your Tracker ID to this list!&lt;br /&gt;
&lt;br /&gt;
Once we run out of tracker IDs, a more sophisticated approach will have to be found. For example, the ID &amp;lt;tt&amp;gt;0FFF&amp;lt;/tt&amp;gt; could be reserved, and a pointer to extended tracker information could be placed in the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; header field.&lt;br /&gt;
&lt;br /&gt;
== Detecting other trackers ==&lt;br /&gt;
&lt;br /&gt;
Some trackers disguise as Impulse Tracker 2, but there are ways to uncover this disguise:&lt;br /&gt;
&lt;br /&gt;
=== BeRoTracker ===&lt;br /&gt;
&lt;br /&gt;
Earlier versions of BeRoTracker, which did not use the tracker ID described above, can be identified by the four byte &amp;lt;tt&amp;gt;MODU&amp;lt;/tt&amp;gt; magic which can be found after the Edit History / MIDI Macro / ModPlug extension block. &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0217&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt; (overlaps with ModPlug Tracker). The edit history flag is set and there are always 0 entries in the edit history.&lt;br /&gt;
&lt;br /&gt;
=== CheeseTracker ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are both &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Instrument mode flag is always set. The only other flags that can be optionally set are: Stereo Mode, Linear Slides, Old Effects, Compatible Gxx.&lt;br /&gt;
* The only &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag ever set is the song message flag (even though row highlights are always written).&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;&lt;br /&gt;
* All sample and instrument filenames read &amp;lt;tt&amp;gt;XXXXXXXX.YYY&amp;lt;/tt&amp;gt; (obviously this should not be used as a stand-alone detection criterion, as files re-saved with other trackers will still use these filenames).&lt;br /&gt;
&lt;br /&gt;
=== ChibiTracker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are both &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; reads &amp;lt;tt&amp;gt;CHBI&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Further interesting criteria: Sample data is stored directly after header. All sample and instrument filenames read &amp;lt;tt&amp;gt;-DEPRECATED-&amp;lt;/tt&amp;gt; (obviously this should not be used as a stand-alone detection criterion, as files re-saved with other trackers will still use these filenames). ChibiTracker also uses a line feed character (&amp;lt;tt&amp;gt;0A&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt;) instead of a carriage return (&amp;lt;tt&amp;gt;0D&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\r&amp;lt;/tt&amp;gt;) in the song message.&lt;br /&gt;
&lt;br /&gt;
=== ModPlug Tracker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 pre-alpha 4 (and possibly earlier) - 1.0 alpha 4&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0202&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, row highlights are both 0. These attributes alone are not enough to fingerprint these ModPlug Tracker versions, but luckily it also stores the remaining data in a very peculiar order: patterns first, then instrument headers, and then interleaves sample headers and their corresponding sample data. These versions also do not optimize empty 64-row patterns with a 0 parapointer, so they can be identified by checking if the first pattern parapointer is not 0 and less than the first sample parapointer.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 alpha 5&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Pattern highlights and edit history flags are not set. Instruments are 560 bytes apart.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 alpha 6 / beta 1 / beta 2&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Pattern highlights and edit history flags are set. Instruments are 560 bytes apart up to and including beta 1, in beta 2 they are 557 bytes apart.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 beta 3.2 - 1.09 build 66 (possibly up to build 89)&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0202&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Instruments are 557 bytes apart.&lt;br /&gt;
* Newer versions of &#039;&#039;&#039;ModPlug Tracker&#039;&#039;&#039;, &#039;&#039;&#039;OpenMPT 1.17 in compatible mode&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0217&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. If there are any instruments in the file, the instrument &amp;lt;tt&amp;gt;TrkVers&amp;lt;/tt&amp;gt; field is &amp;lt;tt&amp;gt;0211&amp;lt;/tt&amp;gt; for ModPlug Tracker and &amp;lt;tt&amp;gt;0220&amp;lt;/tt&amp;gt; for OpenMPT. ModPlug Tracker writes &amp;lt;tt&amp;gt;FF&amp;lt;/tt&amp;gt; for unused channels in the panning map, OpenMPT never does this. When an IT file uses all 64 channels (so the panning map cannot be used for distinction), the presence of ModPlug extensions (channel names, plugin chunks, etc.) can help telling MPT 1.16 and OpenMPT 1.17 compatibility export apart. The latter also does not save a final &amp;quot;---&amp;quot; order list item, while MPT 1.16 does.&lt;br /&gt;
&lt;br /&gt;
=== OpenMPT ===&lt;br /&gt;
&lt;br /&gt;
* OpenMPT 1.17.02.20 to OpenMPT 1.17.02.25 wrote the value &amp;lt;tt&amp;gt;0300&amp;lt;/tt&amp;gt; in both the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; fields.&lt;br /&gt;
* OpenMPT 1.17.02.26 to OpenMPT 1.18 wrote the value &amp;lt;tt&amp;gt;0888&amp;lt;/tt&amp;gt; in both the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; fields.&lt;br /&gt;
* Later versions of OpenMPT use the tracker ID provided above. In that case, the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; field reads &amp;lt;tt&amp;gt;OMPT&amp;lt;/tt&amp;gt; if the file was saved in normal mode, and is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (or the lower two bytes of version information starting from OpenMPT 1.29.10.00) if it was saved in compatible mode.&lt;br /&gt;
&lt;br /&gt;
=== OpenSPC conversions ===&lt;br /&gt;
&lt;br /&gt;
OpenSPC is a tool to convert SNES music from the SPC format to the IT format. If all the following conditions are true, you can be fairly sure that a module was written with OpenSPC:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;09&amp;lt;/tt&amp;gt; (Linear Slides, Stereo Playback).&lt;br /&gt;
* &amp;lt;tt&amp;gt;Special&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Both pattern highlight values are &amp;lt;tt&amp;gt;00&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* No instruments are used.&lt;br /&gt;
* &amp;lt;tt&amp;gt;PatNum&amp;lt;/tt&amp;gt; + 1 == &amp;lt;tt&amp;gt;OrdNum&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Global volume is 128 decimal.&lt;br /&gt;
* Master volume is 100 decimal.&lt;br /&gt;
* Initial Speed is 1.&lt;br /&gt;
* Pan Separation is 128 decimal.&lt;br /&gt;
* Pitch wheel depth is 0.&lt;br /&gt;
* There is no song message, i.e. message length and offset are 0.&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is 0.&lt;br /&gt;
&lt;br /&gt;
Earlier versions of spc2it (before commit d3d1b524032f668be8ee20d25339e1c635fb9bcf) will be mis-identified as OpenSPC, as the tool closely follows the way its predecessor writes out IT files.&lt;br /&gt;
&lt;br /&gt;
=== Unknown XM to IT conversion tool ===&lt;br /&gt;
&lt;br /&gt;
There is a currently unknown XM to IT conversion tool which can be identified easily by the fact that it writes unsigned samples (which was the default only until Impulse Tracker 2.01). However, only sample slots with actual sample data should be considered for this test, as re-saving such a file in Impulse Tracker will not reset the unsigned flag for empty slots. If the following conditions are true, you can be fairly sure that a module was written with the unknown converter:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0204&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt;: Stereo Playback, Instrument Mode, Old Effects are always set, Linear Slides are optional.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Special&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Both pattern highlight values are &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Global volume is 128 decimal.&lt;br /&gt;
* Master volume is 48 decimal.&lt;br /&gt;
* Pan Separation is 128 decimal.&lt;br /&gt;
* Pitch wheel depth is 0.&lt;br /&gt;
* There is no song message, i.e. message length and offset are 0.&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is 0.&lt;br /&gt;
* Song title is no longer than 20 characters.&lt;br /&gt;
* All channels are panned centre (32) or muted, and their volume is 64 decimal.&lt;br /&gt;
&lt;br /&gt;
To be extra sure, you can check all of these properties, but just checking &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; and unsigned sample data is probably enough.&lt;br /&gt;
&lt;br /&gt;
=== UNMO3 ===&lt;br /&gt;
&lt;br /&gt;
UNMO3 is a tool to convert an MO3-compressed module file back into its original format.&lt;br /&gt;
&lt;br /&gt;
In IT files created with UNMO3, the following are always true:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;pwd&amp;lt;/tt&amp;gt; is 0&lt;br /&gt;
* Both row highlights are 0&lt;br /&gt;
* Flags: Use MIDI Pitch Controller (bit 6) and Request embedded MIDI configuration (bit 7) are never set&lt;br /&gt;
&lt;br /&gt;
This partially overlaps with Impulse Tracker 2.14 and CheeseTracker fingerprints, however:&lt;br /&gt;
* CheeseTracker should write non-zero row highlights, even when resaving an UNMO3-ed file.&lt;br /&gt;
* It is highly unlikely that Impulse Tracker 2.14 writes a &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; value of &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. If it writes zero row highlights, the row highlight &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag is set.&lt;br /&gt;
* Impulse Tracker 2.14 never writes an empty edit history (see below).&lt;br /&gt;
* CheeseTracker always uses instrument mode.&lt;br /&gt;
&lt;br /&gt;
Some older versions of UNMO3 write out IT files that are malformed in some way or another, but it is easy to detect and work around. Some UNMO3-ed IT files are floating around in the wild, so it may be worthwile to implement those work-arounds:&lt;br /&gt;
&lt;br /&gt;
==== Special flags prior UNMO3 2.4.0.2 ====&lt;br /&gt;
&lt;br /&gt;
* UNMO3 2.4 (released in 2008) and older sets the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag bits 1 (edit history) and 2 (row highlights) whenever bit 3 (MIDI macros) is set as well.&lt;br /&gt;
* UNMO3 2.4.0.1 (January 2011) always sets the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag bit 1 (edit history), but the behaviour for bit 2 (row highlights) remains as in previous versions.&lt;br /&gt;
* UNMO3 2.4.0.2 (July 2011) never sets the row highlights flag.&lt;br /&gt;
&lt;br /&gt;
==== Sample mode prior to UNMO3 2.4.0.1 ====&lt;br /&gt;
&lt;br /&gt;
UNMO3 2.4 and older reserves space for the instrument parapointers (as many as there are samples) even when the IT file is in sample mode. This can be detected by the fact that 4 * &amp;lt;tt&amp;gt;SmpNum&amp;lt;/tt&amp;gt; zero bytes follow after the pattern parapointers. These bytes need to be skipped in order to be able to read MIDI macros and ModPlug plugin settings which may potentially follow.&lt;br /&gt;
&lt;br /&gt;
UNMO3 2.4.0.1 fixes this problem.&lt;br /&gt;
&lt;br /&gt;
==== Edit History prior to UNMO3 2.4.0.1 ====&lt;br /&gt;
&lt;br /&gt;
As mentioned above, UNMO3 older than version 2.4.0.1 may or may not set the edit history flag, but they always write two edit history length bytes (zeroes) in the file anyway. Keep this in mind, as MIDI Macros and ModPlug plugin settings will not load properly if you don’t.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Edit history flag is set&#039;&#039;&#039;: Nothing needs to be done. We can still use this for identifying UNMO3-saved IT files, because Impulse Tracker never writes an edit history of length 0.&lt;br /&gt;
* &#039;&#039;&#039;Edit history flag is not set&#039;&#039;&#039;: This is the troublesome case due to MIDI macros and plugin settings. However, a reliable way to detect such malformed IT files would be to try to read the edit history length if all of the above detection criteria for UNMO3 are fulfilled. For those old UNMO3 versions, you should read two zero bytes. If that is the case, it means that the first MIDI macro would be empty (if MIDI macros are embedded) or the first plugin chunk ID starts with two zero bytes (impossible). Since UNMO3 writes out default values for the nine global MIDI macros, the first MIDI macro would have to start with “FF” (MIDI Start) and not be empty, so it is clear that the two zero bytes belong to the (empty) edit history.&lt;br /&gt;
&lt;br /&gt;
Later version of UNMO3 set the correct header flag for the edit history and write the two zero length bytes.&lt;br /&gt;
&lt;br /&gt;
== Special Header Flags ==&lt;br /&gt;
&lt;br /&gt;
The following &amp;quot;Special&amp;quot; flags are not documented:&lt;br /&gt;
&lt;br /&gt;
* Bit 1 (&amp;lt;tt&amp;gt;02&amp;lt;/tt&amp;gt;): If set, edit history information (see [[#Edit History|below]]) is present.&lt;br /&gt;
* Bit 2 (&amp;lt;tt&amp;gt;04&amp;lt;/tt&amp;gt;): If set, the row highlights (at offset &amp;lt;tt&amp;gt;1E&amp;lt;/tt&amp;gt; - &amp;lt;tt&amp;gt;1F&amp;lt;/tt&amp;gt;) should be read. If not set, they should be ignored.&lt;br /&gt;
&lt;br /&gt;
== Edit History ==&lt;br /&gt;
    &lt;br /&gt;
It is little known that Impulse Tracker 2.08 and later keep track of when an IT file is opened and how long it is left open.&lt;br /&gt;
The edit history can be found directly after the IT header and before the possibly present MIDI macro configuration.&lt;br /&gt;
&lt;br /&gt;
A 16-Bit integer &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; tells how many edit history blocks are present. Every block is 8 bytes long, so the 16-bit integer is followed by &amp;lt;tt&amp;gt;8 * num&amp;lt;/tt&amp;gt; bytes of edit history information.&lt;br /&gt;
&lt;br /&gt;
Each history block consists of a 16-Bit FAT date, a 16-Bit FAT time and a 32-Bit DOS timer, which contains the time how long the file was open in the editor, in 1/18.2th seconds.&lt;br /&gt;
Information on how to decode the FAT date and time stamps can be found on the [https://msdn.microsoft.com/en-us/library/windows/desktop/ms724247%28v=vs.85%29.aspx MSDN].&lt;br /&gt;
&lt;br /&gt;
Note: Many programs don’t write an edit history, but they set the edit history flag in the header and write the two zero bytes for the history length. Many of them also ignore the edit history flag when loading files and always read the two &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; num bytes (ignoring the special flag), so if you want to write out an IT file that does not have an edit history and do not mind about the two extra bytes, the safest (most compatible) way is to set the edit history flag and write two zero bytes for &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Also note that none of this is really relevant if you are sure that you never write out the MIDI macro configuration or ModPlug extensions, since these are the only two things that could normally follow the edit history. So if you have no MIDI macros and no ModPlug extensions, it is always safe to not set the special flag and not write the two extra bytes.&lt;br /&gt;
&lt;br /&gt;
== Edit Timer ==&lt;br /&gt;
&lt;br /&gt;
Before the addition of the full Edit History, a simple Edit Timer was stored in the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; field of the file header. Starting from Impulse Tracker 2.07, this field contains the total edit time as a 32-Bit DOS timer (same resolution as in the Edit History). Starting from Impulse Tracker 2.08, the timer is encrypted. To decrypt:&lt;br /&gt;
&lt;br /&gt;
 editTime = editTime XOR &#039;ITRK&#039;&lt;br /&gt;
 editTime = editTime RoR 7&lt;br /&gt;
 editTime = -editTime&lt;br /&gt;
 editTime = editTime RoL 4&lt;br /&gt;
 editTime = editTime XOR &#039;JTHL&#039;&lt;br /&gt;
&lt;br /&gt;
== Proposed way to store compressed stereo samples ==&lt;br /&gt;
&lt;br /&gt;
Since Impulse Tracker itself does not support stereo samples, a common way of how to decode compressed stereo samples had to be found - After all, it is possible to just treat them as one continuous stream (not stopping the encoding / decoding process after the end of the left channel), or to treat them as two separate, consecutive streams. XMPlay was probably the only player that could handle compressed stereo samples even before there was a single implementation for saving compressed stereo samples. GreaseMonkey has decided to follow [https://www.un4seen.com/forum/?topic=12448.msg86479#msg86479 XMPlay&#039;s way] of decoding compressed stereo samples by treating them as two streams of the same length, so OpenMPT follows this example. If you intend to add IT sample compression support in your application, you should do the same to ensure compatibility across as many applications as possible.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Hacks ==&lt;br /&gt;
&lt;br /&gt;
For a list of all the file format hacks that ModPlug Tracker / OpenMPT added to the IT format over the years, see the [[Development: OpenMPT Format Extensions|OpenMPT Format Extensions]] article.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Formats/IT]]&lt;br /&gt;
[[Category:IT Format|Format Specification]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_Formats/S3M&amp;diff=4663</id>
		<title>Development: Formats/S3M</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_Formats/S3M&amp;diff=4663"/>
		<updated>2024-11-09T05:04:46Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tracker IDs */ fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;General information concerning the S3M file format. Variable names and hexadecimal numbers (in little-endian formats) are indicated by a &amp;lt;tt&amp;gt;monospace font&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Tracker IDs ==&lt;br /&gt;
&lt;br /&gt;
The S3M header contains a field, &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, which is used to identify the application that was used to create the file.&lt;br /&gt;
The following custom tracker IDs (read as little-endian hexadecimal numbers) are known to be found in the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;0208&amp;lt;/tt&amp;gt; - Found in some tracks by Yerzmyey, appears to be from a tracker called Akord (Polish localized version of a tracker called Squeak Tracker)&lt;br /&gt;
* &amp;lt;tt&amp;gt;1xyy&amp;lt;/tt&amp;gt; - Scream Tracker x.yy - Many other trackers, like ModPlug Tracker, disguise as Scream Tracker 3.20, so this is &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; a reliable way to tell if a file was really made with Scream Tracker, [[#Detecting trackers disguising as Scream Tracker|see below]].&lt;br /&gt;
* &amp;lt;tt&amp;gt;2xyy&amp;lt;/tt&amp;gt; - Imago Orpheus x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;2013&amp;lt;/tt&amp;gt; - PlayerPRO on little-endian platforms&lt;br /&gt;
* &amp;lt;tt&amp;gt;3xyy&amp;lt;/tt&amp;gt; - Impulse Tracker x.yy. Impulse Tracker v1.03 (and possibly v1.02) writes &amp;lt;tt&amp;gt;3320&amp;lt;/tt&amp;gt;. For even older Impulse Tracker versions, see [[#Early Impulse Tracker versions|below]].&lt;br /&gt;
* &amp;lt;tt&amp;gt;4xyy&amp;lt;/tt&amp;gt; - Schism Tracker x.yy up to Schism Tracker v0.50, later versions encode a timestamp in the version number - see Schism Tracker’s &amp;lt;tt&amp;gt;[https://github.com/schismtracker/schismtracker/blob/master/schism/version.c version.c]&amp;lt;/tt&amp;gt; or OpenMPT’s &amp;lt;tt&amp;gt;[https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/soundlib/Load_it.cpp Load_it.cpp]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;5xyy&amp;lt;/tt&amp;gt; - OpenMPT x.yy - lower two bytes of version number are stored in the two reserved bytes at offset 54 starting from OpenMPT 1.29.10.00.&lt;br /&gt;
* &amp;lt;tt&amp;gt;5xyy&amp;lt;/tt&amp;gt; - Liquid Tracker x.yy - OpenMPT unfortunately shares this tracker ID with Liquid Tracker. Only one S3M file made with Liquid Tracker has been found in the wild. The two programs can be told apart, though: Either by the fact that the full OpenMPT version info is present, or for older OpenMPT versions by checking the ultraclick value (Liquid Tracker writes an ultraclick value of 16, while OpenMPT versions before the addition of the full version information wrote an ultraclick value of 8. Shortly after the full version information was added, the ultraclick value was changed to 16).&lt;br /&gt;
* &amp;lt;tt&amp;gt;57yy&amp;lt;/tt&amp;gt; - NESMusa 7.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;5447&amp;lt;/tt&amp;gt; - Graoumf Tracker (appears as &amp;quot;GT&amp;quot; magic bytes on disk)&lt;br /&gt;
* &amp;lt;tt&amp;gt;6xyy&amp;lt;/tt&amp;gt; - BeRoTracker x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;7xyy&amp;lt;/tt&amp;gt; - CreamTracker x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;CA00&amp;lt;/tt&amp;gt; - Camoto / libgamemusic&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: BeRoTracker used the ID &amp;lt;tt&amp;gt;4100&amp;lt;/tt&amp;gt; since 2004, but has switched to using the &amp;lt;tt&amp;gt;6xyy&amp;lt;/tt&amp;gt; scheme in 2012. Luckily, this version is not used by Schism Tracker, so it is still possible to tell the two trackers apart.&lt;br /&gt;
&lt;br /&gt;
Are you a tracker developer and your tracker can save S3M files? Please add your Tracker ID to this list!&lt;br /&gt;
&lt;br /&gt;
== Detecting trackers disguising as Scream Tracker ==&lt;br /&gt;
&lt;br /&gt;
Some trackers disguise as Scream Tracker 3, but there are ways to uncover this disguise:&lt;br /&gt;
&lt;br /&gt;
=== ModPlug Tracker ===&lt;br /&gt;
&lt;br /&gt;
ModPlug Tracker and OpenMPT up to version 1.17.03.01 identifies as Scream Tracker 3.20 in the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field, but it puts zeroes for the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; field, only ever sets flags &amp;lt;tt&amp;gt;10&amp;lt;/tt&amp;gt; (Amiga Limits) and &amp;lt;tt&amp;gt;40&amp;lt;/tt&amp;gt; (Fast Volume Slides), writes multiples of 16 orders, always saves channel pannings, and writes zero into the ultraclick removal field (Scream Tracker 3 always puts either 16, 24, or 32 there).&lt;br /&gt;
&lt;br /&gt;
ModPlug Tracker versions up to 1.0 alpha 5 can be identified by not setting the stereo bit on the master volume. Versions 1.0 alpha 6 up to 1.16.203 can be told apart from later versions if less than 32 channels are used: In the extended panning table, all channels have bit 5 (use panning) set, even those past the last used channel. Later versions write &amp;lt;tt&amp;gt;08&amp;lt;/tt&amp;gt; (center panning, do not use) for such channels instead.&lt;br /&gt;
&lt;br /&gt;
=== Early Schism Tracker versions ===&lt;br /&gt;
&lt;br /&gt;
Before Schism Tracker switched to using its own tracker ID, it largely used the original ModPlug Tracker source code, so many files may me mis-identified as being made with ModPlug. However, at some point it swtiched to writing multiples of 2 orders instead of 16, so if all the other ModPlug detections are correct, but the order list length is only a multiple of 2, it was most likely Schism Tracker that wrote the file.&lt;br /&gt;
&lt;br /&gt;
Note that there is an automatic conversion of Vic&#039;s soundtrack for Acme&#039;s &amp;quot;Paper&amp;quot; demo which would match these conditions as well; however that conversion writes pattern data before sample headers, which can be used to tell it apart.&lt;br /&gt;
&lt;br /&gt;
=== Early Impulse Tracker versions ===&lt;br /&gt;
&lt;br /&gt;
Impulse Tracker v1.01 (and potentially v1.00 and v1.02) identifies as Scream Tracker 3.20, puts zeros for the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt; fields, and sets flag 8 (zero-volume optimizations). It does not use the channel panning table, which sets it apart from real Scream Tracker 3.20.&lt;br /&gt;
&lt;br /&gt;
=== Velvet Studio / PlayerPRO ===&lt;br /&gt;
&lt;br /&gt;
Velvet Studio and PlayerPRO also pretend to be Scream Tracker 3.20, but write zeroes for &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;flags&amp;lt;/tt&amp;gt;, and do &#039;&#039;&#039;not&#039;&#039;&#039; save channel pannings. Velvet Studio also writes a fairly recognizable LRRL pattern for the channels.&lt;br /&gt;
&lt;br /&gt;
To tell the two trackers apart: PlayerPRO always writes a global volume of 64 and a mix volume of 48 (mono). On the other hand, Velvet Studio always writes the stereo flag.&lt;br /&gt;
&lt;br /&gt;
PlayerPRO also writes an extra 16 bytes of padding between sample headers.&lt;br /&gt;
&lt;br /&gt;
=== Sound Club 2 ===&lt;br /&gt;
&lt;br /&gt;
Sound Club two writes &amp;quot;SCLUB2.0&amp;quot; into the 8 consecutive reserved bytes in the file header.&lt;br /&gt;
&lt;br /&gt;
=== UNMO3 ===&lt;br /&gt;
&lt;br /&gt;
Nowadays, the MO3 format has support for storing the original value of the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field, so recent UNMO3 versions make use of this. When this information is not available, or if an older UNMO3 version is used, it can be identified as follows: It pretends to be Scream Tacker 3.01, &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt; are 0, channel pannings are always saved (a feature not supported by Scream Tracker 3.01). The only flags it should ever write are Fast Slides and Amiga Limits. Mix volume should always indicate stereo mixing.&lt;br /&gt;
&lt;br /&gt;
=== deMODifier ===&lt;br /&gt;
&lt;br /&gt;
[https://worrydream.com/iigs/#demodifier deMODifier] is a converter for SoundSmith files to S3M format. It disguises as Scream Tracker 3.01, &amp;lt;tt&amp;gt;flags&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt; are 0, global volume is always 48, mix volume is 176 (48 + stereo), tempo is always 150 and no panning table is present. Sample filenames of non-empty sample slots always end in &amp;lt;code&amp;gt;.IFF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note: This detection should only take place after it can be ruled out that the file was saved with Scream Tracker (see [[#Output driver detection]]).&lt;br /&gt;
&lt;br /&gt;
=== To-S3M ===&lt;br /&gt;
&lt;br /&gt;
[https://files.scene.org/view/resources/music/utils/tos3m100.zip To-S3M] is a converter for MTM modules to S3M format. It disguises as Scream Tracker 3.01, &amp;lt;tt&amp;gt;flags&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt; are 0, global volume is always 64, mix volume is 176 (48 + stereo), speed is always 6, tempo is always 125 and no panning table is present. Files with and without the stereo flag have been spotted, but ignoring that, the mix volume is always 48.&lt;br /&gt;
&lt;br /&gt;
Note: This detection should only take place after it can be ruled out that the file was saved with Scream Tracker (see [[#Output driver detection]]).&lt;br /&gt;
&lt;br /&gt;
=== Detecting other trackers ===&lt;br /&gt;
&lt;br /&gt;
Scream Tracker 3.10 / 3.20 / 3.21 normally only writes 16, 24 or 32 in the &#039;&#039;ultraclick removal&#039;&#039; field (earlier versions write 0 there), so this could be a way to check if a file was &#039;&#039;not&#039;&#039; saved with Scream Tracker 3. However, Scream Tracker does not sanitize this field when re-saving a file made with another tracker, so even if the file was saved with Scream Tracker, a different value might still be carried over from another tracker. See the following section for more reliable fingerprinting.&lt;br /&gt;
&lt;br /&gt;
== Output driver detection ==&lt;br /&gt;
&lt;br /&gt;
Scream Tracker’s Gravis Ultrasound and Sound Blaster drivers differ in their interpretation of various pattern effects, which affects playback of some modules noticeably. Luckily, there is a way to tell which driver was loaded when the S3M file was last saved in Scream Tracker, which can serve as a detection heuristic: If the file was saved with the Gravis Ultrasound driver loaded, every non-empty sample header will have a unique &amp;lt;tt&amp;gt;Int:Gp&amp;lt;/tt&amp;gt; value. If the file was saved with the Sound Blaster driver loaded, every non-empty sample header will have 1 in this field. Note that the first GUS sample also uses address 1, so if there is only one non-empty sample slot, GUS and SB cannot be told apart.&lt;br /&gt;
&lt;br /&gt;
Note that some S3Ms saved with Scream Tracker 3.00 (&amp;lt;tt&amp;gt;cwtv&amp;lt;/tt&amp;gt; = &amp;lt;tt&amp;gt;1300&amp;lt;/tt&amp;gt;) have a &amp;lt;tt&amp;gt;Int:Gp&amp;lt;/tt&amp;gt; value of 0 for all samples. There is probably a very early version of Scream Tracker 3.00 (probably from 1992) which does not support the Gravis Ultrasound. For higher &amp;lt;tt&amp;gt;cwtv&amp;lt;/tt&amp;gt; values, the fact that all &amp;lt;tt&amp;gt;Int:Gp&amp;lt;/tt&amp;gt; values are 0 can be used for detecting other trackers or tools disguising as Scream Tracker (e.g. automatic PSM to S3M conversions).&lt;br /&gt;
&lt;br /&gt;
== Impulse Tracker Edit Timer ==&lt;br /&gt;
&lt;br /&gt;
Impulse Tracker hides its [[Development: Formats/IT#Edit Timer|edit timer]] in the file header; there is a section of 8 reserved bytes, of which the first and last two are zero, and the four bytes in the middle contain the edit timer in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Formats/S3M]]&lt;br /&gt;
[[Category:S3M Format|Format Specification]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_Formats/S3M&amp;diff=4658</id>
		<title>Development: Formats/S3M</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_Formats/S3M&amp;diff=4658"/>
		<updated>2024-10-30T05:46:43Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Velvet Studio / PlayePRO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;General information concerning the S3M file format. Variable names and hexadecimal numbers (in little-endian formats) are indicated by a &amp;lt;tt&amp;gt;monospace font&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Tracker IDs ==&lt;br /&gt;
&lt;br /&gt;
The S3M header contains a field, &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, which is used to identify the application that was used to create the file.&lt;br /&gt;
The following custom tracker IDs (read as little-endian hexadecimal numbers) are known to be found in the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;0208&amp;lt;/tt&amp;gt; - Found in some tracks by Yerzmyey, appears to be from a tracker called Akord (Polish localized version of a tracker called Squeak Tracker)&lt;br /&gt;
* &amp;lt;tt&amp;gt;1xyy&amp;lt;/tt&amp;gt; - Scream Tracker x.yy - Many other trackers, like ModPlug Tracker, disguise as Scream Tracker 3.20, so this is &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; a reliable way to tell if a file was really made with Scream Tracker, [[#Detecting trackers disguising as Scream Tracker|see below]].&lt;br /&gt;
* &amp;lt;tt&amp;gt;2xyy&amp;lt;/tt&amp;gt; - Imago Orpheus x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;2013&amp;lt;/tt&amp;gt; - PlayerPRO on little-endian platforms&lt;br /&gt;
* &amp;lt;tt&amp;gt;3xyy&amp;lt;/tt&amp;gt; - Impulse Tracker x.yy. Impulse Tracker v1.03 (and possibly v1.02) writes &amp;lt;tt&amp;gt;3320&amp;lt;/tt&amp;gt;. For even older Impulse Tracker versions, see [[#Early Impulse Tracker versions|below]].&lt;br /&gt;
* &amp;lt;tt&amp;gt;4xyy&amp;lt;/tt&amp;gt; - Schism Tracker x.yy up to Schism Tracker v0.50, later versions encode a timestamp in the version number - see Schism Tracker’s &amp;lt;tt&amp;gt;[https://github.com/schismtracker/schismtracker/blob/master/schism/version.c version.c]&amp;lt;/tt&amp;gt; or OpenMPT’s &amp;lt;tt&amp;gt;[https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/soundlib/Load_it.cpp Load_it.cpp]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;5xyy&amp;lt;/tt&amp;gt; - OpenMPT x.yy - lower two bytes of version number are stored in the two reserved bytes at offset 54 starting from OpenMPT 1.29.10.00.&lt;br /&gt;
* &amp;lt;tt&amp;gt;5xyy&amp;lt;/tt&amp;gt; - Liquid Tracker x.yy - OpenMPT unfortunately shares this tracker ID with Liquid Tracker. Only one S3M file made with Liquid Tracker has been found in the wild. The two programs can be told apart, though: Either by the fact that the full OpenMPT version info is present, or for older OpenMPT versions by checking the ultraclick value (Liquid Tracker writes an ultraclick value of 16, while OpenMPT versions before the addition of the full version information wrote an ultraclick value of 8. Shortly after the full version information was added, the ultraclick value was changed to 16).&lt;br /&gt;
* &amp;lt;tt&amp;gt;57yy&amp;lt;/tt&amp;gt; - NESMusa 7.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;5447&amp;lt;/tt&amp;gt; - Graoumf Tracker (appears as &amp;quot;GT&amp;quot; magic bytes on disk)&lt;br /&gt;
* &amp;lt;tt&amp;gt;6xyy&amp;lt;/tt&amp;gt; - BeRoTracker x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;7xyy&amp;lt;/tt&amp;gt; - CreamTracker x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;CA00&amp;lt;/tt&amp;gt; - Camoto / libgamemusic&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: BeRoTracker used the ID &amp;lt;tt&amp;gt;4100&amp;lt;/tt&amp;gt; since 2004, but has switched to using the &amp;lt;tt&amp;gt;6xyy&amp;lt;/tt&amp;gt; scheme in 2012. Luckily, this version is not used by Schism Tracker, so it is still possible to tell the two trackers apart.&lt;br /&gt;
&lt;br /&gt;
Are you a tracker developer and you tracker can save S3M files? Please add your Tracker ID to this list!&lt;br /&gt;
&lt;br /&gt;
== Detecting trackers disguising as Scream Tracker ==&lt;br /&gt;
&lt;br /&gt;
Some trackers disguise as Scream Tracker 3, but there are ways to uncover this disguise:&lt;br /&gt;
&lt;br /&gt;
=== ModPlug Tracker ===&lt;br /&gt;
&lt;br /&gt;
ModPlug Tracker and OpenMPT up to version 1.17.03.01 identifies as Scream Tracker 3.20 in the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field, but it puts zeroes for the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; field, only ever sets flags &amp;lt;tt&amp;gt;10&amp;lt;/tt&amp;gt; (Amiga Limits) and &amp;lt;tt&amp;gt;40&amp;lt;/tt&amp;gt; (Fast Volume Slides), writes multiples of 16 orders, always saves channel pannings, and writes zero into the ultraclick removal field (Scream Tracker 3 always puts either 16, 24, or 32 there).&lt;br /&gt;
&lt;br /&gt;
ModPlug Tracker versions up to 1.0 alpha 5 can be identified by not setting the stereo bit on the master volume. Versions 1.0 alpha 6 up to 1.16.203 can be told apart from later versions if less than 32 channels are used: In the extended panning table, all channels have bit 5 (use panning) set, even those past the last used channel. Later versions write &amp;lt;tt&amp;gt;08&amp;lt;/tt&amp;gt; (center panning, do not use) for such channels instead.&lt;br /&gt;
&lt;br /&gt;
=== Early Schism Tracker versions ===&lt;br /&gt;
&lt;br /&gt;
Before Schism Tracker switched to using its own tracker ID, it largely used the original ModPlug Tracker source code, so many files may me mis-identified as being made with ModPlug. However, at some point it swtiched to writing multiples of 2 orders instead of 16, so if all the other ModPlug detections are correct, but the order list length is only a multiple of 2, it was most likely Schism Tracker that wrote the file.&lt;br /&gt;
&lt;br /&gt;
Note that there is an automatic conversion of Vic&#039;s soundtrack for Acme&#039;s &amp;quot;Paper&amp;quot; demo which would match these conditions as well; however that conversion writes pattern data before sample headers, which can be used to tell it apart.&lt;br /&gt;
&lt;br /&gt;
=== Early Impulse Tracker versions ===&lt;br /&gt;
&lt;br /&gt;
Impulse Tracker v1.01 (and potentially v1.00 and v1.02) identifies as Scream Tracker 3.20, puts zeros for the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt; fields, and sets flag 8 (zero-volume optimizations). It does not use the channel panning table, which sets it apart from real Scream Tracker 3.20.&lt;br /&gt;
&lt;br /&gt;
=== Velvet Studio / PlayerPRO ===&lt;br /&gt;
&lt;br /&gt;
Velvet Studio and PlayerPRO also pretend to be Scream Tracker 3.20, but write zeroes for &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;flags&amp;lt;/tt&amp;gt;, and do &#039;&#039;&#039;not&#039;&#039;&#039; save channel pannings. Velvet Studio also writes a fairly recognizable LRRL pattern for the channels.&lt;br /&gt;
&lt;br /&gt;
To tell the two trackers apart: PlayerPRO always writes a global volume of 64 and a mix volume of 48 (mono). On the other hand, Velvet Studio always writes the stereo flag.&lt;br /&gt;
&lt;br /&gt;
PlayerPRO also writes an extra 16 bytes of padding between sample headers.&lt;br /&gt;
&lt;br /&gt;
=== Sound Club 2 ===&lt;br /&gt;
&lt;br /&gt;
Sound Club two writes &amp;quot;SCLUB2.0&amp;quot; into the 8 consecutive reserved bytes in the file header.&lt;br /&gt;
&lt;br /&gt;
=== UNMO3 ===&lt;br /&gt;
&lt;br /&gt;
Nowadays, the MO3 format has support for storing the original value of the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field, so recent UNMO3 versions make use of this. When this information is not available, or if an older UNMO3 version is used, it can be identified as follows: It pretends to be Scream Tacker 3.01, &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt; are 0, channel pannings are always saved (a feature not supported by Scream Tracker 3.01). The only flags it should ever write are Fast Slides and Amiga Limits. Mix volume should always indicate stereo mixing.&lt;br /&gt;
&lt;br /&gt;
=== deMODifier ===&lt;br /&gt;
&lt;br /&gt;
[https://worrydream.com/iigs/#demodifier deMODifier] is a converter for SoundSmith files to S3M format. It disguises as Scream Tracker 3.01, &amp;lt;tt&amp;gt;flags&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt; are 0, global volume is always 48, mix volume is 176 (48 + stereo), tempo is always 150 and no panning table is present. Sample filenames of non-empty sample slots always end in &amp;lt;code&amp;gt;.IFF&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note: This detection should only take place after it can be ruled out that the file was saved with Scream Tracker (see [[#Output driver detection]]).&lt;br /&gt;
&lt;br /&gt;
=== To-S3M ===&lt;br /&gt;
&lt;br /&gt;
[https://files.scene.org/view/resources/music/utils/tos3m100.zip To-S3M] is a converter for MTM modules to S3M format. It disguises as Scream Tracker 3.01, &amp;lt;tt&amp;gt;flags&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ultraclick&amp;lt;/tt&amp;gt; are 0, global volume is always 64, mix volume is 176 (48 + stereo), speed is always 6, tempo is always 125 and no panning table is present. Files with and without the stereo flag have been spotted, but ignoring that, the mix volume is always 48.&lt;br /&gt;
&lt;br /&gt;
Note: This detection should only take place after it can be ruled out that the file was saved with Scream Tracker (see [[#Output driver detection]]).&lt;br /&gt;
&lt;br /&gt;
=== Detecting other trackers ===&lt;br /&gt;
&lt;br /&gt;
Scream Tracker 3.10 / 3.20 / 3.21 normally only writes 16, 24 or 32 in the &#039;&#039;ultraclick removal&#039;&#039; field (earlier versions write 0 there), so this could be a way to check if a file was &#039;&#039;not&#039;&#039; saved with Scream Tracker 3. However, Scream Tracker does not sanitize this field when re-saving a file made with another tracker, so even if the file was saved with Scream Tracker, a different value might still be carried over from another tracker. See the following section for more reliable fingerprinting.&lt;br /&gt;
&lt;br /&gt;
== Output driver detection ==&lt;br /&gt;
&lt;br /&gt;
Scream Tracker’s Gravis Ultrasound and Sound Blaster drivers differ in their interpretation of various pattern effects, which affects playback of some modules noticeably. Luckily, there is a way to tell which driver was loaded when the S3M file was last saved in Scream Tracker, which can serve as a detection heuristic: If the file was saved with the Gravis Ultrasound driver loaded, every non-empty sample header will have a unique &amp;lt;tt&amp;gt;Int:Gp&amp;lt;/tt&amp;gt; value. If the file was saved with the Sound Blaster driver loaded, every non-empty sample header will have 1 in this field. Note that the first GUS sample also uses address 1, so if there is only one non-empty sample slot, GUS and SB cannot be told apart.&lt;br /&gt;
&lt;br /&gt;
Note that some S3Ms saved with Scream Tracker 3.00 (&amp;lt;tt&amp;gt;cwtv&amp;lt;/tt&amp;gt; = &amp;lt;tt&amp;gt;1300&amp;lt;/tt&amp;gt;) have a &amp;lt;tt&amp;gt;Int:Gp&amp;lt;/tt&amp;gt; value of 0 for all samples. There is probably a very early version of Scream Tracker 3.00 (probably from 1992) which does not support the Gravis Ultrasound. For higher &amp;lt;tt&amp;gt;cwtv&amp;lt;/tt&amp;gt; values, the fact that all &amp;lt;tt&amp;gt;Int:Gp&amp;lt;/tt&amp;gt; values are 0 can be used for detecting other trackers or tools disguising as Scream Tracker (e.g. automatic PSM to S3M conversions).&lt;br /&gt;
&lt;br /&gt;
== Impulse Tracker Edit Timer ==&lt;br /&gt;
&lt;br /&gt;
Impulse Tracker hides its [[Development: Formats/IT#Edit Timer|edit timer]] in the file header; there is a section of 8 reserved bytes, of which the first and last two are zero, and the four bytes in the middle contain the edit timer in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Formats/S3M]]&lt;br /&gt;
[[Category:S3M Format|Format Specification]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_Test_Cases/S3M&amp;diff=4657</id>
		<title>Development: Test Cases/S3M</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_Test_Cases/S3M&amp;diff=4657"/>
		<updated>2024-10-30T05:35:16Z</updated>

		<summary type="html">&lt;p&gt;CS127: fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Testsuite Introduction|format=S3M|tracker=Scream Tracker 3}}&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=AdlibZeroVolumeNote.s3m|pass=14612}}&lt;br /&gt;
A peculiar edge case where a note played at volume 0 causes a following note playing at volume 64 to not be heard. This was caused by the note-on bit not being reset before triggering the new note.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=FreqLimits.s3m|pass=1134}}&lt;br /&gt;
Scream Tracker 3 stops playback if the period is too low (the frequency is too high). The upper period limit is tested in [[#PeriodLimitUpper.s3m|PeriodLimitUpper.s3m]].&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=LoopReset.s3m|pass=6127}}&lt;br /&gt;
Scream Tracker 3 resets the start position of the last pattern loop on every pattern transition. Each time pattern 1 is played, seven notes should be heard.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=NOP.s3m|pass=11602}}&lt;br /&gt;
Related to [[#ParamMemory.s3m|ParamMemory.s3m]], even empty effect cells with a non-zero parameter contribute to the effect memory. In this example, a major arpeggio should be heard, as there is a &amp;lt;tt&amp;gt; 37&amp;lt;/tt&amp;gt; no-op effect on the first row.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=NoCombinedSlidesOnFirstTick-Fast.s3m|pass=21826}}&lt;br /&gt;
Combined slide commands Kxy and Lxy do not run on the first tick in Scream Tracker, effectively rendering fine slides with such commands inefficient. This test is with Fast Slides enabled.&lt;br /&gt;
As most other software supports fine slides with these commands, OpenMPT will only emulate this quirk when opening a file saved with Scream Tracker 3.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=NoCombinedSlidesOnFirstTick-Normal.s3m|pass=21826}}&lt;br /&gt;
Combined slide commands Kxy and Lxy do not run on the first tick in Scream Tracker, effectively rendering fine slides with such commands inefficient. This test is with Fast Slides disabled.&lt;br /&gt;
As most other software supports fine slides with these commands, OpenMPT will only emulate this quirk when opening a file saved with Scream Tracker 3.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=OffsetLoopWraparound.s3m|pass=12507}}&lt;br /&gt;
Offset commands beyond the loop end do two things in Scream Tracker 3: With a GUS, the playback wraps around to the loop start, but with a SB sample playback is stopped. This test case is for the more useful GUS behaviour. It is possible to [[Development:_Formats/S3M#Output_driver_detection|identify the sound card last used in Scream Tracker]], so this check can be applied conditionally.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=OffsetPastSampleEnd.s3m|pass=12761}}&lt;br /&gt;
Offset commands beyond the sample end of non-looped samples should stop sample playback.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=OxxMemory.s3m|pass=10915}}&lt;br /&gt;
When Scream Tracker 3 encounters a note without instrument number, it recalls the previous note′s offset. But unlike ProTracker, it does not add up offset values. When played correctly, this module should stay silent.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=OxxMemoryWithRetrig.s3m|pass=12762}}&lt;br /&gt;
Refined version of [[#OxxMemory.s3m|OxxMemory.s3m]] which tests the interaction between Oxx and Qxx with and without instrument numbers. The numbers should be heard in the same order as specified in the module title.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=ParamMemory.s3m|pass=1053}}&lt;br /&gt;
Scream Tracker 3 uses the last non-zero effect parameter as a memory for most effects: Dxy, Kxy, Lxy, Exx, Fxx, Ixy, Jxy, Qxy, Rxy, Sxy. Other effects may have their own memory or share it with another command (such as Hxy / Uxy).&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=PatternDelays.s3m|pass=1221}}&lt;br /&gt;
When there are multiple row delays (SEx), only the first one is considered. The tricky part here is that the “first one” might not always be the “leftmost” one, because Scream Tracker 3 first evaluates all “left” channels (whose name starts with &amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt; in the pan table), and then all “right” channels (whose name starts with &amp;lt;tt&amp;gt;R&amp;lt;/tt&amp;gt; in the pan table). This test case does not exploit this behaviour, the first row delay is always found on a left channel or there are only row delays on a right channel. I do not really know if it is worth emulating this idiosynchrasy.&lt;br /&gt;
Note: Scream Tracker 3 does not have tick delay (S6x) commands, but they are tested here for completeness (Impulse Tracker supports them as well, so its playback behaviour is used as a reference).&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=PatternDelaysRetrig.s3m|pass=1221}}&lt;br /&gt;
Rows on which a row delay (SEx) effect is placed have multiple “first ticks”, i.e. you should set your “first tick flag” on every tick that is a multiple of the song speed (or &amp;lt;tt&amp;gt;speed + tick delay&amp;lt;/tt&amp;gt; if you support tick delays in your S3M player). In this test module, the note pitch is changed multiple times per row, depending on the row delay values.&lt;br /&gt;
&amp;lt;br/&amp;gt;Note: This test case broke in r3520 and was fixed again in r4895.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=PeriodLimit.s3m|pass=4796}}&lt;br /&gt;
Scream Tracker 3 limits the final output period to be at least 64, i.e. when playing a note that is too high or when sliding the period lower than 64, the output period will simply be clamped to 64. However, when reaching a period of 0 through slides, the output on the channel should be stopped. When played correctly, both channels in this module should play identically.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=PeriodLimitUpper.s3m|pass=15258}}&lt;br /&gt;
Scream Tracker 3 limits the channel period to be at most 32767, but when using the GUS driver, the frequency resolution is too low so the test module will sound very different.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=PortaAfterArp.s3m|pass=7525}}&lt;br /&gt;
A portamento up or portamento down effect immediately following an arpeggio effect should slide from the last arpeggiated note, and not from the channel frequency as it was before the arpeggio. Tone portamento is not affected. When played correctly, both channels in this module should play identically.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=PortaSmpChange.s3m|pass=3578}}&lt;br /&gt;
If the sample number next to a portamento effect differs from the previous number, the old sample should be kept, but the new sample&#039;s default volume should still be applied.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=RetrigAfterNoteCut.s3m|pass=12760}}&lt;br /&gt;
&amp;lt;tt&amp;gt;Qxy&amp;lt;/tt&amp;gt; should not retrigger notes after they have been cut with &amp;lt;tt&amp;gt;^^^&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;SCx&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=RetrigSlide.s3m|pass=16646}}&lt;br /&gt;
&amp;lt;tt&amp;gt;Qxy&amp;lt;/tt&amp;gt; should not reset the note frequency after a pitch slide.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=TonePortamentoWithAdlibNote.s3m|pass=17731}}&lt;br /&gt;
If there is a tone portamento next to an Adlib note, the tone portamento is not executed. If there is no note on the next row, the target note of the tone portamento is instantly heard on the first tick of the next row instead. Note that tone portamento without a note is not affected by this.&lt;br /&gt;
&lt;br /&gt;
In Scream Tracker 3.01, this feature still works as intended. Only Scream Tracker 3.03 and later expose this weird behaviour.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=VibratoTypeChange.s3m|pass=6316}}&lt;br /&gt;
Hxx and Uxx use the same effect memory for the vibrato depth. For example, U1F followed by H00 causes the second effect to be played as H1F and vice versa. This also effectively means that Kxx will always plays “normal” vibratos, even if a fine vibrato has previously been used. When played correctly, this module should remain silent.&lt;br /&gt;
&lt;br /&gt;
{{Testcase|format=s3m|name=weirdloop.s3m}}&lt;br /&gt;
A “broken” pattern loop. The voice should say “1” and then repeat “4 2 1 2”. Interestingly, the playback differs between various versions of Scream Tracker 3.&lt;br /&gt;
&lt;br /&gt;
{{Testcase Summary}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Test Cases/S3M]]&lt;br /&gt;
[[Category:S3M Format|Test Cases]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Manual:_Setup/Keyboard&amp;diff=4656</id>
		<title>Manual: Setup/Keyboard</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Manual:_Setup/Keyboard&amp;diff=4656"/>
		<updated>2024-10-30T05:34:07Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Key */ fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Settings Keyboard.png|thumb|300px|Keyboard tab of the settings dialog]]&lt;br /&gt;
&lt;br /&gt;
In this page you can choose or edit keyboard shortcuts for many of the actions in OpenMPT, which are always active unless the input focus is within a textbox. OpenMPT keeps an internal default layout, but you can save your own or load others, for example from the &amp;lt;code&amp;gt;ExtraKeymaps&amp;lt;/code&amp;gt; folder in OpenMPT’s application folder by clicking on the “Import Keys” button near the middle of the page. The list of the &#039;&#039;&#039;current&#039;&#039;&#039; shortcuts are kept in the &amp;lt;code&amp;gt;Keybindings.mkb&amp;lt;/code&amp;gt; file in the &amp;lt;code&amp;gt;%APPDATA%\OpenMPT&amp;lt;/code&amp;gt; folder (or OpenMPT’s application folder if in portable mode), but with this dialog, you can save these shortcuts in a separate file for safekeeping or sharing.&lt;br /&gt;
The following is a description of the various items on the page.&lt;br /&gt;
&lt;br /&gt;
To view or edit keyboard shortcuts, first find the context to which the keypress would be applied by clicking on the Category field. A popup menu will open and you can choose the context to view. If you wanted, for example, to assign the &amp;lt;kbd&amp;gt;Q&amp;lt;/kbd&amp;gt; key to the base octave C when inputting a note in a pattern, this keypress would be needed in the Pattern Editor for the note column. So you would select “Pattern Editor – Note Column” from the popup menu. The list of assignable note messages will be displayed in the field below it. Select the “Base octave C” entry and select it. Alternatively, if you know (parts of) the shortcut name, you can type it into the “Find” box.&lt;br /&gt;
&lt;br /&gt;
Limited support for MIDI message handling is also there: Additionally to computer keyboard keys, MIDI CCs and MIDI note events may be used to trigger shortcuts. To make use of them, first [[Manual: MIDI Reference#Enabling MIDI Input|enable MIDI Input]]. Then, go to this settings dialog, focus the Key input field and send the wanted MIDI CC or note using your MIDI device.&lt;br /&gt;
&lt;br /&gt;
It is possible to assign the same key combination to several shortcuts by means of the hidden setting [[Manual: Hidden Settings#.5BMisc.5D|Misc.AllowMultipleCommandsPerKey]], but a warning about this potentially unwanted situation is emitted if you are trying to re-use an existing key combination that may be conflicting.&lt;br /&gt;
&lt;br /&gt;
== Shortcut List ==&lt;br /&gt;
&lt;br /&gt;
=== Select Category ===&lt;br /&gt;
Shows the current set of functions you can assign shortcuts to. Clicking this field opens a popup menu so you can choose which set of shortcuts you wish to edit or assign.&lt;br /&gt;
&lt;br /&gt;
=== Action List ===&lt;br /&gt;
Clicking on one of the entries selects it for key assignment. See the [[Manual: Keyboard Actions|Keyboard Actions]] table for a description of all available actions.&lt;br /&gt;
&lt;br /&gt;
=== Find ===&lt;br /&gt;
This can be used to search for a specific shortcut in the complete shortcut list by its name. Instead of searching by name, you can also search by shortcut. Just click on the &#039;&#039;&#039;Key&#039;&#039;&#039; edit box and enter the key combination that you want to find (e.g. pressing &amp;lt;kbd&amp;gt;Ctrl&amp;lt;/kbd&amp;gt;+&amp;lt;kbd&amp;gt;C&amp;lt;/kbd&amp;gt; would bring up the “Copy” shortcut when using the default configuration). Focus the edit box again to remove the search term.&lt;br /&gt;
&lt;br /&gt;
== Key Setup ==&lt;br /&gt;
&lt;br /&gt;
=== Key setup choice ===&lt;br /&gt;
This field lets you switch between the choices of key assignments for this action. If there is no key assigned, it will display &amp;lt;code&amp;gt;&amp;lt;new&amp;gt;&amp;lt;/code&amp;gt;; otherwise, the text will read &amp;lt;code&amp;gt;&amp;quot;Choice &#039;&#039;x&#039;&#039; (of &#039;&#039;y&#039;&#039;)&amp;quot;&amp;lt;/code&amp;gt; where &#039;&#039;&#039;&#039;&#039;x&#039;&#039;&#039;&#039;&#039; is the number of the current shortcut and &#039;&#039;&#039;&#039;&#039;y&#039;&#039;&#039;&#039;&#039; is the total count of this action’s current key assignments. Clicking in this field will display other choices, where you can select the one to edit.&lt;br /&gt;
&lt;br /&gt;
=== Key ===&lt;br /&gt;
Shows the key assignment for this shortcut. Double-clicking in this field (after choosing an action in the Action List) will “listen” for a new key assignment. Any keypresses or recognized MIDI events will be entered into this field and assigned to the action as a keyboard shortcut. In order to stop “listening” for new key assignments, press the Cancel button right next to it or click on another control.&lt;br /&gt;
&lt;br /&gt;
=== Set / Cancel ===&lt;br /&gt;
You can also press the Set button to start “listening” for a new shortcut assignment. It then changes into a Cancel button, in case you want to abort the action and not assign a new key.&lt;br /&gt;
&lt;br /&gt;
=== Restore ===&lt;br /&gt;
Clicking on this button resets the key assignments of this action to when the action was first selected.&lt;br /&gt;
&lt;br /&gt;
=== On Key Down/Hold/Up ===&lt;br /&gt;
When any of these are checked, the action will be activated at the corresponding event of the keypress, either when the key is pressed down, when it is held down, and / or when the key is released.&lt;br /&gt;
&lt;br /&gt;
=== Delete ===&lt;br /&gt;
Clicking on this button deletes the current key assignment. If there were other keyboard shortcuts for this action, they remain.&lt;br /&gt;
&lt;br /&gt;
=== Repeat notes on hold ===&lt;br /&gt;
These two buttons are a shortcut for enabling or disabling the “On Key Hold” property for all &#039;&#039;&#039;note&#039;&#039;&#039; keys.&lt;br /&gt;
&lt;br /&gt;
=== Chord Detect Interval ===&lt;br /&gt;
If you have the Pattern Editor’s Edit Step setting set to some other value than 0 and have a record group set up, OpenMPT will put all notes detected within the Chord Detect Interval on the same row, regardless of the Edit Step setting, i.e. the notes are interpreted as a chord.&lt;br /&gt;
&lt;br /&gt;
=== Import Keys ===&lt;br /&gt;
Use this button to import an &amp;lt;code&amp;gt;.mkb&amp;lt;/code&amp;gt; (OpenMPT keyboard layout) file. This allows you to use an alternate set of pre-defined keyboard assignments. In the side bar of the file dialog, a shortcut to the &amp;lt;code&amp;gt;ExtraKeymaps&amp;lt;/code&amp;gt; can be found to quickly jump to the alternative keyboard layouts shipped with OpenMPT.&lt;br /&gt;
&lt;br /&gt;
=== Export Keys ===&lt;br /&gt;
Use this button to export the current set of keyboard shortcuts to a keyboard layout file. This is helpful not only for multiple users of one OpenMPT setup, but also for testing different setups for ease of use.&lt;br /&gt;
&lt;br /&gt;
=== Restore Default Configuration ===&lt;br /&gt;
Clicking on this button restores all keybindings to their default keys.&lt;br /&gt;
&lt;br /&gt;
=== Error Log ===&lt;br /&gt;
Shows conflicts between key assignments. Conflicts occur when one keypress or combination keypress is already assigned to an action within the same context or a parent context. A problem may also occur when modifier keys (&amp;lt;kbd&amp;gt;Shift&amp;lt;/kbd&amp;gt;, &amp;lt;kbd&amp;gt;Ctrl&amp;lt;/kbd&amp;gt;, &amp;lt;kbd&amp;gt;Alt&amp;lt;/kbd&amp;gt; or the &amp;lt;kbd&amp;gt;Windows&amp;lt;/kbd&amp;gt; key) are expected but another key is assigned. In this case, OpenMPT will not allow the non-modifier key to be assigned.&lt;br /&gt;
&lt;br /&gt;
=== Clear Log ===&lt;br /&gt;
Clicking this button deletes all the text in the log window.&lt;br /&gt;
&lt;br /&gt;
[[Category:Manual|Setup/Keyboard]]&lt;br /&gt;
[[de:Handbuch: Setup/Keyboard]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4623</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4623"/>
		<updated>2024-08-19T02:00:16Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* OpenMPT Instrument Extensions */ typo fix&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]  || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32   || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Plugin Type&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;VST plugins: &amp;lt;code&amp;gt;PtsV&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x56737450&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DMO plugins: &amp;lt;code&amp;gt;OMXD&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x44584D4F&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Internal plugins use various other IDs.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32    || Unique Plugin ID&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint8     || Routing Flags&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x01: Apply to master mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x02: Bypass&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x04: Dry mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x08: Expand mix [0%,100%] → [-100%,100%]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x10: Auto-suspend on silence&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9      || uint8     || Mix mode&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0: Default (&amp;lt;code&amp;gt;MIX += DRY * dryRatio + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;1: Wet Subtract (&amp;lt;code&amp;gt;MIX += DRY - WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;2: Dry Subtract (&amp;lt;code&amp;gt;MIX += WET - DRY * dryRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3: Mix Subtract (&amp;lt;code&amp;gt;MIX -= WET - DRY * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;4: Middle Subtract (&amp;lt;code&amp;gt;MIX -= middle - WET * wetRatio + middle - DRY&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;5: L/R Balance (&amp;lt;code&amp;gt;MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;6: Instrument (&amp;lt;code&amp;gt;MIX += DRY + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
Prior to OpenMPT 1.32.00.11, instrument plugins behaved like the &amp;quot;Instrument&amp;quot; mix mode regardless of their actual mix mode (mix mode and expand mix options were not available in the GUI for instrument plugins).&amp;lt;br/&amp;gt;&lt;br /&gt;
This was fixed in 1.32.00.11, and the &amp;quot;Instrument&amp;quot; mix mode was added to emulate the old behaviour for old modules.&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint8     || Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
|-&lt;br /&gt;
| 11     || uint8     || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint32    || Output Routing (0 = send to master, 0x80 + x = send to plugin x)&lt;br /&gt;
|-&lt;br /&gt;
| 16     || uint32    || Shell plugin ID (0 if this is not a shell plugin)&lt;br /&gt;
|-&lt;br /&gt;
| 20     || uint8[12] || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 32     || char[32]  || User-chosen plugin name (Windows code page)&lt;br /&gt;
|-&lt;br /&gt;
| 64     || char[64]  || Library name (Original DLL name / DMO identifier).&amp;lt;br/&amp;gt;UTF-8 (max. 64 bytes) since OpenMPT 1.22.07.01, Windows code page in older versions.&lt;br /&gt;
|-&lt;br /&gt;
| 128    || uint32    || Size of plugin-specific data in bytes (parameters or opaque chunk)&lt;br /&gt;
|-&lt;br /&gt;
| 132    || uint8[]   || Plugin-specific data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk opcodes, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read too far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Synth Pre-Amp (VSTi / OPL)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. In this case, the i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors must be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || VarInt    || Length of the filename&lt;br /&gt;
|-&lt;br /&gt;
| ?      || char[]    || Filename (UTF-8, not null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform must be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. must be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data must be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag must be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint16    || Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
|-&lt;br /&gt;
| 2      || uint32    || Number of items in the order list&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint32[]  || The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int32&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the Tuning Collection version is 2.&lt;br /&gt;
* uint32 if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint32&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is uint32. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| float32&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* uint32 if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as uint32 instead of uint16 and uint8 respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Default panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint16    || Default volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint16    || Global volume (0...64)&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint16    || (Reserved, must be 0)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint8     || Auto-vibrato type &amp;lt;!-- todo: list the types --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 13     || uint8     || Auto-vibrato sweep&lt;br /&gt;
|-&lt;br /&gt;
| 14     || uint8     || Auto-vibrato depth&lt;br /&gt;
|-&lt;br /&gt;
| 15     || uint8     || Auto-vibrato rate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard Vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 1,048,575&amp;amp;nbsp;Hz (655350&amp;amp;nbsp;Hz for older versions).&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4622</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4622"/>
		<updated>2024-08-18T11:20:41Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* FX00, ... FX99, F100, ... F255 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]  || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32   || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Plugin Type&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;VST plugins: &amp;lt;code&amp;gt;PtsV&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x56737450&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DMO plugins: &amp;lt;code&amp;gt;OMXD&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x44584D4F&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Internal plugins use various other IDs.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32    || Unique Plugin ID&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint8     || Routing Flags&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x01: Apply to master mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x02: Bypass&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x04: Dry mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x08: Expand mix [0%,100%] → [-100%,100%]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x10: Auto-suspend on silence&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9      || uint8     || Mix mode&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0: Default (&amp;lt;code&amp;gt;MIX += DRY * dryRatio + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;1: Wet Subtract (&amp;lt;code&amp;gt;MIX += DRY - WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;2: Dry Subtract (&amp;lt;code&amp;gt;MIX += WET - DRY * dryRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3: Mix Subtract (&amp;lt;code&amp;gt;MIX -= WET - DRY * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;4: Middle Subtract (&amp;lt;code&amp;gt;MIX -= middle - WET * wetRatio + middle - DRY&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;5: L/R Balance (&amp;lt;code&amp;gt;MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;6: Instrument (&amp;lt;code&amp;gt;MIX += DRY + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
Prior to OpenMPT 1.32.00.11, instrument plugins behaved like the &amp;quot;Instrument&amp;quot; mix mode regardless of their actual mix mode (mix mode and expand mix options were not available in the GUI for instrument plugins).&amp;lt;br/&amp;gt;&lt;br /&gt;
This was fixed in 1.32.00.11, and the &amp;quot;Instrument&amp;quot; mix mode was added to emulate the old behaviour for old modules.&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint8     || Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
|-&lt;br /&gt;
| 11     || uint8     || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint32    || Output Routing (0 = send to master, 0x80 + x = send to plugin x)&lt;br /&gt;
|-&lt;br /&gt;
| 16     || uint32    || Shell plugin ID (0 if this is not a shell plugin)&lt;br /&gt;
|-&lt;br /&gt;
| 20     || uint8[12] || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 32     || char[32]  || User-chosen plugin name (Windows code page)&lt;br /&gt;
|-&lt;br /&gt;
| 64     || char[64]  || Library name (Original DLL name / DMO identifier).&amp;lt;br/&amp;gt;UTF-8 (max. 64 bytes) since OpenMPT 1.22.07.01, Windows code page in older versions.&lt;br /&gt;
|-&lt;br /&gt;
| 128    || uint32    || Size of plugin-specific data in bytes (parameters or opaque chunk)&lt;br /&gt;
|-&lt;br /&gt;
| 132    || uint8[]   || Plugin-specific data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk opcodes, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Synth Pre-Amp (VSTi / OPL)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. In this case, the i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors must be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || VarInt    || Length of the filename&lt;br /&gt;
|-&lt;br /&gt;
| ?      || char[]    || Filename (UTF-8, not null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform must be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. must be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data must be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag must be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint16    || Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
|-&lt;br /&gt;
| 2      || uint32    || Number of items in the order list&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint32[]  || The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int32&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the Tuning Collection version is 2.&lt;br /&gt;
* uint32 if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint32&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is uint32. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| float32&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* uint32 if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as uint32 instead of uint16 and uint8 respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Default panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint16    || Default volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint16    || Global volume (0...64)&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint16    || (Reserved, must be 0)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint8     || Auto-vibrato type &amp;lt;!-- todo: list the types --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 13     || uint8     || Auto-vibrato sweep&lt;br /&gt;
|-&lt;br /&gt;
| 14     || uint8     || Auto-vibrato depth&lt;br /&gt;
|-&lt;br /&gt;
| 15     || uint8     || Auto-vibrato rate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard Vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 1,048,575&amp;amp;nbsp;Hz (655350&amp;amp;nbsp;Hz for older versions).&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4621</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4621"/>
		<updated>2024-08-18T11:20:23Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* FX00, ... FX99, F100, ... F255 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]  || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32   || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Plugin Type&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;VST plugins: &amp;lt;code&amp;gt;PtsV&amp;lt;/code&amp;gt; (`0x56737450`)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DMO plugins: &amp;lt;code&amp;gt;OMXD&amp;lt;/code&amp;gt; (`0x44584D4F`)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Internal plugins use various other IDs.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32    || Unique Plugin ID&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint8     || Routing Flags&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x01: Apply to master mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x02: Bypass&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x04: Dry mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x08: Expand mix [0%,100%] → [-100%,100%]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x10: Auto-suspend on silence&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9      || uint8     || Mix mode&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0: Default (&amp;lt;code&amp;gt;MIX += DRY * dryRatio + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;1: Wet Subtract (&amp;lt;code&amp;gt;MIX += DRY - WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;2: Dry Subtract (&amp;lt;code&amp;gt;MIX += WET - DRY * dryRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3: Mix Subtract (&amp;lt;code&amp;gt;MIX -= WET - DRY * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;4: Middle Subtract (&amp;lt;code&amp;gt;MIX -= middle - WET * wetRatio + middle - DRY&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;5: L/R Balance (&amp;lt;code&amp;gt;MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;6: Instrument (&amp;lt;code&amp;gt;MIX += DRY + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
Prior to OpenMPT 1.32.00.11, instrument plugins behaved like the &amp;quot;Instrument&amp;quot; mix mode regardless of their actual mix mode (mix mode and expand mix options were not available in the GUI for instrument plugins).&amp;lt;br/&amp;gt;&lt;br /&gt;
This was fixed in 1.32.00.11, and the &amp;quot;Instrument&amp;quot; mix mode was added to emulate the old behaviour for old modules.&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint8     || Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
|-&lt;br /&gt;
| 11     || uint8     || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint32    || Output Routing (0 = send to master, 0x80 + x = send to plugin x)&lt;br /&gt;
|-&lt;br /&gt;
| 16     || uint32    || Shell plugin ID (0 if this is not a shell plugin)&lt;br /&gt;
|-&lt;br /&gt;
| 20     || uint8[12] || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 32     || char[32]  || User-chosen plugin name (Windows code page)&lt;br /&gt;
|-&lt;br /&gt;
| 64     || char[64]  || Library name (Original DLL name / DMO identifier).&amp;lt;br/&amp;gt;UTF-8 (max. 64 bytes) since OpenMPT 1.22.07.01, Windows code page in older versions.&lt;br /&gt;
|-&lt;br /&gt;
| 128    || uint32    || Size of plugin-specific data in bytes (parameters or opaque chunk)&lt;br /&gt;
|-&lt;br /&gt;
| 132    || uint8[]   || Plugin-specific data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk opcodes, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Synth Pre-Amp (VSTi / OPL)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. In this case, the i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors must be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || VarInt    || Length of the filename&lt;br /&gt;
|-&lt;br /&gt;
| ?      || char[]    || Filename (UTF-8, not null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform must be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. must be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data must be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag must be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint16    || Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
|-&lt;br /&gt;
| 2      || uint32    || Number of items in the order list&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint32[]  || The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int32&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the Tuning Collection version is 2.&lt;br /&gt;
* uint32 if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint32&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is uint32. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| float32&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* uint32 if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as uint32 instead of uint16 and uint8 respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Default panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint16    || Default volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint16    || Global volume (0...64)&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint16    || (Reserved, must be 0)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint8     || Auto-vibrato type &amp;lt;!-- todo: list the types --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 13     || uint8     || Auto-vibrato sweep&lt;br /&gt;
|-&lt;br /&gt;
| 14     || uint8     || Auto-vibrato depth&lt;br /&gt;
|-&lt;br /&gt;
| 15     || uint8     || Auto-vibrato rate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard Vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 1,048,575&amp;amp;nbsp;Hz (655350&amp;amp;nbsp;Hz for older versions).&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4543</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4543"/>
		<updated>2024-05-08T07:42:40Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* FX00, ... FX99, F100, ... F255 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]  || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32   || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Plugin Type&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;VST plugins: &amp;lt;code&amp;gt;PtsV&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DMO plugins: &amp;lt;code&amp;gt;OMXD&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Internal plugins use various other IDs.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4      || char[4]   || Unique Plugin ID&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint8     || Routing Flags&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x01: Apply to master mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x02: Bypass&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x04: Dry mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x08: Expand mix [0%,100%] → [-100%,100%]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x10: Auto-suspend on silence&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9      || uint8     || Mix mode&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0: Default (&amp;lt;code&amp;gt;MIX += DRY * dryRatio + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;1: Wet Subtract (&amp;lt;code&amp;gt;MIX += DRY - WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;2: Dry Subtract (&amp;lt;code&amp;gt;MIX += WET - DRY * dryRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3: Mix Subtract (&amp;lt;code&amp;gt;MIX -= WET - DRY * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;4: Middle Subtract (&amp;lt;code&amp;gt;MIX -= middle - WET * wetRatio + middle - DRY&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;5: L/R Balance (&amp;lt;code&amp;gt;MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;6: Instrument (&amp;lt;code&amp;gt;MIX += DRY + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
Prior to OpenMPT 1.32.00.11, instrument plugins behaved like the &amp;quot;Instrument&amp;quot; mix mode regardless of their actual mix mode (mix mode and expand mix options were not available in the GUI for instrument plugins).&amp;lt;br/&amp;gt;&lt;br /&gt;
This was fixed in 1.32.00.11, and the &amp;quot;Instrument&amp;quot; mix mode was added to emulate the old behaviour for old modules.&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint8     || Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
|-&lt;br /&gt;
| 11     || uint8     || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint32    || Output Routing (0 = send to master, 0x80 + x = send to plugin x)&lt;br /&gt;
|-&lt;br /&gt;
| 16     || uint8[16] || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 32     || char[32]  || User-chosen plugin name (Windows code page)&lt;br /&gt;
|-&lt;br /&gt;
| 64     || char[64]  || Library name (Original DLL name / DMO identifier).&amp;lt;br/&amp;gt;UTF-8 (max. 64 bytes) since OpenMPT 1.22.07.01, Windows code page in older versions.&lt;br /&gt;
|-&lt;br /&gt;
| 128    || uint32    || Size of plugin-specific data in bytes (parameters or opaque chunk)&lt;br /&gt;
|-&lt;br /&gt;
| 132    || uint8[]   || Plugin-specific data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk opcodes, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Synth Pre-Amp (VSTi / OPL)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. In this case, the i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors must be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || VarInt    || Length of the filename&lt;br /&gt;
|-&lt;br /&gt;
| ?      || char[]    || Filename (UTF-8, not null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform must be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. must be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data must be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag must be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint16    || Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
|-&lt;br /&gt;
| 2      || uint32    || Number of items in the order list&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint32[]  || The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int32&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the Tuning Collection version is 2.&lt;br /&gt;
* uint32 if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint32&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is uint32. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| float32&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* uint32 if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as uint32 instead of uint16 and uint8 respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Default panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint16    || Default volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint16    || Global volume (0...64)&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint16    || (Reserved, must be 0)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint8     || Auto-vibrato type &amp;lt;!-- todo: list the types --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 13     || uint8     || Auto-vibrato sweep&lt;br /&gt;
|-&lt;br /&gt;
| 14     || uint8     || Auto-vibrato depth&lt;br /&gt;
|-&lt;br /&gt;
| 15     || uint8     || Auto-vibrato rate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard Vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 1,048,575&amp;amp;nbsp;Hz (655350&amp;amp;nbsp;Hz for older versions).&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4542</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4542"/>
		<updated>2024-05-08T07:38:13Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* FX00, ... FX99, F100, ... F255 */ wrap mix mode formulas in code blocks&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]  || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32   || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Plugin Type&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;VST plugins: &amp;lt;code&amp;gt;PtsV&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DMO plugins: &amp;lt;code&amp;gt;OMXD&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Internal plugins use various other IDs.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4      || char[4]   || Unique Plugin ID&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint8     || Routing Flags&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x01: Apply to master mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x02: Bypass&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x04: Dry mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x08: Expand mix [0%,100%] → [-100%,100%]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x10: Auto-suspend on silence&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9      || uint8     || Mix mode&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0: Default (&amp;lt;code&amp;gt;MIX += DRY * dryRatio + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;1: Wet Subtract (&amp;lt;code&amp;gt;MIX += DRY - WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;2: Dry Subtract (&amp;lt;code&amp;gt;MIX += WET - DRY * dryRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3: Mix Subtract (&amp;lt;code&amp;gt;MIX -= WET - DRY * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;4: Middle Subtract (&amp;lt;code&amp;gt;MIX -= middle - WET * wetRatio + middle - DRY&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;5: L/R Balance (&amp;lt;code&amp;gt;MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;6: Instrument (&amp;lt;code&amp;gt;MIX += DRY + WET * wetRatio&amp;lt;/code&amp;gt;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
Prior to OpenMPT 1.32.00.11, instrument plugins behaved like the &amp;quot;Instrument&amp;quot; mix mode regardless of their actual mix mode (mix mode and expand mix options were not available in the GUI for instrument plugins).&amp;lt;br/&amp;gt;&lt;br /&gt;
This was fixed in 1.32.00.11, and the &amp;quot;Instrument&amp;quot; mix mode was added to emulate the old behaviour for old modules.&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint8     || Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
|-&lt;br /&gt;
| 11     || uint8     || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint32    || Output Routing (0 = send to master 0x80 + x = send to plugin x)&lt;br /&gt;
|-&lt;br /&gt;
| 16     || uint8[16] || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 32     || char[32]  || User-chosen plugin name (Windows code page)&lt;br /&gt;
|-&lt;br /&gt;
| 64     || char[64]  || Library name (Original DLL name / DMO identifier).&amp;lt;br/&amp;gt;UTF-8 (max. 64 bytes) since OpenMPT 1.22.07.01, Windows code page in older versions.&lt;br /&gt;
|-&lt;br /&gt;
| 128    || uint32    || Size of plugin-specific data in bytes (parameters or opaque chunk)&lt;br /&gt;
|-&lt;br /&gt;
| 132    || uint8[]   || Plugin-specific data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk opcodes, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Synth Pre-Amp (VSTi / OPL)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. In this case, the i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors must be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || VarInt    || Length of the filename&lt;br /&gt;
|-&lt;br /&gt;
| ?      || char[]    || Filename (UTF-8, not null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform must be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. must be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data must be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag must be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint16    || Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
|-&lt;br /&gt;
| 2      || uint32    || Number of items in the order list&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint32[]  || The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int32&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the Tuning Collection version is 2.&lt;br /&gt;
* uint32 if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint32&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is uint32. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| float32&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* uint32 if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as uint32 instead of uint16 and uint8 respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Default panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint16    || Default volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint16    || Global volume (0...64)&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint16    || (Reserved, must be 0)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint8     || Auto-vibrato type &amp;lt;!-- todo: list the types --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 13     || uint8     || Auto-vibrato sweep&lt;br /&gt;
|-&lt;br /&gt;
| 14     || uint8     || Auto-vibrato depth&lt;br /&gt;
|-&lt;br /&gt;
| 15     || uint8     || Auto-vibrato rate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard Vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 1,048,575&amp;amp;nbsp;Hz (655350&amp;amp;nbsp;Hz for older versions).&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Manual:_General&amp;diff=4538</id>
		<title>Manual: General</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Manual:_General&amp;diff=4538"/>
		<updated>2024-05-07T23:52:14Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Mix Settings */ added the Instrument mix mode&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:General Tab.png|thumb|300px|General Tab]]&lt;br /&gt;
&lt;br /&gt;
The General tab holds the general global settings of each song and is also used to set up the plugins that are used in a song. Many of these settings can be changed using a coarse slider, a text box to enter a precise value or the spin button next to the text boxes to increase or decrease a value. Some options are not available in all module formats; if that is the case, their controls are simply greyed out and cannot be accessed.&lt;br /&gt;
&lt;br /&gt;
The General tab is divided into two halves. They are divided by a splitter bar, which can be dragged vertically to change the size of both views.&lt;br /&gt;
&lt;br /&gt;
== Song Setup ==&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Track Name&#039;&#039;&#039;: In the first text box, you can enter the name of your song. Depending on the module format used, the length of this text field is limited.&lt;br /&gt;
* &#039;&#039;&#039;Artist&#039;&#039;&#039;: Contains the name of the track artist.&lt;br /&gt;
* &#039;&#039;&#039;Song Properties&#039;&#039;&#039;: Next to the track name, you can see which module format the current song is in, as well as the number of pattern channels. To change either of them (plus some further global settings), click the button to open the [[Manual: Song Properties|Song Properties]] dialog.&lt;br /&gt;
* &#039;&#039;&#039;Resampling&#039;&#039;&#039;: In the MPTM format, a default resampling mode can be enforced. If &#039;&#039;&#039;Default&#039;&#039;&#039; is chosen, the default resampling method as configured in the [[Manual: Setup/Mixer#Resampling|Mixer Settings]] is used. This setting can be further overridden by [[Manual: Instruments#Sample Quality|instruments]]. In other formats, this dropdown list can be used to temporarily override the global resampling method, but its setting is not stored in files.&lt;br /&gt;
* &#039;&#039;&#039;VU Meters&#039;&#039;&#039;: The VU Meters show the level of the left and right master output channel during playback. Their colour can be configured in the [[Manual: Setup/Display|Display Setup]].&lt;br /&gt;
&lt;br /&gt;
=== Tempo ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Initial Tempo&#039;&#039;&#039;: The track′s initial Tempo value. The effect of this setting is determined by the [[Manual: Song Properties#Tempo Mode|Tempo Mode]], which can be set in the [[Manual: Song Properties|Song Properties]] dialog. This setting can also be changed during playback using the Txx command in MPTM / IT / S3M and the Fxx command (with xx ≥ 20h) in XM / MOD tracks. In the MPTM format, the tempo may be fractional (e.g. 136.46 BPM) and can be incremented / decremented in 0.1 steps by holding &amp;lt;kbd&amp;gt;Shift&amp;lt;/kbd&amp;gt; when clicking the spinner buttons, or 0.01 steps by holding &amp;lt;kbd&amp;gt;Ctrl&amp;lt;/kbd&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Ticks / Row&#039;&#039;&#039; (&#039;&#039;&#039;Initial Speed&#039;&#039;&#039;): The track′s initial ticks per row (Speed) value. The effect of this setting is determined by the [[Manual: Song Properties#Tempo Mode|Tempo Mode]], which can be set in the [[Manual: Song Properties|Song Properties]] dialog. This setting can also be changed during playback using the Axx command in MPTM / IT / S3M and the Fxx command (with xx &amp;lt; 20h) in XM / MOD tracks.&lt;br /&gt;
* &#039;&#039;&#039;Tempo Tap&#039;&#039;&#039;: Use the &#039;&#039;&#039;Tap&#039;&#039;&#039; button to tap in the beats per minute. Click the button or hit enter while the button is focussed to signal a beat. The more beats you tap in, the more precise the tempo is estimated. Wait for about two seconds to reset the estimation.&lt;br /&gt;
&lt;br /&gt;
=== Restart / Loop ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Restart&#039;&#039;&#039;: If &#039;&#039;&#039;Loop Song&#039;&#039;&#039; is enabled, playback will resume at this [[Manual: Patterns#Order List|order list]] position when the song end is reached. If there is more than one sequence (order list), this value represents the restart position of the currently selected sequence.&lt;br /&gt;
* &#039;&#039;&#039;Loop Song&#039;&#039;&#039;: If this box is checked, your song will restart from the restart position and loop if the end is reached. This is a global setting rather than a per-song setting and is applied to all tracks you play in OpenMPT.&lt;br /&gt;
&lt;br /&gt;
=== Volume Settings ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Initial Global Volume&#039;&#039;&#039;: The track′s initial Global Volume value, which is the global amplification of a song. The exact effect of this setting depends on the [[Manual: Song Properties#Mix Levels|Mix Levels]], which can be set in the [[Manual: Song Properties|Song Properties]] dialog. Global volume can be changed during playback using the Vxx command in MPTM / IT / S3M (with xx ranging from 00h to 80h in MPTM / IT and from 00h to 40h in S3M) or Gxx in the XM format (with xx ranging from 00h to 40h).&lt;br /&gt;
* &#039;&#039;&#039;Synth Volume&#039;&#039;&#039;: This setting determines the overall amplification of the output of all VST instruments and FM synthesis. This setting cannot be changed using pattern effects.&lt;br /&gt;
* &#039;&#039;&#039;Sample Volume&#039;&#039;&#039;: This setting determines the overall amplification of samples. Too high amplification will saturate or overdrive sample output. This setting cannot be changed using pattern effects. It is the only volume slider available for ProTracker MOD files, but the value is actually not stored in such files.&lt;br /&gt;
&lt;br /&gt;
When using [[Manual:_Song_Properties#Mix_Levels|modern or compatible mix levels]], hovering the volume sliders reveals a tooltip that translates the current attenuation setting into dB units. For the VSTi volume, this means how much every single instrument plugin is attenuated, and for the sample volume, it means how much every single sample voice is attenuated.&lt;br /&gt;
&lt;br /&gt;
== Channel Setup ==&lt;br /&gt;
&lt;br /&gt;
In the middle of the page is the Channel Setup section, which displays four channels at a time, and allows for editing each channel’s initial settings. To browse through all available channels, use the tab control.&lt;br /&gt;
The track format determines what settings can be modified both initially and during output. The following properties can be set for each channel:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Colour&#039;&#039;&#039;: Clicking on the coloured button next to the channel number allows you to pick the colour of this channel, which is shown at the top of the pattern editor.&lt;br /&gt;
* &#039;&#039;&#039;Channel Name&#039;&#039;&#039;: You can assign a name to your channels which is shown in the [[Manual: Patterns|Pattern Editor]] and the [[Manual: Channel Manager|Channel Manager]], to keep your module tidy and help distinguish channels.&lt;br /&gt;
* &#039;&#039;&#039;Initial Channel Volume&#039;&#039;&#039;: The global volume of a channel. All note volumes are multiplied with this. Channel volume is only applied to samples, not to VST instruments, but since it is applied to samples, it can affect the input of an effect plugin. XM and MOD files do not have a channel volume setting. S3M files can make use of channel volume, but they have no initial channel volume, so this control is greyed out. You can use the Mxx command (with xx ranging from 00h to 40h) in patterns to set the channel volume.&lt;br /&gt;
* &#039;&#039;&#039;Initial Panning&#039;&#039;&#039;: The channel’s initial stereo panning. Unlike the channel volume, this setting is not “global”; panning commands, sample panning and instrument &#039;&#039;override&#039;&#039; the initial panning. In MOD files, the initial panning is fixed to a Left/Right/Right/Left scheme; XM files do not support initial channel panning due to the fact that every sample in XM files has a forced default panning. Panning can be changed in the patterns by using the 8xx or E8x command in XM and MOD files and the Xxx or S8x command in MPTM / IT / S3M files.&lt;br /&gt;
* &#039;&#039;&#039;Mute&#039;&#039;&#039;: Clicking on this button enables / disables all audio output from this channel.&amp;lt;br /&amp;gt; Notes played in a channel are always processed, but if “Ignore Muted Channels” is set in the [[Manual: Setup/General|General Options]] page, unmuting a channel will not play a currently running note, instead picking up when a new note is called. Keep in mind that no effects are processed on muted channels in S3M files, so e.g. tempo changes or pattern breaks are not handled on muted channels in S3M files. Also, the channel mute status is only saved in MPTM / IT / S3M files.&lt;br /&gt;
* &#039;&#039;&#039;Surround&#039;&#039;&#039;: This button toggles the surround panning setting for the current channel. Surround and initial panning are mutually exclusive; if surround is enabled, the initial panning is forced to center. Surround can be reset in the pattern using a panning command (unless quad surround panning is enabled). In MPTM and IT files, surround can be enabled using the command S91; in the S3M format, the command XA4 shall be used.&lt;br /&gt;
* &#039;&#039;&#039;Channel Effect&#039;&#039;&#039;: Here you can assign an effect plugin to the current channel. All sample output on this channel is then routed through the effect plugin. To apply more than one plugin to the channel, you can use the plugin’s “Output To” property to route its output to another plugin. Note: While instrument plugins override channel plugins (i.e. if an instrument has a plugin assigned, the sample output of this instrument is &#039;&#039;&#039;not&#039;&#039;&#039; routed through the channel′s effect plugin), channel plugins are always preferred over instrument plugins when using [[Manual: Zxx Macros#Plugin Parameter Control|MIDI Macros]].&lt;br /&gt;
&lt;br /&gt;
The channel properties can also be edited directly from the pattern editor by using the [[Manual: Quick Channel Settings|Quick Channel Settings dialog]].&lt;br /&gt;
&lt;br /&gt;
== Plugin Setup ==&lt;br /&gt;
&lt;br /&gt;
The bottom part of this tab is dedicated to the plugin setup. Here, you can load plugins into your song, configure them, move them, and so on.&lt;br /&gt;
&lt;br /&gt;
=== General ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Plugin Slot&#039;&#039;&#039;: Shows the currently edited plugin; all parameters shown in this section apply to this plugin. Clicking in the field opens a list where you can switch to a different plugin. Clicking on the left / right arrows next to the field changes the current plugin to the previous / next one in the Plugin List. There are 250 available slots where plugins can be placed, and they do not need to be placed sequentially. However, if an output chain is set up, a VST can only output to one farther down the list (with a higher slot number). So for example, a chain can route its audio from slots 1 to 3 to 5, but not 1 to 5 to 3.&lt;br /&gt;
* &#039;&#039;&#039;Move Plugin&#039;&#039;&#039;: This allows you to move the current plugin to another slot. When moving, you will be shown a dialog box which will allow you to choose an empty slot to move the plugin to. References to this plugin (for example from instruments or channel setup) are updated automatically when moving. If the moved plugin is part of a chain, and the plugin is moved to a slot &#039;&#039;after&#039;&#039; its output plugin, the “move plugin chain” must remain enabled, or otherwise the chain will be broken and the Output field (see below) will revert to Default.&lt;br /&gt;
* &#039;&#039;&#039;Clone Plugin&#039;&#039;&#039;: Creates a new instance of the same plugin in another slot. If the plugin is part of the chain, it is possible to clone the entire chain starting from this plugin by enabling the “move plugin chain” option.&lt;br /&gt;
* &#039;&#039;&#039;Insert Slot&#039;&#039;&#039;: Creates an empty slot &#039;&#039;before&#039;&#039; the current plugin’s place in the list. This will effectively push the current plugin and all those after it in the list down one slot. If a plugin occupies the last slot (with the highest number), it is deleted; &#039;&#039;&#039;this cannot be undone&#039;&#039;&#039;, but you are prompted to confirm the insertion in that case.&lt;br /&gt;
* &#039;&#039;&#039;Remove&#039;&#039;&#039;: Removes this plugin instance from the module.&lt;br /&gt;
* &#039;&#039;&#039;Select Plugin&#039;&#039;&#039;: Opens the [[Manual: Plugin Manager|Plugin Manager]], where you can select a plugin to put into the current slot, replacing the current plugin if there is one. You can also &#039;&#039;&#039;remove&#039;&#039;&#039; the current plugin by choosing “No Plugin” in the Plugin Manager.&lt;br /&gt;
* &#039;&#039;&#039;Editor&#039;&#039;&#039;: This button opens the [[Manual: Plugin Window|Plugin Window]] where you can edit the plugin′s properties. &amp;lt;kbd&amp;gt;Shift&amp;lt;/kbd&amp;gt;-clicking the button closes all other open plugin editors.&lt;br /&gt;
* &#039;&#039;&#039;Display Name&#039;&#039;&#039;: An text field where you can provide a custom name for the plugin. This label will appear in the Channel Header if the plugin is assigned to a channel, or the Plugin Select field in the Instruments page if it is assigned to an instrument, so it can be useful to choose a custom name here if you are using several instances of the same plugin.&lt;br /&gt;
* &#039;&#039;&#039;Input / Output Type&#039;&#039;&#039;: A description of the type of audio signal going in and out of the plugin (none, mono, or stereo).&lt;br /&gt;
&lt;br /&gt;
=== Factory Preset ===&lt;br /&gt;
&lt;br /&gt;
Here you can quickly change some parameters. Usually, the more comfortable way to do this is using the [[Manual: Plugin Window|Plugin Window]], but some plugins might not expose all parameters through their window. So in that case, you can still edit them here.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Preset&#039;&#039;&#039;: The currently loaded plugin preset, or “patch”. The number of available preset slots varies from plugin to plugin; some do not have any presets at all.&lt;br /&gt;
* &#039;&#039;&#039;Load Preset&#039;&#039;&#039;: Use this to load an existing plugin preset or bank (.fxp or .fxb file).&lt;br /&gt;
* &#039;&#039;&#039;Save Preset&#039;&#039;&#039;: Use this to save the current plugin parameters to a plugin preset or bank file.&lt;br /&gt;
* &#039;&#039;&#039;Parameter&#039;&#039;&#039;: Pick a parameter from this list to edit it using the slider below. You can either drag the slider to adjust the value, or input a parameter using the text box next to it. Use the &#039;&#039;&#039;Set&#039;&#039;&#039; button to apply the value you typed into the text box.&lt;br /&gt;
&lt;br /&gt;
[[Image: Plugin Dry Wet Ratio.png|thumb|300px|The “Expand” option changes the behaviour of the Dry / Wet ratio setting.]]&lt;br /&gt;
&lt;br /&gt;
=== Mix Settings ===&lt;br /&gt;
&lt;br /&gt;
This option group is used to set up the inputs and outputs of the plugin.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Master&#039;&#039;&#039;: When enabled, this plugin is applied to the master audio output.&lt;br /&gt;
* &#039;&#039;&#039;Bypass&#039;&#039;&#039;: If checked, the plugin is not processed anymore. An instrument plugin will cease to make sound and effect plugins will stop having an effect on the audio that is routed through them.&lt;br /&gt;
* &#039;&#039;&#039;Expand&#039;&#039;&#039;: This option affects the Dry / Wet setting. Normally, the Dry / Wet ratio ranges from 100% Wet / 0% Dry to 0% Wet / 100% Dry, but with this setting, it ranges from 100% Wet / -100% Dry to -100% Wet / 100% Dry. A negative value means that the phase of the signal is inverted. So if the slider is full left, you get to hear the wet signal as well as an inverted copy of the dry signal, at the middle you get no output at all (0% Wet / 0% Dry) and if the slider is full right, you get the original signal plus an inverted copy of the wet signal. While being potentially interesting conceptually, this setting is unlikely to be useful musically. This setting is not available for plugins with no inputs.&lt;br /&gt;
* &#039;&#039;&#039;Dry Mix&#039;&#039;&#039;: If enabled, the dry (incoming) signal is added to the output signal of a plugin, in addition to the dry amount of the Dry / Wet slider. This is most commonly used for plugins that have no Dry / Wet mix settings built in. For example, in a delay plugin with no dry signal, all you get is the later echoes with no original sound, which is not what you normally want. In that case, you can enable Dry Mix to add the original signal.&lt;br /&gt;
* &#039;&#039;&#039;Auto-Suspend&#039;&#039;&#039;: If enabled, the plugin will be suspended temporarily if it has not received any input (MIDI or audio) and also not produced any output for several seconds. If a plugin gets confused by the observed discontinuity in time, or if its output contains long intentional passages of silences that do not correlate with any input, this option can be turned off.&lt;br /&gt;
* &#039;&#039;&#039;Mix Mode&#039;&#039;&#039;: This determines how the Wet / Dry ratio affects the output signal. Several options are available:&lt;br /&gt;
** &#039;&#039;&#039;Default&#039;&#039;&#039;: No special processing.&lt;br /&gt;
** &#039;&#039;&#039;Wet Subtract&#039;&#039;&#039;: The Dry signal is added to the mix, the Wet signal (multiplied by the Wet ratio) is subtracted from the mix.&lt;br /&gt;
** &#039;&#039;&#039;Dry Subtract&#039;&#039;&#039;: The Wet signal is added to the mix, the Dry signal (multiplied by the Dry ratio) is subtracted from the mix.&lt;br /&gt;
** &#039;&#039;&#039;Mix Subtract&#039;&#039;&#039;: The Wet signal is subtracted from the mix, the Dry signal (multiplied by the Wet ratio) is added to the mix.&lt;br /&gt;
** &#039;&#039;&#039;Middle Subtract&#039;&#039;&#039;: The Middle channel is subtracted from the mix, then the dry and wet signal are added normally.&lt;br /&gt;
** &#039;&#039;&#039;LR Balance&#039;&#039;&#039;: The Wet / Dry ratio is treated as a panning ratio for the signal.&lt;br /&gt;
** &#039;&#039;&#039;Instrument&#039;&#039;&#039;: Same as default, but the dry ratio is forced to 1 (old behaviour of instrument plugins prior to OpenMPT 1.32.00.11, regardless of their mix mode).&lt;br /&gt;
* &#039;&#039;&#039;Gain&#039;&#039;&#039;: This adjusts the volume of the plugin from 0.1 - 8.0 in increments of 0.1. This is used to reduce or boost the volume of plugins that are quieter or louder than desired. The default gain is 1.0 (no change in volume).&lt;br /&gt;
* &#039;&#039;&#039;Output To&#039;&#039;&#039;: Specifies where the plugin′s audio and MIDI output is routed to. By default it is combined into the Master Audio route, but you can create a plugin chain by routing it to another plugin as long as its slot number is higher than the current plugin′s slot. Note that MIDI events are only routed if an output plugin is specified, i.e. they are not routed to the master.&lt;br /&gt;
* &#039;&#039;&#039;Dry / Wet Slider&#039;&#039;&#039;: Controls the Dry / Wet ratio of the plugin. The exact meaning of the ratio is determined by the “Expand”, “Dry Mix” and “Mix Mode” options described above.&lt;br /&gt;
&lt;br /&gt;
[[Category:Manual|General Tab]]&lt;br /&gt;
[[Category:Tabs|General Tab]]&lt;br /&gt;
[[de:Handbuch: General]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4537</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4537"/>
		<updated>2024-05-07T23:47:41Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* FX00, ... FX99, F100, ... F255 */ fixed a few mistakes, changed mix mode descriptions, and added the new Instrument mix mode&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]  || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32   || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Plugin Type&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;VST plugins: &amp;lt;code&amp;gt;PtsV&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DMO plugins: &amp;lt;code&amp;gt;OMXD&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Internal plugins use various other IDs.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4      || char[4]   || Unique Plugin ID&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint8     || Routing Flags&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x01: Apply to master mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x02: Bypass&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x04: Dry mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x08: Expand mix [0%,100%] → [-100%,100%]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x10: Auto-suspend on silence&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9      || uint8     || Mix mode&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0: Default&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;1: Wet Subtract&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;2: Dry Subtract&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3: Mix Subtract&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;4: Middle Subtract&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;5: L/R Balance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;6: Instrument (same as default, but forces dry ratio to 1)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
Prior to OpenMPT 1.32.00.11, instrument plugins behaved like the &amp;quot;Instrument&amp;quot; mix mode regardless of their actual mix mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
This was fixed in 1.32.00.11, and the &amp;quot;Instrument&amp;quot; mix mode was added to emulate the old behaviour for old modules.&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint8     || Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
|-&lt;br /&gt;
| 11     || uint8     || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint32    || Output Routing (0 = send to master 0x80 + x = send to plugin x)&lt;br /&gt;
|-&lt;br /&gt;
| 16     || uint8[16] || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 32     || char[32]  || User-chosen plugin name (Windows code page)&lt;br /&gt;
|-&lt;br /&gt;
| 64     || char[64]  || Library name (Original DLL name / DMO identifier).&amp;lt;br/&amp;gt;UTF-8 (max. 64 bytes) since OpenMPT 1.22.07.01, Windows code page in older versions.&lt;br /&gt;
|-&lt;br /&gt;
| 128    || uint32    || Size of plugin-specific data in bytes (parameters or opaque chunk)&lt;br /&gt;
|-&lt;br /&gt;
| 132    || uint8[]   || Plugin-specific data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk opcodes, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Synth Pre-Amp (VSTi / OPL)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. In this case, the i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors must be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || VarInt    || Length of the filename&lt;br /&gt;
|-&lt;br /&gt;
| ?      || char[]    || Filename (UTF-8, not null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform must be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. must be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data must be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag must be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint16    || Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
|-&lt;br /&gt;
| 2      || uint32    || Number of items in the order list&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint32[]  || The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int32&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the Tuning Collection version is 2.&lt;br /&gt;
* uint32 if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint32&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is uint32. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| float32&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* uint32 if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as uint32 instead of uint16 and uint8 respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Default panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint16    || Default volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint16    || Global volume (0...64)&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint16    || (Reserved, must be 0)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint8     || Auto-vibrato type &amp;lt;!-- todo: list the types --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 13     || uint8     || Auto-vibrato sweep&lt;br /&gt;
|-&lt;br /&gt;
| 14     || uint8     || Auto-vibrato depth&lt;br /&gt;
|-&lt;br /&gt;
| 15     || uint8     || Auto-vibrato rate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard Vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 1,048,575&amp;amp;nbsp;Hz (655350&amp;amp;nbsp;Hz for older versions).&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_Formats/IT&amp;diff=4535</id>
		<title>Development: Formats/IT</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_Formats/IT&amp;diff=4535"/>
		<updated>2024-05-02T19:48:40Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* ModPlug Tracker */ fix another typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;General information concerning the IT file format. Any variable names in this document refer to the original variable names from [https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT ITTECH.TXT]. Variable names and hexadecimal numbers (in little-endian formats) are indicated by a &amp;lt;tt&amp;gt;monospace font&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note: Impulse tracker is now open source! You can grab the [https://github.com/sagamusix/impulsetracker source code] at GitHub.&lt;br /&gt;
&lt;br /&gt;
== Tracker IDs ==&lt;br /&gt;
&lt;br /&gt;
The IT header contains a field, &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, which is used to identify the application that was used to create the file.&lt;br /&gt;
The following custom tracker IDs (read as little-endian hexadecimal numbers) are known to be found in the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;0xyy&amp;lt;/tt&amp;gt; - Impulse Tracker x.yy - Many other trackers, like ModPlug Tracker, disguise as various versions of Impulse Tracker, so this is &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; a reliable way to tell if a file was really made with Impulse Tracker. See [[#Detecting other trackers|below]] for detecting such trackers.&lt;br /&gt;
* &amp;lt;tt&amp;gt;1xyy&amp;lt;/tt&amp;gt; - Schism Tracker x.yy up to Schism Tracker v0.50, later versions encode a timestamp in the version number - see Schism Tracker’s &amp;lt;tt&amp;gt;[https://github.com/schismtracker/schismtracker/blob/master/schism/version.c version.c]&amp;lt;/tt&amp;gt; or OpenMPT’s &amp;lt;tt&amp;gt;[https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/soundlib/Load_it.cpp Load_it.cpp]&amp;lt;/tt&amp;gt; for a version not relying on the C runtime library (since &amp;lt;tt&amp;gt;localtime&amp;lt;/tt&amp;gt; is not guaranteed to be thread-safe).&lt;br /&gt;
* &amp;lt;tt&amp;gt;4xyy&amp;lt;/tt&amp;gt; - pyIT x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;5xyy&amp;lt;/tt&amp;gt; - OpenMPT x.yy - lower two bytes of version number are stored in the &amp;quot;reserved&amp;quot; header field starting from OpenMPT 1.29.10.00 in compatible mode (otherwise OpenMPT song extensions are used as before).&lt;br /&gt;
* &amp;lt;tt&amp;gt;6xyy&amp;lt;/tt&amp;gt; - BeRoTracker x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;7xyz&amp;lt;/tt&amp;gt; - ITMCK x.y.z (N.B. the user can override the value of the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; header by the &amp;lt;tt&amp;gt;-w&amp;lt;/tt&amp;gt; command-line switch or the &amp;lt;tt&amp;gt;#TRACKER-VERSION&amp;lt;/tt&amp;gt; command in the input file)&lt;br /&gt;
* &amp;lt;tt&amp;gt;7FFF&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt = 0215&amp;lt;/tt&amp;gt;: munch.py&lt;br /&gt;
* &amp;lt;tt&amp;gt;8xyy&amp;lt;/tt&amp;gt; - Tralala x.yy; prealpha versions, built from svn, before the first release identify as version 0.00 (i.e. Cwt/v=8000)&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cxyy&amp;lt;/tt&amp;gt; - ChickDune ChipTune Tracker x.yy (currently non-public alpha version)&lt;br /&gt;
* &amp;lt;tt&amp;gt;DAEB&amp;lt;/tt&amp;gt; - spc2it (after commit d3d1b524032f668be8ee20d25339e1c635fb9bcf)&lt;br /&gt;
&lt;br /&gt;
Are you a tracker developer and your tracker can save IT files? Please add your Tracker ID to this list!&lt;br /&gt;
&lt;br /&gt;
Once we run out of tracker IDs, a more sophisticated approach will have to be found. For example, the ID &amp;lt;tt&amp;gt;0FFF&amp;lt;/tt&amp;gt; could be reserved, and a pointer to extended tracker information could be placed in the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; header field.&lt;br /&gt;
&lt;br /&gt;
== Detecting other trackers ==&lt;br /&gt;
&lt;br /&gt;
Some trackers disguise as Impulse Tracker 2, but there are ways to uncover this diguise:&lt;br /&gt;
&lt;br /&gt;
=== BeRoTracker ===&lt;br /&gt;
&lt;br /&gt;
Earlier versions of BeRoTracker, which did not use the tracker ID described above, can be identified by the four byte &amp;lt;tt&amp;gt;MODU&amp;lt;/tt&amp;gt; magic which can be found after the Edit History / MIDI Macro / ModPlug extension block. &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0217&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt; (overlaps with ModPlug Tracker). The edit history flag is set and there are always 0 entries in the edit history.&lt;br /&gt;
&lt;br /&gt;
=== CheeseTracker ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are both &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Instrument mode flag is always set. The only other flags that can be optionally set are: Stereo Mode, Linear Slides, Old Effects, Compatible Gxx.&lt;br /&gt;
* The only &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag ever set is the song message flag (even though row highlights are always written).&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;&lt;br /&gt;
* All sample and instrument filenames read &amp;lt;tt&amp;gt;XXXXXXXX.YYY&amp;lt;/tt&amp;gt; (obviously this should not be used as a stand-alone detection criterion, as files re-saved with other trackers will still use these filenames).&lt;br /&gt;
&lt;br /&gt;
=== ChibiTracker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are both &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; reads &amp;lt;tt&amp;gt;CHBI&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Further interesting criteria: Sample data is stored directly after header. All sample and instrument filenames read &amp;lt;tt&amp;gt;-DEPRECATED-&amp;lt;/tt&amp;gt; (obviously this should not be used as a stand-alone detection criterion, as files re-saved with other trackers will still use these filenames). ChibiTracker also uses a line feed character (&amp;lt;tt&amp;gt;0A&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt;) instead of a carriage return (&amp;lt;tt&amp;gt;0D&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\r&amp;lt;/tt&amp;gt;) in the song message.&lt;br /&gt;
&lt;br /&gt;
=== ModPlug Tracker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 pre-alpha 4 (and possibly earlier) - 1.0 alpha 4&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0202&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, row highlights are both 0. These attributes alone are not enough to fingerprint these ModPlug Tracker versions, but luckily it also stores the remaining data in a very peculiar order: patterns first, then instrument headers, and then interleaves sample headers and their corresponding sample data. These versions also do not optimize empty 64-row patterns with a 0 parapointer, so they can be identified by checking if the first pattern parapointer is not 0 and less than the first sample parapointer.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 alpha 5&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Pattern highlights and edit history flags are not set. Instruments are 560 bytes apart.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 alpha 6 / beta 1 / beta 2&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Pattern highlights and edit history flags are set. Instruments are 560 bytes apart up to and including beta 1, in beta 2 they are 557 bytes apart.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 beta 3.2 - 1.07&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0202&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Instruments are 557 bytes apart.&lt;br /&gt;
* Newer versions of &#039;&#039;&#039;ModPlug Tracker&#039;&#039;&#039;, &#039;&#039;&#039;OpenMPT 1.17 in compatible mode&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0217&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. If there are any instruments in the file, the instrument &amp;lt;tt&amp;gt;TrkVers&amp;lt;/tt&amp;gt; field is &amp;lt;tt&amp;gt;0211&amp;lt;/tt&amp;gt; for ModPlug Tracker and &amp;lt;tt&amp;gt;0220&amp;lt;/tt&amp;gt; for OpenMPT. ModPlug Tracker writes &amp;lt;tt&amp;gt;FF&amp;lt;/tt&amp;gt; for unused channels in the panning map, OpenMPT never does this. When an IT file uses all 64 channels (so the panning map cannot be used for distinction), the presence of ModPlug extensions (channel names, plugin chunks, etc.) can help telling MPT 1.16 and OpenMPT 1.17 compatibility export apart. The latter also does not save a final &amp;quot;---&amp;quot; order list item, while MPT 1.16 does.&lt;br /&gt;
&lt;br /&gt;
=== OpenMPT ===&lt;br /&gt;
&lt;br /&gt;
* OpenMPT 1.17.02.20 to OpenMPT 1.17.02.25 wrote the value &amp;lt;tt&amp;gt;0300&amp;lt;/tt&amp;gt; in both the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; fields.&lt;br /&gt;
* OpenMPT 1.17.02.26 to OpenMPT 1.18 wrote the value &amp;lt;tt&amp;gt;0888&amp;lt;/tt&amp;gt; in both the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; fields.&lt;br /&gt;
* Later versions of OpenMPT use the tracker ID provided above. In that case, the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; field reads &amp;lt;tt&amp;gt;OMPT&amp;lt;/tt&amp;gt; if the file was saved in normal mode, and is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (or the lower two bytes of version information starting from OpenMPT 1.29.10.00) if it was saved in compatible mode.&lt;br /&gt;
&lt;br /&gt;
=== OpenSPC conversions ===&lt;br /&gt;
&lt;br /&gt;
OpenSPC is a tool to convert SNES music from the SPC format to the IT format. If all the following conditions are true, you can be fairly sure that a module was written with OpenSPC:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;09&amp;lt;/tt&amp;gt; (Linear Slides, Stereo Playback).&lt;br /&gt;
* &amp;lt;tt&amp;gt;Special&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Both pattern highlight values are &amp;lt;tt&amp;gt;00&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* No instruments are used.&lt;br /&gt;
* &amp;lt;tt&amp;gt;PatNum&amp;lt;/tt&amp;gt; + 1 == &amp;lt;tt&amp;gt;OrdNum&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Global volume is 128 decimal.&lt;br /&gt;
* Master volume is 100 decimal.&lt;br /&gt;
* Initial Speed is 1.&lt;br /&gt;
* Pan Separation is 128 decimal.&lt;br /&gt;
* Pitch wheel depth is 0.&lt;br /&gt;
* There is no song message, i.e. message length and offset are 0.&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is 0.&lt;br /&gt;
&lt;br /&gt;
Earlier versions of spc2it (before commit d3d1b524032f668be8ee20d25339e1c635fb9bcf) will be mis-identified as OpenSPC, as the tool closely follows the way its predecessor writes out IT files.&lt;br /&gt;
&lt;br /&gt;
=== Unknown XM to IT conversion tool ===&lt;br /&gt;
&lt;br /&gt;
There is a currently unknown XM to IT conversion tool which can be identified easily by the fact that it writes unsigned samples (which was the default only until Impulse Tracker 2.01). However, only sample slots with actual sample data should be considered for this test, as re-saving such a file in Impulse Tracker will not reset the unsigned flag for empty slots. If the following conditions are true, you can be fairly sure that a module was written with the unknown converter:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0204&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt;: Stereo Playback, Instrument Mode, Old Effects are always set, Linear Slides are optional.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Special&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Both pattern highlight values are &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Global volume is 128 decimal.&lt;br /&gt;
* Master volume is 48 decimal.&lt;br /&gt;
* Pan Separation is 128 decimal.&lt;br /&gt;
* Pitch wheel depth is 0.&lt;br /&gt;
* There is no song message, i.e. message length and offset are 0.&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is 0.&lt;br /&gt;
* Song title is no longer than 20 characters.&lt;br /&gt;
* All channels are panned centre (32) or muted, and their volume is 64 decimal.&lt;br /&gt;
&lt;br /&gt;
To be extra sure, you can check all of these properties, but just checking &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; and unsigned sample data is probably enough.&lt;br /&gt;
&lt;br /&gt;
=== UNMO3 ===&lt;br /&gt;
&lt;br /&gt;
UNMO3 is a tool to convert an MO3-compressed module file back into its original format.&lt;br /&gt;
&lt;br /&gt;
In IT files created with UNMO3, the following are always true:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;pwd&amp;lt;/tt&amp;gt; is 0&lt;br /&gt;
* Both row highlights are 0&lt;br /&gt;
* Flags: Use MIDI Pitch Controller (bit 6) and Request embedded MIDI configuration (bit 7) are never set&lt;br /&gt;
&lt;br /&gt;
This partially overlaps with Impulse Tracker 2.14 and CheeseTracker fingerprints, however:&lt;br /&gt;
* CheeseTracker should write non-zero row highlights, even when resaving an UNMO3-ed file.&lt;br /&gt;
* It is highly unlikely that Impulse Tracker 2.14 writes a &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; value of &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. If it writes zero row highlights, the row highlight &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag is set.&lt;br /&gt;
* Impulse Tracker 2.14 never writes an empty edit history (see below).&lt;br /&gt;
* CheeseTracker always uses instrument mode.&lt;br /&gt;
&lt;br /&gt;
Some older versions of UNMO3 write out IT files that are malformed in some way or another, but it is easy to detect and work around. Some UNMO3-ed IT files are floating around in the wild, so it may be worthwile to implement those work-arounds:&lt;br /&gt;
&lt;br /&gt;
==== Special flags prior UNMO3 2.4.0.2 ====&lt;br /&gt;
&lt;br /&gt;
* UNMO3 2.4 (released in 2008) and older sets the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag bits 1 (edit history) and 2 (row highlights) whenever bit 3 (MIDI macros) is set as well.&lt;br /&gt;
* UNMO3 2.4.0.1 (January 2011) always sets the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag bit 1 (edit history), but the behaviour for bit 2 (row highlights) remains as in previous versions.&lt;br /&gt;
* UNMO3 2.4.0.2 (July 2011) never sets the row highlights flag.&lt;br /&gt;
&lt;br /&gt;
==== Sample mode prior to UNMO3 2.4.0.1 ====&lt;br /&gt;
&lt;br /&gt;
UNMO3 2.4 and older reserves space for the instrument parapointers (as many as there are samples) even when the IT file is in sample mode. This can be detected by the fact that 4 * &amp;lt;tt&amp;gt;SmpNum&amp;lt;/tt&amp;gt; zero bytes follow after the pattern parapointers. These bytes need to be skipped in order to be able to read MIDI macros and ModPlug plugin settings which may potentially follow.&lt;br /&gt;
&lt;br /&gt;
UNMO3 2.4.0.1 fixes this problem.&lt;br /&gt;
&lt;br /&gt;
==== Edit History prior to UNMO3 2.4.0.1 ====&lt;br /&gt;
&lt;br /&gt;
As mentioned above, UNMO3 older than version 2.4.0.1 may or may not set the edit history flag, but they always write two edit history length bytes (zeroes) in the file anyway. Keep this in mind, as MIDI Macros and ModPlug plugin settings will not load properly if you don’t.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Edit history flag is set&#039;&#039;&#039;: Nothing needs to be done. We can still use this for identifying UNMO3-saved IT files, because Impulse Tracker never writes an edit history of length 0.&lt;br /&gt;
* &#039;&#039;&#039;Edit history flag is not set&#039;&#039;&#039;: This is the troublesome case due to MIDI macros and plugin settings. However, a reliable way to detect such malformed IT files would be to try to read the edit history length if all of the above detection criteria for UNMO3 are fulfilled. For those old UNMO3 versions, you should read two zero bytes. If that is the case, it means that the first MIDI macro would be empty (if MIDI macros are embedded) or the first plugin chunk ID starts with two zero bytes (impossible). Since UNMO3 writes out default values for the nine global MIDI macros, the first MIDI macro would have to start with “FF” (MIDI Start) and not be empty, so it is clear that the two zero bytes belong to the (empty) edit history.&lt;br /&gt;
&lt;br /&gt;
Later version of UNMO3 set the correct header flag for the edit history and write the two zero length bytes.&lt;br /&gt;
&lt;br /&gt;
== Special Header Flags ==&lt;br /&gt;
&lt;br /&gt;
The following &amp;quot;Special&amp;quot; flags are not documented:&lt;br /&gt;
&lt;br /&gt;
* Bit 1 (&amp;lt;tt&amp;gt;02&amp;lt;/tt&amp;gt;): If set, edit history information (see [[#Edit History|below]]) is present.&lt;br /&gt;
* Bit 2 (&amp;lt;tt&amp;gt;04&amp;lt;/tt&amp;gt;): If set, the row highlights (at offset &amp;lt;tt&amp;gt;1E&amp;lt;/tt&amp;gt; - &amp;lt;tt&amp;gt;1F&amp;lt;/tt&amp;gt;) should be read. If not set, they should be ignored.&lt;br /&gt;
&lt;br /&gt;
== Edit History ==&lt;br /&gt;
    &lt;br /&gt;
It is little known that the latest versions of Impulse Tracker keep track of when an IT file is opened and how long it is left open.&lt;br /&gt;
The edit history can be found directly after the IT header and before the possibly present MIDI macro configuration.&lt;br /&gt;
&lt;br /&gt;
A 16-Bit integer &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; tells how many edit history blocks are present. Every block is 8 bytes long, so the 16-bit integer is followed by &amp;lt;tt&amp;gt;8 * num&amp;lt;/tt&amp;gt; bytes of edit history information.&lt;br /&gt;
&lt;br /&gt;
Each history block consists of a 16-Bit FAT date, a 16-Bit FAT time and a 32-Bit DOS timer, which contains the time how long the file was open in the editor, in 1/18.2th seconds.&lt;br /&gt;
Information on how to decode the FAT date and time stamps can be found on the [https://msdn.microsoft.com/en-us/library/windows/desktop/ms724247%28v=vs.85%29.aspx MSDN].&lt;br /&gt;
&lt;br /&gt;
Note: Many programs don’t write an edit history, but they set the edit history flag in the header and write the two zero bytes for the history length. Many of them also ignore the edit history flag when loading files and always read the two &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; num bytes (ignoring the special flag), so if you want to write out an IT file that does not have an edit history and do not mind about the two extra bytes, the safest (most compatible) way is to set the edit history flag and write two zero bytes for &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Also note that none of this is really relevant if you are sure that you never write out the MIDI macro configuration or ModPlug extensions, since these are the only two things that could normally follow the edit history. So if you have no MIDI macros and no ModPlug extensions, it is always safe to not set the special flag and not write the two extra bytes.&lt;br /&gt;
&lt;br /&gt;
== Edit Timer ==&lt;br /&gt;
&lt;br /&gt;
Before the addition of the full Edit History, a simple Edit Timer was stored in the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; field of the file header. Starting from Impulse Tracker 2.07, this field contains the total edit time as a 32-Bit DOS timer (same resolution as in the Edit History). Starting from Impulse Tracker 2.08, the timer is encrypted. To decrypt:&lt;br /&gt;
&lt;br /&gt;
 editTime = editTime XOR &#039;ITRK&#039;&lt;br /&gt;
 editTime = editTime RoR 7&lt;br /&gt;
 editTime = -editTime&lt;br /&gt;
 editTime = editTime RoL 4&lt;br /&gt;
 editTime = editTime XOR &#039;JTHL&#039;&lt;br /&gt;
&lt;br /&gt;
== Proposed way to store compressed stereo samples ==&lt;br /&gt;
&lt;br /&gt;
Since Impulse Tracker itself does not support stereo samples, a common way of how to decode compressed stereo samples had to be found - After all, it is possible to just treat them as one continuous stream (not stopping the encoding / decoding process after the end of the left channel), or to treat them as two separate, consecutive streams. XMPlay was probably the only player that could handle compressed stereo samples even before there was a single implementation for saving compressed stereo samples. GreaseMonkey has decided to follow [https://www.un4seen.com/forum/?topic=12448.msg86479#msg86479 XMPlay&#039;s way] of decoding compressed stereo samples by treating them as two streams of the same length, so OpenMPT follows this example. If you intend to add IT sample compression support in your application, you should do the same to ensure compatibility across as many applications as possible.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Hacks ==&lt;br /&gt;
&lt;br /&gt;
For a list of all the file format hacks that ModPlug Tracker / OpenMPT added to the IT format over the years, see the [[Development: OpenMPT Format Extensions|OpenMPT Format Extensions]] article.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Formats/IT]]&lt;br /&gt;
[[Category:IT Format|Format Specification]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_Formats/IT&amp;diff=4534</id>
		<title>Development: Formats/IT</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_Formats/IT&amp;diff=4534"/>
		<updated>2024-05-02T19:45:40Z</updated>

		<summary type="html">&lt;p&gt;CS127: fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;General information concerning the IT file format. Any variable names in this document refer to the original variable names from [https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT ITTECH.TXT]. Variable names and hexadecimal numbers (in little-endian formats) are indicated by a &amp;lt;tt&amp;gt;monospace font&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note: Impulse tracker is now open source! You can grab the [https://github.com/sagamusix/impulsetracker source code] at GitHub.&lt;br /&gt;
&lt;br /&gt;
== Tracker IDs ==&lt;br /&gt;
&lt;br /&gt;
The IT header contains a field, &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, which is used to identify the application that was used to create the file.&lt;br /&gt;
The following custom tracker IDs (read as little-endian hexadecimal numbers) are known to be found in the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; field:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;0xyy&amp;lt;/tt&amp;gt; - Impulse Tracker x.yy - Many other trackers, like ModPlug Tracker, disguise as various versions of Impulse Tracker, so this is &amp;lt;strong&amp;gt;not&amp;lt;/strong&amp;gt; a reliable way to tell if a file was really made with Impulse Tracker. See [[#Detecting other trackers|below]] for detecting such trackers.&lt;br /&gt;
* &amp;lt;tt&amp;gt;1xyy&amp;lt;/tt&amp;gt; - Schism Tracker x.yy up to Schism Tracker v0.50, later versions encode a timestamp in the version number - see Schism Tracker’s &amp;lt;tt&amp;gt;[https://github.com/schismtracker/schismtracker/blob/master/schism/version.c version.c]&amp;lt;/tt&amp;gt; or OpenMPT’s &amp;lt;tt&amp;gt;[https://source.openmpt.org/browse/openmpt/trunk/OpenMPT/soundlib/Load_it.cpp Load_it.cpp]&amp;lt;/tt&amp;gt; for a version not relying on the C runtime library (since &amp;lt;tt&amp;gt;localtime&amp;lt;/tt&amp;gt; is not guaranteed to be thread-safe).&lt;br /&gt;
* &amp;lt;tt&amp;gt;4xyy&amp;lt;/tt&amp;gt; - pyIT x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;5xyy&amp;lt;/tt&amp;gt; - OpenMPT x.yy - lower two bytes of version number are stored in the &amp;quot;reserved&amp;quot; header field starting from OpenMPT 1.29.10.00 in compatible mode (otherwise OpenMPT song extensions are used as before).&lt;br /&gt;
* &amp;lt;tt&amp;gt;6xyy&amp;lt;/tt&amp;gt; - BeRoTracker x.yy&lt;br /&gt;
* &amp;lt;tt&amp;gt;7xyz&amp;lt;/tt&amp;gt; - ITMCK x.y.z (N.B. the user can override the value of the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; header by the &amp;lt;tt&amp;gt;-w&amp;lt;/tt&amp;gt; command-line switch or the &amp;lt;tt&amp;gt;#TRACKER-VERSION&amp;lt;/tt&amp;gt; command in the input file)&lt;br /&gt;
* &amp;lt;tt&amp;gt;7FFF&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt = 0215&amp;lt;/tt&amp;gt;: munch.py&lt;br /&gt;
* &amp;lt;tt&amp;gt;8xyy&amp;lt;/tt&amp;gt; - Tralala x.yy; prealpha versions, built from svn, before the first release identify as version 0.00 (i.e. Cwt/v=8000)&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cxyy&amp;lt;/tt&amp;gt; - ChickDune ChipTune Tracker x.yy (currently non-public alpha version)&lt;br /&gt;
* &amp;lt;tt&amp;gt;DAEB&amp;lt;/tt&amp;gt; - spc2it (after commit d3d1b524032f668be8ee20d25339e1c635fb9bcf)&lt;br /&gt;
&lt;br /&gt;
Are you a tracker developer and your tracker can save IT files? Please add your Tracker ID to this list!&lt;br /&gt;
&lt;br /&gt;
Once we run out of tracker IDs, a more sophisticated approach will have to be found. For example, the ID &amp;lt;tt&amp;gt;0FFF&amp;lt;/tt&amp;gt; could be reserved, and a pointer to extended tracker information could be placed in the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; header field.&lt;br /&gt;
&lt;br /&gt;
== Detecting other trackers ==&lt;br /&gt;
&lt;br /&gt;
Some trackers disguise as Impulse Tracker 2, but there are ways to uncover this diguise:&lt;br /&gt;
&lt;br /&gt;
=== BeRoTracker ===&lt;br /&gt;
&lt;br /&gt;
Earlier versions of BeRoTracker, which did not use the tracker ID described above, can be identified by the four byte &amp;lt;tt&amp;gt;MODU&amp;lt;/tt&amp;gt; magic which can be found after the Edit History / MIDI Macro / ModPlug extension block. &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0217&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt; (overlaps with ModPlug Tracker). The edit history flag is set and there are always 0 entries in the edit history.&lt;br /&gt;
&lt;br /&gt;
=== CheeseTracker ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are both &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Instrument mode flag is always set. The only other flags that can be optionally set are: Stereo Mode, Linear Slides, Old Effects, Compatible Gxx.&lt;br /&gt;
* The only &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag ever set is the song message flag (even though row highlights are always written).&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;&lt;br /&gt;
* All sample and instrument filenames read &amp;lt;tt&amp;gt;XXXXXXXX.YYY&amp;lt;/tt&amp;gt; (obviously this should not be used as a stand-alone detection criterion, as files re-saved with other trackers will still use these filenames).&lt;br /&gt;
&lt;br /&gt;
=== ChibiTracker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are both &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; reads &amp;lt;tt&amp;gt;CHBI&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Further interesting criteria: Sample data is stored directly after header. All sample and instrument filenames read &amp;lt;tt&amp;gt;-DEPRECATED-&amp;lt;/tt&amp;gt; (obviously this should not be used as a stand-alone detection criterion, as files re-saved with other trackers will still use these filenames). ChibiTracker also uses a line feed character (&amp;lt;tt&amp;gt;0A&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt;) instead of a carriage return (&amp;lt;tt&amp;gt;0D&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\r&amp;lt;/tt&amp;gt;) in the song message.&lt;br /&gt;
&lt;br /&gt;
=== ModPlug Tracker ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 pre-alpha 4 (and possibly earlier) - 1.0 alpha 4&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0202&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, row highlights are both 0. These attributes alone are not enough to fingerprint these ModPlug Tracker versions, but luckily it also stores the remaining data in a very peculiar order: patterns first, then instrument headers, and then interleaves sample headers and their corresponding sample data. These versions also do not optimize empty 64-row patterns with a 0 parapointer, so they can be identified by checking if the first pattern parapointer is not 0 and less than the first sample parapointer.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 alpha 5&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Pattern highlights and edit history flags are not set. Instruments are 560 bytes apart.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 alpha 6 / beta 1 / beta 2&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Pattern highlights and edit history flags are set. Instruments are 560 bytes apart up to and including beta 1, in beta 2 they are 557 bytes apart.&lt;br /&gt;
* &#039;&#039;&#039;ModPlug Tracker 1.0 beta 3.2 - 1.07&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0202&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. Instruments are 557 bytes apart.&lt;br /&gt;
* Newer versions of &#039;&#039;&#039;ModPlug Tracker&#039;&#039;&#039;, &#039;&#039;&#039;OpenMPT 1.17 in compatible mode&#039;&#039;&#039;: &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0217&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. If there are any instruments in the file, the instrument &amp;lt;tt&amp;gt;TrkVers&amp;lt;/tt&amp;gt; field is &amp;lt;tt&amp;gt;0211&amp;lt;/tt&amp;gt; for ModPlug Tracker and &amp;lt;tt&amp;gt;0220&amp;lt;/tt&amp;gt; for OpenMPT. ModPlug Tracker writes &amp;lt;tt&amp;gt;FF&amp;lt;/tt&amp;gt; for unused channels in the panning map, OpenMPT never does this. When an IT file uses all 64 channels (so the panning map cannot be used for distinction), the presence of ModPlug extensions (channel names, plugin chunks, etc.) can help telling MPT 1.16 and OpenMPT 1.17 compatibility export apart. The latter also does not save a final &amp;quot;---&amp;quot; oder list item, while MPT 1.16 does.&lt;br /&gt;
&lt;br /&gt;
=== OpenMPT ===&lt;br /&gt;
&lt;br /&gt;
* OpenMPT 1.17.02.20 to OpenMPT 1.17.02.25 wrote the value &amp;lt;tt&amp;gt;0300&amp;lt;/tt&amp;gt; in both the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; fields.&lt;br /&gt;
* OpenMPT 1.17.02.26 to OpenMPT 1.18 wrote the value &amp;lt;tt&amp;gt;0888&amp;lt;/tt&amp;gt; in both the &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; fields.&lt;br /&gt;
* Later versions of OpenMPT use the tracker ID provided above. In that case, the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; field reads &amp;lt;tt&amp;gt;OMPT&amp;lt;/tt&amp;gt; if the file was saved in normal mode, and is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (or the lower two bytes of version information starting from OpenMPT 1.29.10.00) if it was saved in compatible mode.&lt;br /&gt;
&lt;br /&gt;
=== OpenSPC conversions ===&lt;br /&gt;
&lt;br /&gt;
OpenSPC is a tool to convert SNES music from the SPC format to the IT format. If all the following conditions are true, you can be fairly sure that a module was written with OpenSPC:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;09&amp;lt;/tt&amp;gt; (Linear Slides, Stereo Playback).&lt;br /&gt;
* &amp;lt;tt&amp;gt;Special&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Both pattern highlight values are &amp;lt;tt&amp;gt;00&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* No instruments are used.&lt;br /&gt;
* &amp;lt;tt&amp;gt;PatNum&amp;lt;/tt&amp;gt; + 1 == &amp;lt;tt&amp;gt;OrdNum&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Global volume is 128 decimal.&lt;br /&gt;
* Master volume is 100 decimal.&lt;br /&gt;
* Initial Speed is 1.&lt;br /&gt;
* Pan Separation is 128 decimal.&lt;br /&gt;
* Pitch wheel depth is 0.&lt;br /&gt;
* There is no song message, i.e. message length and offset are 0.&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is 0.&lt;br /&gt;
&lt;br /&gt;
Earlier versions of spc2it (before commit d3d1b524032f668be8ee20d25339e1c635fb9bcf) will be mis-identified as OpenSPC, as the tool closely follows the way its predecessor writes out IT files.&lt;br /&gt;
&lt;br /&gt;
=== Unknown XM to IT conversion tool ===&lt;br /&gt;
&lt;br /&gt;
There is a currently unknown XM to IT conversion tool which can be identified easily by the fact that it writes unsigned samples (which was the default only until Impulse Tracker 2.01). However, only sample slots with actual sample data should be considered for this test, as re-saving such a file in Impulse Tracker will not reset the unsigned flag for empty slots. If the following conditions are true, you can be fairly sure that a module was written with the unknown converter:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0204&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0200&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Flags&amp;lt;/tt&amp;gt;: Stereo Playback, Instrument Mode, Old Effects are always set, Linear Slides are optional.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Special&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Both pattern highlight values are &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Global volume is 128 decimal.&lt;br /&gt;
* Master volume is 48 decimal.&lt;br /&gt;
* Pan Separation is 128 decimal.&lt;br /&gt;
* Pitch wheel depth is 0.&lt;br /&gt;
* There is no song message, i.e. message length and offset are 0.&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is 0.&lt;br /&gt;
* Song title is no longer than 20 characters.&lt;br /&gt;
* All channels are panned centre (32) or muted, and their volume is 64 decimal.&lt;br /&gt;
&lt;br /&gt;
To be extra sure, you can check all of these properties, but just checking &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; and unsigned sample data is probably enough.&lt;br /&gt;
&lt;br /&gt;
=== UNMO3 ===&lt;br /&gt;
&lt;br /&gt;
UNMO3 is a tool to convert an MO3-compressed module file back into its original format.&lt;br /&gt;
&lt;br /&gt;
In IT files created with UNMO3, the following are always true:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;Cwt/v&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;Cmwt&amp;lt;/tt&amp;gt; are &amp;lt;tt&amp;gt;0214&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;pwd&amp;lt;/tt&amp;gt; is 0&lt;br /&gt;
* Both row highlights are 0&lt;br /&gt;
* Flags: Use MIDI Pitch Controller (bit 6) and Request embedded MIDI configuration (bit 7) are never set&lt;br /&gt;
&lt;br /&gt;
This partially overlaps with Impulse Tracker 2.14 and CheeseTracker fingerprints, however:&lt;br /&gt;
* CheeseTracker should write non-zero row highlights, even when resaving an UNMO3-ed file.&lt;br /&gt;
* It is highly unlikely that Impulse Tracker 2.14 writes a &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; value of &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;. If it writes zero row highlights, the row highlight &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag is set.&lt;br /&gt;
* Impulse Tracker 2.14 never writes an empty edit history (see below).&lt;br /&gt;
* CheeseTracker always uses instrument mode.&lt;br /&gt;
&lt;br /&gt;
Some older versions of UNMO3 write out IT files that are malformed in some way or another, but it is easy to detect and work around. Some UNMO3-ed IT files are floating around in the wild, so it may be worthwile to implement those work-arounds:&lt;br /&gt;
&lt;br /&gt;
==== Special flags prior UNMO3 2.4.0.2 ====&lt;br /&gt;
&lt;br /&gt;
* UNMO3 2.4 (released in 2008) and older sets the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag bits 1 (edit history) and 2 (row highlights) whenever bit 3 (MIDI macros) is set as well.&lt;br /&gt;
* UNMO3 2.4.0.1 (January 2011) always sets the &amp;lt;tt&amp;gt;special&amp;lt;/tt&amp;gt; flag bit 1 (edit history), but the behaviour for bit 2 (row highlights) remains as in previous versions.&lt;br /&gt;
* UNMO3 2.4.0.2 (July 2011) never sets the row highlights flag.&lt;br /&gt;
&lt;br /&gt;
==== Sample mode prior to UNMO3 2.4.0.1 ====&lt;br /&gt;
&lt;br /&gt;
UNMO3 2.4 and older reserves space for the instrument parapointers (as many as there are samples) even when the IT file is in sample mode. This can be detected by the fact that 4 * &amp;lt;tt&amp;gt;SmpNum&amp;lt;/tt&amp;gt; zero bytes follow after the pattern parapointers. These bytes need to be skipped in order to be able to read MIDI macros and ModPlug plugin settings which may potentially follow.&lt;br /&gt;
&lt;br /&gt;
UNMO3 2.4.0.1 fixes this problem.&lt;br /&gt;
&lt;br /&gt;
==== Edit History prior to UNMO3 2.4.0.1 ====&lt;br /&gt;
&lt;br /&gt;
As mentioned above, UNMO3 older than version 2.4.0.1 may or may not set the edit history flag, but they always write two edit history length bytes (zeroes) in the file anyway. Keep this in mind, as MIDI Macros and ModPlug plugin settings will not load properly if you don’t.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Edit history flag is set&#039;&#039;&#039;: Nothing needs to be done. We can still use this for identifying UNMO3-saved IT files, because Impulse Tracker never writes an edit history of length 0.&lt;br /&gt;
* &#039;&#039;&#039;Edit history flag is not set&#039;&#039;&#039;: This is the troublesome case due to MIDI macros and plugin settings. However, a reliable way to detect such malformed IT files would be to try to read the edit history length if all of the above detection criteria for UNMO3 are fulfilled. For those old UNMO3 versions, you should read two zero bytes. If that is the case, it means that the first MIDI macro would be empty (if MIDI macros are embedded) or the first plugin chunk ID starts with two zero bytes (impossible). Since UNMO3 writes out default values for the nine global MIDI macros, the first MIDI macro would have to start with “FF” (MIDI Start) and not be empty, so it is clear that the two zero bytes belong to the (empty) edit history.&lt;br /&gt;
&lt;br /&gt;
Later version of UNMO3 set the correct header flag for the edit history and write the two zero length bytes.&lt;br /&gt;
&lt;br /&gt;
== Special Header Flags ==&lt;br /&gt;
&lt;br /&gt;
The following &amp;quot;Special&amp;quot; flags are not documented:&lt;br /&gt;
&lt;br /&gt;
* Bit 1 (&amp;lt;tt&amp;gt;02&amp;lt;/tt&amp;gt;): If set, edit history information (see [[#Edit History|below]]) is present.&lt;br /&gt;
* Bit 2 (&amp;lt;tt&amp;gt;04&amp;lt;/tt&amp;gt;): If set, the row highlights (at offset &amp;lt;tt&amp;gt;1E&amp;lt;/tt&amp;gt; - &amp;lt;tt&amp;gt;1F&amp;lt;/tt&amp;gt;) should be read. If not set, they should be ignored.&lt;br /&gt;
&lt;br /&gt;
== Edit History ==&lt;br /&gt;
    &lt;br /&gt;
It is little known that the latest versions of Impulse Tracker keep track of when an IT file is opened and how long it is left open.&lt;br /&gt;
The edit history can be found directly after the IT header and before the possibly present MIDI macro configuration.&lt;br /&gt;
&lt;br /&gt;
A 16-Bit integer &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; tells how many edit history blocks are present. Every block is 8 bytes long, so the 16-bit integer is followed by &amp;lt;tt&amp;gt;8 * num&amp;lt;/tt&amp;gt; bytes of edit history information.&lt;br /&gt;
&lt;br /&gt;
Each history block consists of a 16-Bit FAT date, a 16-Bit FAT time and a 32-Bit DOS timer, which contains the time how long the file was open in the editor, in 1/18.2th seconds.&lt;br /&gt;
Information on how to decode the FAT date and time stamps can be found on the [https://msdn.microsoft.com/en-us/library/windows/desktop/ms724247%28v=vs.85%29.aspx MSDN].&lt;br /&gt;
&lt;br /&gt;
Note: Many programs don’t write an edit history, but they set the edit history flag in the header and write the two zero bytes for the history length. Many of them also ignore the edit history flag when loading files and always read the two &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt; num bytes (ignoring the special flag), so if you want to write out an IT file that does not have an edit history and do not mind about the two extra bytes, the safest (most compatible) way is to set the edit history flag and write two zero bytes for &amp;lt;tt&amp;gt;num&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Also note that none of this is really relevant if you are sure that you never write out the MIDI macro configuration or ModPlug extensions, since these are the only two things that could normally follow the edit history. So if you have no MIDI macros and no ModPlug extensions, it is always safe to not set the special flag and not write the two extra bytes.&lt;br /&gt;
&lt;br /&gt;
== Edit Timer ==&lt;br /&gt;
&lt;br /&gt;
Before the addition of the full Edit History, a simple Edit Timer was stored in the &amp;lt;tt&amp;gt;reserved&amp;lt;/tt&amp;gt; field of the file header. Starting from Impulse Tracker 2.07, this field contains the total edit time as a 32-Bit DOS timer (same resolution as in the Edit History). Starting from Impulse Tracker 2.08, the timer is encrypted. To decrypt:&lt;br /&gt;
&lt;br /&gt;
 editTime = editTime XOR &#039;ITRK&#039;&lt;br /&gt;
 editTime = editTime RoR 7&lt;br /&gt;
 editTime = -editTime&lt;br /&gt;
 editTime = editTime RoL 4&lt;br /&gt;
 editTime = editTime XOR &#039;JTHL&#039;&lt;br /&gt;
&lt;br /&gt;
== Proposed way to store compressed stereo samples ==&lt;br /&gt;
&lt;br /&gt;
Since Impulse Tracker itself does not support stereo samples, a common way of how to decode compressed stereo samples had to be found - After all, it is possible to just treat them as one continuous stream (not stopping the encoding / decoding process after the end of the left channel), or to treat them as two separate, consecutive streams. XMPlay was probably the only player that could handle compressed stereo samples even before there was a single implementation for saving compressed stereo samples. GreaseMonkey has decided to follow [https://www.un4seen.com/forum/?topic=12448.msg86479#msg86479 XMPlay&#039;s way] of decoding compressed stereo samples by treating them as two streams of the same length, so OpenMPT follows this example. If you intend to add IT sample compression support in your application, you should do the same to ensure compatibility across as many applications as possible.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Hacks ==&lt;br /&gt;
&lt;br /&gt;
For a list of all the file format hacks that ModPlug Tracker / OpenMPT added to the IT format over the years, see the [[Development: OpenMPT Format Extensions|OpenMPT Format Extensions]] article.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|Formats/IT]]&lt;br /&gt;
[[Category:IT Format|Format Specification]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4375</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4375"/>
		<updated>2023-02-28T18:14:13Z</updated>

		<summary type="html">&lt;p&gt;CS127: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). For older versions, check [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&amp;lt;!-- Impulse Tracker 8 lol --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions).&lt;br /&gt;
&lt;br /&gt;
The chunk contains settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
Other MPTM features (e.g. fractional tempos) use [[Development:_OpenMPT_Format_Extensions|regular OpenMPT extensions]].&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format, &#039;&#039;&#039;even floating-point numbers&#039;&#039;&#039;):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit (single-precision) IEEE-754 floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character (text encoding may vary, so a single character is not necessarily one byte).&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, &amp;quot;Windows codepage&amp;quot; refers to the user&#039;s selected ACP codepage in Windows (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to [[Wikipedia:Windows-1252|1252]], but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether this chunk&#039;s descriptions (explained later) use a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for each entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, the string uses use a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;. Otherwise, they have to be stored in the same order that OpenMPT reads them.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, the string uses a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt;, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Windows codepage.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection (or &amp;quot;pattern container&amp;quot; according to the source code) is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data, which will be merged onto the IT pattern data when the file is read.&amp;lt;br/&amp;gt;&lt;br /&gt;
Technically, it can be used for storing any pattern data, but OpenMPT uses it for storing only the Parameter Control notes of each pattern.&amp;lt;/br&amp;gt;&lt;br /&gt;
The data is stored in the same format as the [https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT#impulse-pattern-format IT pattern format], but without the first 8 bytes, and with a different format for mask bytes:&amp;lt;br/&amp;gt;&lt;br /&gt;
* Bit 0: Include note (OpenMPT only writes PC and PCs)&lt;br /&gt;
* Bit 1: Include plugin number &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(instrument number if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 2: Include high byte of controller ID &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(volume command type if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 3: Include low byte of controller ID &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(volume command parameter if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 4: Include high byte of parameter &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(effect command type if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 5: Include low byte of parameter &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(effect command parameter if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: Include extra data&amp;lt;/span&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: Windows codepage.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
first version completed: 2022-02-28&lt;br /&gt;
last edit:               2023-02-28&lt;br /&gt;
&lt;br /&gt;
1 year!&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4374</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4374"/>
		<updated>2023-02-23T10:52:23Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Extended Pattern */ fix hyperlink&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). For older versions, check [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&amp;lt;!-- Impulse Tracker 8 lol --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions).&lt;br /&gt;
&lt;br /&gt;
The chunk contains settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
Other MPTM features (e.g. fractional tempos) use [[Development:_OpenMPT_Format_Extensions|regular OpenMPT extensions]].&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character (text encoding may vary, so a single character is not necessarily one byte).&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, &amp;quot;Windows codepage&amp;quot; refers to the user&#039;s selected ACP codepage in Windows (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to [[Wikipedia:Windows-1252|1252]], but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether this chunk&#039;s descriptions (explained later) use a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for each entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, the string uses use a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, the string uses a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt;, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Windows codepage.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection (or &amp;quot;pattern container&amp;quot; according to the source code) is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data, which will be merged onto the IT pattern data when the file is read.&amp;lt;br/&amp;gt;&lt;br /&gt;
Technically, it can be used for storing any pattern data, but OpenMPT uses it for storing only the Parameter Control notes of each pattern.&amp;lt;/br&amp;gt;&lt;br /&gt;
The data is stored in the same format as the [https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT#impulse-pattern-format IT pattern format], but without the first 8 bytes, and with a different format for mask bytes:&amp;lt;br/&amp;gt;&lt;br /&gt;
* Bit 0: Include note (OpenMPT only writes PC and PCs)&lt;br /&gt;
* Bit 1: Include plugin number &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(instrument number if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 2: Include high byte of controller ID &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(volume command type if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 3: Include low byte of controller ID &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(volume command parameter if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 4: Include high byte of parameter &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(effect command type if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 5: Include low byte of parameter &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(effect command parameter if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: Include extra data&amp;lt;/span&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: Windows codepage.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
first version completed: 2022-02-28&lt;br /&gt;
last edit:               2023-02-23&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4373</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4373"/>
		<updated>2023-02-23T10:42:30Z</updated>

		<summary type="html">&lt;p&gt;CS127: small improvements&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). For older versions, check [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&amp;lt;!-- Impulse Tracker 8 lol --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions).&lt;br /&gt;
&lt;br /&gt;
The chunk contains settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
Other MPTM features (e.g. fractional tempos) use [[Development:_OpenMPT_Format_Extensions|regular OpenMPT extensions]].&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character (text encoding may vary, so a single character is not necessarily one byte).&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, &amp;quot;Windows codepage&amp;quot; refers to the user&#039;s selected ACP codepage in Windows (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to [[Wikipedia:Windows-1252|1252]], but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether this chunk&#039;s descriptions (explained later) use a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for each entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, the string uses use a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, the string uses a fixed 16-bit encoding (e.g. [[Wikipedia:Universal_Coded_Character_Set|UCS-2]]) instead of a fixed 8-bit encoding (e.g. [[Wikipedia:ISO/IEC_8859-1|ISO-8859-1]] / [[Wikipedia:Windows-1252|Windows-1252]]).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt;, 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt;, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Windows codepage.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection (or &amp;quot;pattern container&amp;quot; according to the source code) is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; 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).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data, which will be merged onto the IT pattern data when the file is read.&amp;lt;br/&amp;gt;&lt;br /&gt;
Technically, it can be used for storing any pattern data, but OpenMPT uses it for storing only the Parameter Control notes of each pattern.&amp;lt;/br&amp;gt;&lt;br /&gt;
The data is stored in the same format as the [[https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT#impulse-pattern-format|IT pattern format]], but without the first 8 bytes, and with a different format for mask bytes:&amp;lt;br/&amp;gt;&lt;br /&gt;
* Bit 0: Include note (OpenMPT only writes PC and PCs)&lt;br /&gt;
* Bit 1: Include plugin number &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(instrument number if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 2: Include high byte of controller ID &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(volume command type if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 3: Include low byte of controller ID &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(volume command parameter if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 4: Include high byte of parameter &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(effect command type if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* Bit 5: Include low byte of parameter &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;(effect command parameter if not a PC/PCs note)&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: Include extra data&amp;lt;/span&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: Windows codepage.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
first version completed: 2022-02-28&lt;br /&gt;
last edit:               2023-02-23&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4333</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4333"/>
		<updated>2022-10-15T13:11:54Z</updated>

		<summary type="html">&lt;p&gt;CS127: fixed some issues&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character (text encoding may vary, so a single character is not necessarily one byte).&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for each entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
completed: 2022-02-28&lt;br /&gt;
last edit: 2022-10-15&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Manual:_Hidden_Settings&amp;diff=4321</id>
		<title>Manual: Hidden Settings</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Manual:_Hidden_Settings&amp;diff=4321"/>
		<updated>2022-08-12T17:04:48Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* [Broken Plugin Workarounds] */ fixed a typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Settings Advanced.png|thumb|300px|Advanced tab of the settings dialog]]&lt;br /&gt;
&lt;br /&gt;
Some settings for advanced users cannot be changed directly in OpenMPT, however they can be changed by modifying OpenMPT’s configuration file, mptrack.ini, or from the [[Manual:_Setup/Advanced|Advanced Settings]]. When using the latter method, it might be necessary to restart OpenMPT for some options to take effect.&lt;br /&gt;
&lt;br /&gt;
== [Broken Plugin Workarounds] ==&lt;br /&gt;
* &#039;&#039;&#039;VSTMaskAllCrashes&#039;&#039;&#039;: Determines whether crashes in VST plugins should be reported to the user (1) or passed on to the system, i.e. OpenMPT crashes (0). Note that if a plugin crashed, its internal state or even OpenMPT’s state may be inconsistent, so in this situation it is best to close and reopen the tracker anyway.&lt;br /&gt;
* &#039;&#039;&#039;VSTNeverUnloadAnyPlugin&#039;&#039;&#039;: If set to 1, VST plugins are not fully unloaded when closing them. This may help with some buggy plugins (e.g. made with older versions of SynthEdit 1.4). Do not enable this setting unless you have issues when unloading plugins that cannot be solved by using the plugin bridge.&lt;br /&gt;
&lt;br /&gt;
== [Components] ==&lt;br /&gt;
* &#039;&#039;&#039;BlockASIO&#039;&#039;&#039;, &#039;&#039;&#039;BlockPortAudio&#039;&#039;&#039;, &#039;&#039;&#039;BlockRtAudio&#039;&#039;&#039;, &#039;&#039;&#039;BlockWaveOut&#039;&#039;&#039;: If set to 1, the respective sound device types do not get initialized or queried by OpenMPT. You should not need to disable any of these unless told to do so by the OpenMPT developers in order to diagnose problems.&lt;br /&gt;
* &#039;&#039;&#039;BlockMediaFoundation&#039;&#039;&#039;: If set to 1, OpenMPT will not load any samples using MediaFoundation codecs.&lt;br /&gt;
* &#039;&#039;&#039;BlockWineWrapper&#039;&#039;&#039;: If set to 1, OpenMPT will not load the Wine native audio wrapper.&lt;br /&gt;
* &#039;&#039;&#039;KeepLoaded&#039;&#039;&#039;: If set to 0, optional OpenMPT components (e.g. MP3 codecs) are unloaded after usage. This frees up memory used by these components but slows down subsequent uses.&lt;br /&gt;
* &#039;&#039;&#039;LoadOnStartUp&#039;&#039;&#039;: If set to 1, some optional components are loaded right on statup instead of when they are first used.&lt;br /&gt;
&lt;br /&gt;
== [Debug] ==&lt;br /&gt;
Options in this section should generally only be changed if you are advised by an OpenMPT developer to do so.&lt;br /&gt;
* &#039;&#039;&#039;DelegateToWindowsHandler&#039;&#039;&#039;: If set to 1, OpenMPT will invoke the Windows default crash handler after its own crash handler has finished generating the crash report which had been the behaviour in OpenMPT before 1.27.&lt;br /&gt;
* &#039;&#039;&#039;StopSoundDeviceBeforeDump&#039;&#039;&#039;: By default, the sound device is closed after writing out a crash dump. Setting this option to 1 inverts the behaviour.&lt;br /&gt;
* &#039;&#039;&#039;StopSoundDeviceOnCrash&#039;&#039;&#039;: If set to 0, OpenMPT will not close or otherwise touch the state of the sound device when writing out a crash dump. Only change this setting when asked by the OpenMPT developers to do so in order to diagnose sound device related crashes.&lt;br /&gt;
* &#039;&#039;&#039;TraceAlwaysDump&#039;&#039;&#039;: If set to 1 and &#039;&#039;&#039;TraceEnable&#039;&#039;&#039; is also set to 1, OpenMPT will always write out the trace log on program exit even if no crash happened. Do not enable this setting unless you are advised by the developers to do so.&lt;br /&gt;
* &#039;&#039;&#039;TraceEnable&#039;&#039;&#039;: If set to 1, a trace logging system is enabled which can be used by the OpenMPT developers to debug certain problems. Do not enable this setting unless you are advised by the developers to do so.&lt;br /&gt;
* &#039;&#039;&#039;TraceSize&#039;&#039;&#039;: Configures the tracer buffer size. By default, it contains 1,000,000 entries.&lt;br /&gt;
&lt;br /&gt;
== [Display] ==&lt;br /&gt;
* &#039;&#039;&#039;FSUpdateInterval&#039;&#039;&#039;: OpenMPT watches the &#039;&#039;&#039;f&#039;&#039;&#039;ile &#039;&#039;&#039;s&#039;&#039;&#039;ystem in order to update the [[Manual:_Tree_View#Instrument_Library|instrument library]] tree view when files get added or removed to the directory while OpenMPT is running. This setting limits the rate of the GUI updates in these cases to the given value in milliseconds. The default is 500ms.&lt;br /&gt;
* &#039;&#039;&#039;GUIUpdateInterval&#039;&#039;&#039;: Defines the update interval of the GUI in milliseconds (default: depends on the period value found in the sound card settings).&lt;br /&gt;
* &#039;&#039;&#039;HighResUI&#039;&#039;&#039;: If enabled, OpenMPT reports itself to Windows as a DPI-aware application. This setting might have to be disabled if you are using a high-DPI screen in combination with VST plugins that do not have a DPI-aware user interface.&lt;br /&gt;
* &#039;&#039;&#039;ShowSplashScreen&#039;&#039;&#039;: If set to 0, no splash screen is shown when starting the program (same effect as [[Manual: Command-line Parameters|command line option]] /NoLogo).&lt;br /&gt;
* &#039;&#039;&#039;VuMeterUpdateInterval&#039;&#039;&#039;: Defines the update interval of the VU meters in milliseconds (default: 15ms).&lt;br /&gt;
* &#039;&#039;&#039;VuMeterDecaySpeedDecibelPerSecond &#039;&#039;&#039;: Sets the VU meter&#039;s decay speed The default value is 88 dB/s.&lt;br /&gt;
&lt;br /&gt;
== [Export] ==&lt;br /&gt;
* &#039;&#039;&#039;DefaultToSoundcardSamplerate&#039;&#039;&#039;: By default, the [[Manual: Saving and exporting#Exporting tracks|export dialog]] presets the export frequency to the tracker’s currently selected sample rate. One reason for this behaviour is that some plugins do not like it when the sample rate is changed between normal playback and export. If you do not like this behaviour, you can set this value to 0. In this case, OpenMPT remembers the previously selected sample rate instead.&lt;br /&gt;
* &#039;&#039;&#039;FLACCompressionLevel&#039;&#039;&#039;: When [[Manual: Saving and exporting#Exporting tracks|exporting]] to FLAC format, this value sets the FLAC compression level. Higher values mean better compression ratio and require more CPU time. For details, please refer to the FLAC documentation.&lt;br /&gt;
* &#039;&#039;&#039;MP3ID3v2MinPadding&#039;&#039;&#039;: This value is the minimum amount of padding bytes to add to ID3v2 tags. &lt;br /&gt;
* &#039;&#039;&#039;MP3ID3v2PaddingAlignHint&#039;&#039;&#039;: This aligns the MP3 data after the ID3v2 tag in addition to the minimum padding to a multiple of the configured value. Set to 0 to disable additional aligning.&lt;br /&gt;
* &#039;&#039;&#039;MP3ID3v2WriteReplayGainTXXX&#039;&#039;&#039;: Write ReplayGain information (if calculated, see &#039;&#039;&#039;MP3LameCalculateReplayGain&#039;&#039;&#039; and &#039;&#039;&#039;MP3LameCalculatePeakSample&#039;&#039;&#039;) to the ID3v2 tag. This setting defaults to 1.&lt;br /&gt;
* &#039;&#039;&#039;MP3LameCalculateReplayGain&#039;&#039;&#039; and &#039;&#039;&#039;MP3LameCalculatePeakSample&#039;&#039;&#039;: When [[Manual: Saving and exporting#Exporting tracks|exporting]] to MP3 format, calculate the ReplayGain track gain adjustment and the peak sample value (as require by ReplaGain) respectively. The calculated values get written to the VBR/Lame info header automatically in VBR mode. Additionally, the values can be written to the ID3v2 tags when enabled (see &#039;&#039;&#039;MP3ID3v2WriteReplayGainTXXX&#039;&#039;&#039;). Both settings default to 1.&lt;br /&gt;
* &#039;&#039;&#039;MP3LameID3v2UseLame&#039;&#039;&#039;: If set to 1, when [[Manual: Saving and exporting#Exporting tracks|exporting]] to MP3 format, uses the libmp3lame ID3v2.3 implementation instead of the OpenMPT ID3v2.4 implementation. ID3v2.3 is more widely supported by older player software.&lt;br /&gt;
* &#039;&#039;&#039;MP3LameQuality&#039;&#039;&#039;: When [[Manual: Saving and exporting#Exporting tracks|exporting]] to MP3 format using libmp3lame, this value selects the internal algorithm quality used by LAME. Lower values mean better quality and require more CPU time. This is the same as the -q command line parameter for LAME. More details can be found e.g. on [http://wiki.hydrogenaud.io/index.php?title=LAME_-q_switch Hydrogenaudio].&lt;br /&gt;
* &#039;&#039;&#039;OpusComplexity&#039;&#039;&#039;: When [[Manual: Saving and exporting#Exporting tracks|exporting]] to Opus format, this value selects the internal complexity used by libopus. Higher values mean better encoding efficiency and require more CPU time. Value -1 uses the libopus default value. For details, please refer to the [https://opus-codec.org/docs/ libopus documentation].&lt;br /&gt;
&lt;br /&gt;
== [MIDI Input Ports] ==&lt;br /&gt;
In this section, you can set “friendly names” for all MIDI input ports. If you have lots of MIDI ports with undescriptive names (such as “MIDI Device Port 1”, “MIDI Device Port 2”, …), it can be useful to replace those names with more suitable names, e.g. to describe which device is connected to a specific port. To replace a name, add a pair like &amp;lt;code&amp;gt;MIDI Device Port 1=Synthesizer 1&amp;lt;/code&amp;gt; to this section.&lt;br /&gt;
&lt;br /&gt;
Friendly names are also recognized by the MIDI Input / Output plugin: If the selected ports have friendly names assigned when the module is saved, the next time is opened it will try to find the correct device by its friendly name. So if a MIDI device is connected to a different MIDI port, you can rename the ports and OpenMPT will automatically choose the correct port.&lt;br /&gt;
&lt;br /&gt;
== [MIDI Output Ports] ==&lt;br /&gt;
Same as [[#.5BMIDI Input Ports.5D|[MIDI Input Ports]]], but for MIDI output ports.&lt;br /&gt;
&lt;br /&gt;
== [Misc] ==&lt;br /&gt;
* &#039;&#039;&#039;AllowMultipleCommandsPerKey&#039;&#039;&#039;: By default, a key combination can be used by only one command. Setting this to 1 allows you to bind more than one command to a key combination. Beware that this might lead to problems with existing keyboard mappings with overlapping commands!&lt;br /&gt;
* &#039;&#039;&#039;CacheCompleteFileBeforeLoading&#039;&#039;&#039;: If set to 1, OpenMPT caches entire (module, instrument, etc.) files in memory, which may improve file reading performance at the expense of more memory being used.&lt;br /&gt;
* &#039;&#039;&#039;DistinguishModifiers&#039;&#039;&#039;: Enable this option to distinguish between left and right &amp;lt;kbd&amp;gt;Ctrl&amp;lt;/kbd&amp;gt; / &amp;lt;kbd&amp;gt;Alt&amp;lt;/kbd&amp;gt; / &amp;lt;kbd&amp;gt;Shift&amp;lt;/kbd&amp;gt; modifiers, e.g. to create FastTracker 2-like pattern play shortcuts.&lt;br /&gt;
* &#039;&#039;&#039;FlushFileBuffersOnSave&#039;&#039;&#039;: Disabling this option avoids flushing of file buffers after saving modules, samples and other files on disk. This can speed up the write operation but increases the risk of data loss e.g. in case of a power failure.&lt;br /&gt;
* &#039;&#039;&#039;ITCompressionMono&#039;&#039;&#039;: Enables IT-compressed mono samples when saving IT/MPTM files, depending on the value. To enable saving for normal IT files, add 1 to the value, for IT files saved through Compatibility Export, add 2, and for MPTM files add 4. So to enable saving of compressed samples in compatible ITs and MPTMs only, you would use the value 6. Some caveats regarding the usage of compressed samples have been written down on the [https://forum.openmpt.org/index.php?topic=4961.0 forum].&lt;br /&gt;
* &#039;&#039;&#039;ITCompressionStereo&#039;&#039;&#039;: Enables IT-compressed stereo samples when saving IT/MPTM files, depending on the value (see above).&lt;br /&gt;
* &#039;&#039;&#039;MRUListLength&#039;&#039;&#039;: Sets the maximum length of the most recently used file list in the file menu. Allowed values are between 0 (no list) and 15 entries.&lt;br /&gt;
* &#039;&#039;&#039;ProcessPriorityClass&#039;&#039;&#039;: Set the Windows process priority class for OpenMPT. Possible values are: &amp;quot;idle&amp;quot;, &amp;quot;below&amp;quot;, &amp;quot;normal&amp;quot;, &amp;quot;above&amp;quot;, &amp;quot;high&amp;quot;, &amp;quot;realtime&amp;quot;. The default is &amp;quot;normal&amp;quot;. See further discussion on the [https://forum.openmpt.org/index.php?topic=5655.0 forum]. &#039;&#039;&#039;Warning&#039;&#039;&#039;: Changing this setting can cause system lockups requiring hard system reset.&lt;br /&gt;
* &#039;&#039;&#039;SaveChannelMuteStatus&#039;&#039;&#039;: If set to 0, OpenMPT will not save the channel mute status in IT, MPTM and S3M files.&lt;br /&gt;
* &#039;&#039;&#039;SmoothFT2Ramping&#039;&#039;&#039;: If set to 1, XM files made with Fasttracker 2 will automatically use [[Manual:_Compatible_Playback#XM_compatibility_settings|very smooth sample ramping]] settings (like Fasttracker 2 did).&lt;br /&gt;
* &#039;&#039;&#039;UseSingleInstance&#039;&#039;&#039;: Always forces OpenMPT to only use a single program instance, even when the &#039;&#039;&#039;/shared&#039;&#039;&#039; command line switch is not specified.&lt;br /&gt;
&lt;br /&gt;
== [Paths] ==&lt;br /&gt;
* &#039;&#039;&#039;Export_Directory&#039;&#039;&#039;: The default export directory for lossless and lossy audio export. OpenMPT always uses the last used directory for exporting, so changing this setting does not make a lot of sense.&lt;br /&gt;
* &#039;&#039;&#039;UseAppDataDirectory&#039;&#039;&#039;: This is a legacy setting imported from portable OpenMPT installations prior to version 1.29. If &amp;lt;code&amp;gt;mptrack.ini&amp;lt;/code&amp;gt; is found next to &amp;lt;code&amp;gt;OpenMPT.exe&amp;lt;/code&amp;gt; and this value is to 0, portable mode is assumed and all other configuration files are searched directly in the same directory as OpenMPT’s executable (by default they are placed in %APPDATA%\OpenMPT). When upgrading to a newer OpenMPT version, this setting is automatically converted to the new way of enabling portability. See also: [[Manual: System Setup#Portability|System Setup]].&lt;br /&gt;
&lt;br /&gt;
== [Pattern Editor] ==&lt;br /&gt;
* &#039;&#039;&#039;AccessibilityFormat&#039;&#039;&#039;: Defines the description of the pattern editor that can be obtained by screen readers. The string may contain the following variables: &amp;lt;code&amp;gt;%sequence%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%order%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%pattern%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%row%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%channel%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%channel_name%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%column_type%&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;%column_description%&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;AlwaysDrawWholePatternOnScrollSlow&#039;&#039;&#039;: If set to 1, OpenMPT will always repaint the whole pattern display instead of re-using parts of the window that have only moved and not changed. This will be measurably slower, however in some situation the display will look broken otherwise (like jittering play cursor, not updating regions of the pattern display properly when switching to and from the window, or generally sluggish/jerky display). The problem is related to certain graphics drivers (known examples are systems with multiple AMD GPUs in Windows 7, Windows XP in VirtualBox, and all Wine systems). By default, this setting is 0. On Wine, this setting has no effect and is treated as always 1, regardless of its actual value.&lt;br /&gt;
* &#039;&#039;&#039;DefaultSequenceMargins&#039;&#039;&#039;: Defines how many order items are shown at least before and after the currently selected order item (0 by default).&lt;br /&gt;
* &#039;&#039;&#039;EditStepAppliesToCommands&#039;&#039;&#039;: When set to 1, the edit step setting is also applied when entering a command into the volume or effect column.&lt;br /&gt;
* &#039;&#039;&#039;FontDot&#039;&#039;&#039;: Overriding this setting allows to specify a custom character to be used for empty cells with user-configured pattern fonts.&lt;br /&gt;
* &#039;&#039;&#039;NoEditPopup&#039;&#039;&#039;: Disables the reminder popup when trying to edit patterns while editing is disabled and treats all channel columns like the note column to simplify jamming (keyjazz).&lt;br /&gt;
* &#039;&#039;&#039;OrderListOldDropBehaviour&#039;&#039;&#039;: Restores pre-OpenMPT 1.29 drag &amp;amp; drop behaviour in the order list editor. That is, patterns are always dropped left of the drop position, even if the drop position is right of the source.&lt;br /&gt;
* &#039;&#039;&#039;RowDisplayOffset&#039;&#039;&#039;: Defines the displayed number of the first pattern row; by default, it is 0. This does not affect the Goto dialog or break commands in patterns.&lt;br /&gt;
&lt;br /&gt;
== [Sound Settings] ==&lt;br /&gt;
* &#039;&#039;&#039;AllowDeferredProcessing&#039;&#039;&#039;: If set to 0, deferred processing is never used for ASIO drivers.&lt;br /&gt;
* &#039;&#039;&#039;BoostedThreadPriority&#039;&#039;&#039;: Set the priority (for Windows XP) used for sound devices which have &amp;quot;Boost thread priority&amp;quot; set. Possible values are -15,-2,-1,0,1,2,15 (or the full range -15..15 if [Misc]ProcessPriorityClass is set to &amp;quot;realtime&amp;quot;). Default value is 2. See further discussion on the [https://forum.openmpt.org/index.php?topic=5655.0 forum]. &#039;&#039;&#039;Warning&#039;&#039;&#039;: Changing this setting can cause system lockups requiring hard system reset.&lt;br /&gt;
* &#039;&#039;&#039;BoostedThreadMMCSSClass&#039;&#039;&#039;: Set the Multimedia Class Scheduler Service (MMCSS) class used for sound devices which have &amp;quot;Boost thread priority&amp;quot; set. Possible values are &amp;quot;Pro Audio&amp;quot;, &amp;quot;Games&amp;quot;, &amp;quot;Audio&amp;quot; or anything else that may be configured on your systems MMCSS. Default value is &amp;quot;Pro Audio&amp;quot;. See further discussion on the [https://forum.openmpt.org/index.php?topic=5655.0 forum]. &#039;&#039;&#039;Warning&#039;&#039;&#039;: Changing this setting can cause system lockups requiring hard system reset.&lt;br /&gt;
* &#039;&#039;&#039;MaskDriverCrashes&#039;&#039;&#039;: If set to 1, OpenMPT will try ignore crashes in ASIO drivers.&lt;br /&gt;
* &#039;&#039;&#039;MixChannels&#039;&#039;&#039;: Default is 256. The maximum number of sound channels that OpenMPT will use to render. In other words, Polyphony is the allowable number of notes that OpenMPT will process at once. Any computer that has been built in the last ten years should be able to handle the maximum amount of channels for most modules, but while older, low-end computers you will want to decrease the number of channels. Note that reducing the maximum polyphony only reduces the CPU load if those extra channels were actually used — if you play a 10-channel MOD file, it does matter little, if at all, whether the maximum polyphony is set to 16 or 256.&lt;br /&gt;
* &#039;&#039;&#039;ResamplerWFIRCutoff&#039;&#039;&#039;: Configures the bandwidth of the audio signal that is retained by the 8-tap Sinc filter (without low-pass) in percent. The default of 97% offers a good compromise between “freshness” and quality of the resampled sound.&lt;br /&gt;
* &#039;&#039;&#039;SampleRates&#039;&#039;&#039;: A comma-separated list of sample rates that OpenMPT will show in the sound device settings (if supported by the device) and when exporting a WAVE or FLAC file.&lt;br /&gt;
* &#039;&#039;&#039;XMMSModplugResamplerWFIRType&#039;&#039;&#039;: Configures the windowing function of the 8-tap Sinc filter (without low-pass). The windowing functions, from 0 to 7, are: Hann, Hamming, Blackman Exact, Blackman 3-Tap 61, Blackman 3-Tap 67, Blackman-Harris, Blackman 4-Tap 74, Kaiser α=7.5&lt;br /&gt;
&lt;br /&gt;
== [Update] ==&lt;br /&gt;
* &#039;&#039;&#039;SuggestDifferentBuildVariants&#039;&#039;&#039;: By default, if the currently installed OpenMPT version is not optimal for the computer, it will suggest to install a different build variant. This check can be disabled by setting this variable to 0.&lt;br /&gt;
&lt;br /&gt;
== [VST Plugins] ==&lt;br /&gt;
* &#039;&#039;&#039;BridgeAllPlugins&#039;&#039;&#039;: All plugins are forced to be used through the integrated plugin bridge.&lt;br /&gt;
* &#039;&#039;&#039;EnableAutoSuspend&#039;&#039;&#039;: Enables auto-suspend for all plugins newly added to modules after this setting is turned on. If a plugin did not emit any sound during the last four seconds, it is suspended until new notes or sound data are fed into the plugin.&lt;br /&gt;
* &#039;&#039;&#039;EnableMidiMappingInEditor&#039;&#039;&#039;: If set to 0, holding &amp;lt;kbd&amp;gt;Shift&amp;lt;/kbd&amp;gt; while modifying a plugin parameter does not open the [[Manual: MIDI Mapping|MIDI Mapping dialog]].&lt;br /&gt;
* &#039;&#039;&#039;HostProductString&#039;&#039;&#039;: Here you can enter a custom host name that is sent to VST plugins. This can be useful if a plugin claims to only run in certain hosts and refuses to run in others.&lt;br /&gt;
* &#039;&#039;&#039;HostVendorString&#039;&#039;&#039;: Here you can enter the host vendor name for the same reasons as above.&lt;br /&gt;
* &#039;&#039;&#039;HostVendorVersion&#039;&#039;&#039;: Here you can enter the host version as a 32-Bit integer for the same reasons as above.&lt;br /&gt;
* &#039;&#039;&#039;ProjectPath&#039;&#039;&#039;: Some plugins can store extra data alongside the module file. This behaviour can be overridden so that plugins use a different path. This setting can be either a normal absolute path or use the variables &amp;lt;code&amp;gt;%1&amp;lt;/code&amp;gt; (module path) and &amp;lt;code&amp;gt;%2&amp;lt;/code&amp;gt; (module filename) to build a path relative to the module location. So if all external plugin data should be stored in the folder &amp;lt;code&amp;gt;module.mptm-data&amp;lt;/code&amp;gt; (assuming module.mptm is the module filename) next to the module, this value should be set to &amp;lt;code&amp;gt;%1%2-data&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt; Due to restrictions posed by the VST architecture, this path must not contain characters outside the current [https://en.wikipedia.org/wiki/Windows_code_page#ANSI Windows ANSI code page].&lt;br /&gt;
&lt;br /&gt;
[[Category:Manual|Hidden Settings]]&lt;br /&gt;
[[de:Handbuch: Versteckte Optionen]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4314</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4314"/>
		<updated>2022-08-01T21:57:09Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tuning structure */ fixed code block&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]  || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32   || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Plugin Type&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;VST plugins: &amp;lt;code&amp;gt;PtsV&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DMO plugins: &amp;lt;code&amp;gt;OMXD&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4      || char[4]   || Unique Plugin ID&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint8     || Routing Flags&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x01: Apply to master mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x02: Bypass effect&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x04: Wet Mix (dry added)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x08: Expand Mix [0%,100%] → [-200%,200%]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x10: Plugin will automatically suspend on silence&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9      || uint8     || Mix mode&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0: normal processing&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;1: MIX += DRY - WET * wetRatio&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;2: MIX += WET - DRY * dryRatio&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3: MIX -= WET - DRY * wetRatio&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;4: MIX -= middle - WET * wetRatio + middle - DRY&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;5: MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;br/&amp;gt;MIX_R += dryRatio * (WET_L - DRY_L) + wetRatio * (DRY_R - WET_R)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint8     || Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
|-&lt;br /&gt;
| 11     || uint8     || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint32    || Output Routing (0 = send to master 0x80 + x = send to plugin x)&lt;br /&gt;
|-&lt;br /&gt;
| 16     || uint8[16] || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 32     || char[32]  || User-chosen plugin name (Windows code page)&lt;br /&gt;
|-&lt;br /&gt;
| 64     || char[64]  || Library name (Original DLL name / DMO identifier).&amp;lt;br/&amp;gt;UTF-8 (max. 64 bytes) since OpenMPT 1.22.07.01, Windows code page in older versions.&lt;br /&gt;
|-&lt;br /&gt;
| 128    || uint32    || Size of plugin-specific data in bytes (parameters or opaque chunk)&lt;br /&gt;
|-&lt;br /&gt;
| 132    || uint8     || Plugin-specific data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk chunk, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || VSTi Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. The i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors should be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || VarInt    || Length of the filename&lt;br /&gt;
|-&lt;br /&gt;
| ?      || char[]    || Filename (UTF-8, not null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform should be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. should be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data should be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag should be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint16    || Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
|-&lt;br /&gt;
| 2      || uint32    || Number of items in the order list&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint32[]  || The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int32&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the Tuning Collection version is 2.&lt;br /&gt;
* uint32 if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint32&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is uint32. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| float32&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* uint32 if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as uint32 instead of uint16 and uint8 respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Default panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint16    || Default volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint16    || Global volume (0...64)&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint16    || (Reserved, must be 0)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint8     || Auto-vibrato type &amp;lt;!-- todo: list the types --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 13     || uint8     || Auto-vibrato sweep&lt;br /&gt;
|-&lt;br /&gt;
| 14     || uint8     || Auto-vibrato depth&lt;br /&gt;
|-&lt;br /&gt;
| 15     || uint8     || Auto-vibrato rate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 655350 Hz.&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4305</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4305"/>
		<updated>2022-07-07T20:58:17Z</updated>

		<summary type="html">&lt;p&gt;CS127: fixed more typos/mistakes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character (text encoding may vary, so a single character is not necessarily one byte).&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for each entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this entry, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
completed: 2022-02-28&lt;br /&gt;
last edit: 2022-07-08&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4286</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4286"/>
		<updated>2022-05-27T05:58:41Z</updated>

		<summary type="html">&lt;p&gt;CS127: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character (text encoding may vary, so a single character is not necessarily one byte).&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for each entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
completed: 2022-02-28&lt;br /&gt;
last edit: 2022-05-27&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4285</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4285"/>
		<updated>2022-05-27T05:53:49Z</updated>

		<summary type="html">&lt;p&gt;CS127: better tables&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]  || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint32   || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Plugin Type&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;VST plugins: &amp;lt;code&amp;gt;PtsV&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;DMO plugins: &amp;lt;code&amp;gt;OMXD&amp;lt;/code&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4      || char[4]   || Unique Plugin ID&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint8     || Routing Flags&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x01: Apply to master mix&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x02: Bypass effect&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x04: Wet Mix (dry added)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x08: Expand Mix [0%,100%] → [-200%,200%]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0x10: Plugin will automatically suspend on silence&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 9      || uint8     || Mix mode&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;0: normal processing&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;1: MIX += DRY - WET * wetRatio&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;2: MIX += WET - DRY * dryRatio&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;3: MIX -= WET - DRY * wetRatio&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;4: MIX -= middle - WET * wetRatio + middle - DRY&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;5: MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;br/&amp;gt;MIX_R += dryRatio * (WET_L - DRY_L) + wetRatio * (DRY_R - WET_R)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint8     || Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
|-&lt;br /&gt;
| 11     || uint8     || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint32    || Output Routing (0 = send to master 0x80 + x = send to plugin x)&lt;br /&gt;
|-&lt;br /&gt;
| 16     || uint8[16] || (Reserved)&lt;br /&gt;
|-&lt;br /&gt;
| 32     || char[32]  || User-chosen plugin name (Windows code page)&lt;br /&gt;
|-&lt;br /&gt;
| 64     || char[64]  || Library name (Original DLL name / DMO identifier).&amp;lt;br/&amp;gt;UTF-8 (max. 64 bytes) since OpenMPT 1.22.07.01, Windows code page in older versions.&lt;br /&gt;
|-&lt;br /&gt;
| 128    || uint32    || Size of plugin-specific data in bytes (parameters or opaque chunk)&lt;br /&gt;
|-&lt;br /&gt;
| 132    || uint8     || Plugin-specific data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk chunk, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || char[4]   || Magic bytes (FOURCC)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Size of this chunk, excluding the header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || VSTi Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. The i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors should be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || VarInt    || Length of the filename&lt;br /&gt;
|-&lt;br /&gt;
| ?      || char[]    || Filename (UTF-8, not null-terminated)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform should be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. should be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data should be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag should be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint16    || Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
|-&lt;br /&gt;
| 2      || uint32    || Number of items in the order list&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint32[]  || The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int32&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the Tuning Collection version is 2.&lt;br /&gt;
* uint32 if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint32&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| char[4]&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the SFS chunk version is 4.&lt;br /&gt;
* uint32 if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning SFS chunk end signature: CT&amp;lt;sfs&amp;gt;E (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is uint32. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| uint16 or uint32&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is uint32.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint16 if the tuning version is 3.&lt;br /&gt;
* uint32 if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| float32[]&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| float32&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| char[8]&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| int16&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| uint8 or uint32&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* uint8 if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* uint32 if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| char[]&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as uint32 instead of uint16 and uint8 respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Data Type !! Content&lt;br /&gt;
|-&lt;br /&gt;
| 0      || uint32    || Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
|-&lt;br /&gt;
| 4      || uint16    || Default panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 6      || uint16    || Default volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| 8      || uint16    || Global volume (0...64)&lt;br /&gt;
|-&lt;br /&gt;
| 10     || uint16    || (Reserved, must be 0)&lt;br /&gt;
|-&lt;br /&gt;
| 12     || uint8     || Auto-vibrato type &amp;lt;!-- todo: list the types --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 13     || uint8     || Auto-vibrato sweep&lt;br /&gt;
|-&lt;br /&gt;
| 14     || uint8     || Auto-vibrato depth&lt;br /&gt;
|-&lt;br /&gt;
| 15     || uint8     || Auto-vibrato rate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 655350 Hz.&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4270</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4270"/>
		<updated>2022-05-03T16:47:22Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Header Structure */ fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for each entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4264</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4264"/>
		<updated>2022-04-09T13:07:50Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Header Structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&amp;lt;br/&amp;gt;&lt;br /&gt;
Additionally, this causes OpenMPT to be unable to write chunks with more than 16383 entries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4263</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4263"/>
		<updated>2022-04-09T13:05:42Z</updated>

		<summary type="html">&lt;p&gt;CS127: typo fixes, more consistency, and some simplification&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit width (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the least significant bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the least significant two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, unless the chunk has a &amp;quot;flag byte&amp;quot; (explained later) and its bit 0 is set.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in two bytes, even if it only needs one.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT always writes this adaptive integer in eight bytes, even if it needs fewer bytes.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), 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.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4251</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4251"/>
		<updated>2022-03-09T08:57:14Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tuning Collection */ removed redundant info that was repeated in the next sentence&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4248</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4248"/>
		<updated>2022-03-02T04:33:13Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* 228 Chunk Structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and a map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4247</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4247"/>
		<updated>2022-02-28T12:58:13Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tuning Map structure */ added link to tuning map documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint32  Size of this chunk, excluding the header&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
 Offset Type     Content&lt;br /&gt;
 0      char[4]  Plugin type (&amp;quot;PtsV&amp;quot; for VST, &amp;quot;OMXD&amp;quot; for DMO plugins)&lt;br /&gt;
 4      char[4]  Plugin unique ID&lt;br /&gt;
 8      uint8    Routing Flags&lt;br /&gt;
 9      uint8    Mix Mode&lt;br /&gt;
 10     uint8    Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
 11     uint8    Reserved&lt;br /&gt;
 12     uint32   Output Routing (0 = send to master 0x80 + x = send to plugin x)&lt;br /&gt;
 16     char[16] Reserved&lt;br /&gt;
 32     char[32] User-chosen plugin name (Windows code page)&lt;br /&gt;
 64     char[64] Library name (Original DLL name / DMO identifier - UTF-8 starting from OpenMPT 1.22.07.01, Windows code page in older versions)&lt;br /&gt;
 128    uint32   Length of plugin-specific data (parameters or opaque chunk)&lt;br /&gt;
 132    char[]   Plugin-specific data&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routing Flags:&#039;&#039;&#039;&lt;br /&gt;
* 0x01: Apply to master mix&lt;br /&gt;
* 0x02: Bypass effect&lt;br /&gt;
* 0x04: Wet Mix (dry added)&lt;br /&gt;
* 0x08: Expand Mix [0%,100%] → [-200%,200%]&lt;br /&gt;
* 0x10: Plugin will automatically suspend on silence&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mix Modes:&#039;&#039;&#039;&lt;br /&gt;
* 0: normal processing&lt;br /&gt;
* 1: MIX += DRY - WET * wetRatio&lt;br /&gt;
* 2: MIX += WET - DRY * dryRatio&lt;br /&gt;
* 3: MIX -= WET - DRY * wetRatio&lt;br /&gt;
* 4: MIX -= middle - WET * wetRatio + middle - DRY&lt;br /&gt;
* 5: MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;br/&amp;gt;MIX_R += dryRatio * (WET_L - DRY_L) + wetRatio * (DRY_R - WET_R)&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk chunk, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint16  Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint16  Size of this chunk, excluding the header&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || VSTi Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. The i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors should be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
 Offset Type   Content&lt;br /&gt;
 0      VarInt Length of the filename&lt;br /&gt;
 ?      char[] Filename as UTF-8 string (not null-terminated)&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform should be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. should be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data should be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag should be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
 Offset Type     Content&lt;br /&gt;
 0      uint16   Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
 2      uint32   Number of items in the order list&lt;br /&gt;
 6      uint32[] The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[4]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the Tuning Collection version is 2.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[4]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the tuning version is 3.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the tuning version is 3.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format (documented [[Development:_228_Extensions#Tuning_Map|here]]), but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
 Offset Type   Content&lt;br /&gt;
 0      uint32 Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
 4      uint16 Default panning (0...256)&lt;br /&gt;
 6      uint16 Default volume (0...256)&lt;br /&gt;
 8      uint16 Global volume (0...64)&lt;br /&gt;
 10     uint16 Reserved (must be 0)&lt;br /&gt;
 12     uint8  Auto-vibrato type&lt;br /&gt;
 13     uint8  Auto-vibrato sweep&lt;br /&gt;
 14     uint8  Auto-vibrato depth&lt;br /&gt;
 15     uint8  Auto-vibrato rate&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 655350 Hz.&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4246</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4246"/>
		<updated>2022-02-28T12:52:54Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Header Structure */ typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specify what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4245</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4245"/>
		<updated>2022-02-28T12:50:03Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Adaptive Integers */ LE&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4244</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4244"/>
		<updated>2022-02-26T12:52:13Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tuning Map */ ...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It is a structure that stores what tuning each instrument should use. Its entry ID, stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4243</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4243"/>
		<updated>2022-02-26T12:50:24Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tuning */ hopefully no more typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4242</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4242"/>
		<updated>2022-02-26T12:40:16Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Sequences */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4241</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4241"/>
		<updated>2022-02-26T12:38:09Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Extended Pattern Collection */ another one&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6E 75 6D&amp;lt;/code&amp;gt; in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4240</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4240"/>
		<updated>2022-02-26T12:36:55Z</updated>

		<summary type="html">&lt;p&gt;CS127: thats a lot of small mistakes and typos!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4239</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4239"/>
		<updated>2022-02-26T12:34:58Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tuning Map */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally, there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4238</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4238"/>
		<updated>2022-02-26T12:30:43Z</updated>

		<summary type="html">&lt;p&gt;CS127: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4237</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4237"/>
		<updated>2022-02-26T12:29:32Z</updated>

		<summary type="html">&lt;p&gt;CS127: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading the name if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4236</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4236"/>
		<updated>2022-02-26T12:26:57Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tuning */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the group ratio is greater than 0 and if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4235</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4235"/>
		<updated>2022-02-26T12:25:08Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Tuning */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&lt;br /&gt;
* For General tunings, the ratio table stores the ratios for all notes.&lt;br /&gt;
* For Group-geometric tunings, the ratio table stores the ratios for only the first (lowest pitch) group.&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4234</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4234"/>
		<updated>2022-02-26T12:17:59Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Header Structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 1, 2, or 4 respectively.&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4233</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4233"/>
		<updated>2022-02-26T12:13:33Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* Custom Tunings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;:&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;ge; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4232</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4232"/>
		<updated>2022-02-26T12:10:26Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* 228 Chunks in MPTM Files */ unsigned integer (probably not that important but whatever)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;:&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain an unsigned 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;get; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4231</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4231"/>
		<updated>2022-02-26T11:02:06Z</updated>

		<summary type="html">&lt;p&gt;CS127: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;:&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain a 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;get; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4230</id>
		<title>Development: 228 Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_228_Extensions&amp;diff=4230"/>
		<updated>2022-02-26T10:59:07Z</updated>

		<summary type="html">&lt;p&gt;CS127: added the page to development category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Since the OpenMPT MPTM format is based on the Impulse Tracker IT format, OpenMPT stores additional data (besides the ModPlug/OpenMPT song extensions) in MPTM files to store the settings for MPTM features like custom tunings. This additional data is stored in a chunk at the end of MPTM files (after the OpenMPT song extensions), starting with 3 bytes that read &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; when interpreted as text.&lt;br /&gt;
&lt;br /&gt;
228 extensions contain settings for these features:&lt;br /&gt;
* Custom tunings.&lt;br /&gt;
* Pattern time signature overrides, and Parameter Control notes in patterns.&lt;br /&gt;
* All sequences and their order lists.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
These are the datatypes used in this document (&#039;&#039;&#039;all numbers&#039;&#039;&#039; are stored in little-endian format):&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;: an unsigned integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;int8&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;: a signed integer with the given bit width.&lt;br /&gt;
* &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;: a 32-bit floating-point number.&lt;br /&gt;
* &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt;: a text character.&lt;br /&gt;
* Brackets (&amp;lt;code&amp;gt;[]&amp;lt;/code&amp;gt;) after a datatype specify an array of that datatype.&lt;br /&gt;
** If there is a number between the brackets, it is the number of items in the array.&lt;br /&gt;
&lt;br /&gt;
There are also custom datatypes that are explained below:&lt;br /&gt;
&lt;br /&gt;
=== Adaptive Integers ===&lt;br /&gt;
&lt;br /&gt;
Adaptive integers are unsigned 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 &amp;lt;code&amp;gt;auint&amp;lt;/code&amp;gt; followed by its bit depth (e.g., &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;).&lt;br /&gt;
* In a 16-bit adaptive integer, the first bit of the first byte (&amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;) specifies whether the integer is stored in 1 or 2 bytes respectively. The remaining 7 or 15 bits store the integer.&lt;br /&gt;
* In a 32-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
* In a 64-bit adaptive integer, the first two bits of the first byte (&amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;) 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.&lt;br /&gt;
&lt;br /&gt;
=== Strings ===&lt;br /&gt;
&lt;br /&gt;
Most text strings are stored as follows: the string&#039;s length (in &#039;&#039;&#039;characters&#039;&#039;&#039;) stored as a 64-bit adaptive integer, followed by the string itself. OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;. If a string is stored in a different format, it will be specified.&lt;br /&gt;
&lt;br /&gt;
=== Additional Notes ===&lt;br /&gt;
&lt;br /&gt;
* In this document, the word &amp;quot;ANSI&amp;quot; refers to the user&#039;s selected ACP codepage (&amp;lt;code&amp;gt;HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP&amp;lt;/code&amp;gt;), which is &#039;&#039;&#039;usually&#039;&#039;&#039; set to 1252, but may be different depending on the system locale.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunk Structure ==&lt;br /&gt;
&lt;br /&gt;
Each 228 chunk contains a header, a set of entries, and map.&lt;br /&gt;
&lt;br /&gt;
The header contains information about the chunk, such as its number of entries, or the starting position of its map.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
The map contains information about the entries of the chunk, such as the ID, position, and size of each entry.&lt;br /&gt;
&lt;br /&gt;
In the list and table below, features that are never written to files by the current version of OpenMPT are shown in &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;green text&amp;lt;/span&amp;gt; (see [[#Default_Chunk_Settings|Default Chunk Settings]] for more information).&lt;br /&gt;
&lt;br /&gt;
This is the general structure of a 228 chunk:&lt;br /&gt;
&lt;br /&gt;
* Header&lt;br /&gt;
** Signature bytes (&amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;)&lt;br /&gt;
** Chunk ID&lt;br /&gt;
** &amp;quot;Header byte&amp;quot;&lt;br /&gt;
** Additional header data, including the &amp;quot;flag byte&amp;quot;&lt;br /&gt;
** Numeric form of version number&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of version number&amp;lt;/span&amp;gt;&lt;br /&gt;
** Custom ID length for entries&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp&amp;lt;/span&amp;gt;&lt;br /&gt;
** Number of entries in the chunk&lt;br /&gt;
** Starting position of the map in this chunk&lt;br /&gt;
* Entries&lt;br /&gt;
** (Entry 1)&lt;br /&gt;
** (Entry 2)&lt;br /&gt;
** (Entry 3)&lt;br /&gt;
** (etc.)&lt;br /&gt;
* Map&lt;br /&gt;
** ID of Entry 1&lt;br /&gt;
** Start position of Entry 1&lt;br /&gt;
** Size of Entry 1&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 1&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 2&lt;br /&gt;
** Start position of Entry 2&lt;br /&gt;
** Size of Entry 2&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 2&amp;lt;/span&amp;gt;&lt;br /&gt;
** ID of Entry 3&lt;br /&gt;
** Start position of Entry 3&lt;br /&gt;
** Size of Entry 3&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of Entry 3&amp;lt;/span&amp;gt;&lt;br /&gt;
** (etc.)&lt;br /&gt;
&lt;br /&gt;
=== Header Structure ===&lt;br /&gt;
&lt;br /&gt;
This is the structure of the header of a chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[3]&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3-byte signature: &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;. Identifies the start of a 228 chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the chunk&#039;s ID (in bytes).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The chunk&#039;s ID. Usually readable as a string, but can be any set of bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;quot;Header byte&amp;quot;. The bits of this byte specifies what is and isn&#039;t stored in the chunk.&lt;br /&gt;
* Bits 0 and 1 specify the length of the IDs of this chunk&#039;s entries, &#039;&#039;&#039;only if&#039;&#039;&#039; bit 0 of this chunk&#039;s &amp;quot;flag byte&amp;quot; (explained later) is &#039;&#039;&#039;not set&#039;&#039;&#039;, or if the chunk does not have a &amp;quot;flag byte&amp;quot; at all.&lt;br /&gt;
** &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;: all entries in this chunk have IDs with length 0 (i.e., they do not have IDs).&lt;br /&gt;
** &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;:&lt;br /&gt;
* Bit 2: whether this chunk&#039;s map stores the starting position of each entry.&lt;br /&gt;
* Bit 3: whether this chunk&#039;s map stores the size of each entry.&lt;br /&gt;
* Bit 4: whether this chunk&#039;s header stores a numeric form of its version number.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 5: whether this chunk&#039;s header stores a string (text) form of its version number.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 6: whether each text character used in descriptions (explained later) uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 7: whether this chunk&#039;s map contains descriptions for this entry.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of additional header data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Additional header data.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the additional header data is at least 2 bytes long, &#039;&#039;&#039;and&#039;&#039;&#039; the first byte is &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;, the second byte is read as the &amp;quot;flag byte&amp;quot;.&amp;lt;br/&amp;gt;&lt;br /&gt;
The bits of the flag byte contain additional information about the chunk:&lt;br /&gt;
* Bit 0: whether the chunk uses custom ID lengths for its entries.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 1: whether all entries in this chunk have a fixed size.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 2: whether the chunk contains a description about itself.&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Bit 3: whether the chunk contains a timestamp.&amp;lt;/span&amp;gt;&lt;br /&gt;
The flag byte does not need to exist if none of its bits are supposed to be set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Numeric form of the version number. Usually contains the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions, but there are exceptions.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 4 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of the string form of the version number, in bytes.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This byte only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;String form of the version number. It was never used in any version of OpenMPT.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 5 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom ID length for entries.&lt;br /&gt;
* If bit 0 is set, the length of the IDs of this chunk&#039;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.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;If bit 0 is not set, the length of the IDs of this chunk&#039;s entries are stored in the remaining 7 bits of this byte.&amp;lt;/span&amp;gt;&lt;br /&gt;
This byte only exists if the chunk has a flag byte and its bit 0 is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Fixed entry size. Determines the size of all entries in this chunk.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 1 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this chunk&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Chunk description. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one byte (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if the chunk has a flag byte and its bit 2 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint40&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Timestamp, stored as a little-endian unsigned integer in 5 bytes (40 bits).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;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.&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This integer only exists if the chunk has a flag byte and its bit 3 is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of entries in this chunk.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this chunk&#039;s map, relative to the start of this chunk (where the &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt; bytes start).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer does not exist if this chunk does not have a map (see [[#Map_Structure|the section on maps]] for an explanation on whether a map exists or not).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Entry Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Entries of a chunk can be chunks themselves, allowing a chunk to be &amp;quot;nested&amp;quot; in another chunk by being one of the outer chunk&#039;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.&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;&#039;not necessarily related&#039;&#039;&#039; to its chunk ID (which is stored in the inner chunk&#039;s header). &#039;&#039;&#039;It can be the same ID or a different one&#039;&#039;&#039;.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: Entries do &#039;&#039;&#039;not&#039;&#039;&#039; need to be stored in a specific order, &#039;&#039;&#039;as long as the chunk that contains them specifies entry IDs in its map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Map Structure ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
This is the structure of a section of a map corresponding to a &#039;&#039;&#039;single entry&#039;&#039;&#039;:&lt;br /&gt;
{| class=&amp;quot;wikitable&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the entry&#039;s ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The entry&#039;s ID. Usually readable as a string, but can be any set of a bytes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Start position of this entry in the chunk, relative to the start of the chunk itself.&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 2 of the header byte is set.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of this entry in the chunk (in bytes).&amp;lt;br/&amp;gt;&lt;br /&gt;
This adaptive integer only exists if bit 3 of the header byte is set, and bit 1 of the flag byte is &#039;&#039;&#039;not&#039;&#039;&#039; set (or if there is no flag byte).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Length of this entry&#039;s description (in characters).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This adaptive integer only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;Description of the entry. If bit 6 of the header byte is set, each character uses two bytes (Unicode BMP) instead of one (ISO-8859-1 / Windows-1252).&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#00aa00;&amp;quot;&amp;gt;This string only exists if bit 7 of the header byte is set.&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Note: The sections of a chunk&#039;s map which each correspond to an entry, do &#039;&#039;&#039;not&#039;&#039;&#039; need to be in the same order as the way the entries themselves are stored in the chunk, &#039;&#039;&#039;as long as the chunk specifies starting positions and sizes of entries in the map&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== 228 Chunks in MPTM Files ==&lt;br /&gt;
&lt;br /&gt;
Reading the previous sections of this document is absolutely necessary to understand the rest of this document!&lt;br /&gt;
&lt;br /&gt;
The last four bytes of a valid MPTM file should contain a 32-bit integer that points to the starting position of the 228 chunks in the file. The 228 chunks are stored after the OpenMPT song extensions, and before the last four bytes of the file.&lt;br /&gt;
&lt;br /&gt;
There is supposed to be at least one chunk with an ID of &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 6D&amp;lt;/code&amp;gt; in hex bytes), which contains all the settings for MPTM features (like custom tunings) in its entries.&lt;br /&gt;
&lt;br /&gt;
=== Default Chunk Settings ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ALL chunks&#039;&#039;&#039; (and their &amp;quot;sub-chunks&amp;quot;, a.k.a. the entries that are chunks themselves) that are &#039;&#039;&#039;written by the current version of OpenMPT&#039;&#039;&#039; have a header byte of &amp;lt;code&amp;gt;00011111&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x1F&amp;lt;/code&amp;gt;), an additional header data size of 2 (byte &amp;lt;code&amp;gt;00001000&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x08&amp;lt;/code&amp;gt;)), a flag byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;) and a &amp;quot;custom entry ID length&amp;quot; byte of &amp;lt;code&amp;gt;00000001&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This means that all chunks written by the current version of OpenMPT:&lt;br /&gt;
* Have a map.&lt;br /&gt;
* Have variable ID lengths for their entries, so they have to be stored in the map.&lt;br /&gt;
* Store the starting position of their entries in their maps.&lt;br /&gt;
* Store the size of their entries in their maps.&lt;br /&gt;
* Store the numeric form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a string form of their version number in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store a timestamp in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about themselves in their headers.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; store descriptions about their entries in their maps.&lt;br /&gt;
* Do &#039;&#039;&#039;not&#039;&#039;&#039; have fixed sizes for their entries.&lt;br /&gt;
&lt;br /&gt;
However, OpenMPT &#039;&#039;&#039;does&#039;&#039;&#039; 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 &#039;&#039;&#039;not&#039;&#039;&#039; have the properties described above, &#039;&#039;&#039;as long as the structure of the chunks are written &amp;quot;correctly&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 ANSI encoding.&lt;br /&gt;
&lt;br /&gt;
=== Main Chunk ===&lt;br /&gt;
&lt;br /&gt;
As of OpenMPT 1.17.03.01 r323, the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401). Before r323, the chunk&#039;s version number was 1.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings ===&lt;br /&gt;
&lt;br /&gt;
This section documents how custom tunings are stored in MPTM files made with OpenMPT 1.17.02.48 r192 and newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;get; 0x088D). In older versions, custom tunings are the only MPTM feature, and they do not use 228 chunks. The old format is documented in [[Development:_OpenMPT_Format_Extensions#Custom_Tunings_(old)|OpenMPT Format Extensions &amp;amp;sect; Custom Tunings (old)]].&lt;br /&gt;
&lt;br /&gt;
Entries containing custom tunings are stored in the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and only if the song has (or uses) any custom tunings (the default IT tuning does not count).&lt;br /&gt;
&lt;br /&gt;
==== UTF-8 Text Encoding Indicator ====&lt;br /&gt;
&lt;br /&gt;
This entry is a single byte with an entry ID of &amp;lt;code&amp;gt;UTF8Tuning&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;55 54 46 38 54 75 6E 69 6E 67&amp;lt;/code&amp;gt; in hex bytes), stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its byte value is 0: ANSI.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection ====&lt;br /&gt;
&lt;br /&gt;
Tuning collections are chunks that contain custom tunings. They can exist separately in .TC files and can be imported into MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, there is only one tuning collection called the &amp;quot;Tune-specific&amp;quot; tuning collection. For MPTM files made with OpenMPT versions older than 1.27.00.55, although there are &amp;quot;local tunings&amp;quot; and &amp;quot;built-in tunings&amp;quot; (which are now discontinued) besides the &amp;quot;tune-specific&amp;quot; ones, they are &#039;&#039;&#039;not&#039;&#039;&#039; stored in the MPTM files themselves.&lt;br /&gt;
&lt;br /&gt;
In MPTM files, the &amp;quot;tune-specific tunings&amp;quot; collection is stored as an entry of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, and its entry ID (stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk) is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
* The entry ID of the &amp;quot;tune-specific tunings&amp;quot; collection chunk in MPTM files, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* 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 &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;54 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 3.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of this collection&#039;s name, and the name of its tunings.&lt;br /&gt;
* If this entry exists and its byte value is not 0: UTF-8 (override global encoding).&lt;br /&gt;
* If this entry does not exist or its byte value is 0: Inherit encoding from global encoding.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
In TC files, the name would be the same as what it was when the TC file was exported in OpenMPT.&amp;lt;br/&amp;gt;&lt;br /&gt;
In MPTM files, the only stored tuning collection is the Tune-specific tunings, and its name is &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The collection&#039;s edit mask. This value was used to specify which settings of the collection can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
==== Tuning ====&lt;br /&gt;
&lt;br /&gt;
As described above, each custom tuning is stored as a chunk, as one of the entries of a tuning collection (&amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt;) chunk.&lt;br /&gt;
&lt;br /&gt;
For each custom tuning:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;TC&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;(&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;43 54 42 32 34 34 52 54 49&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is 67108868 (&amp;lt;code&amp;gt;0x04000004&amp;lt;/code&amp;gt; in hex).&amp;lt;!-- todo: was this version number different in some older versions? --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These custom tuning chunks can also be exist separately in .TUN files, and can be exported from / imported to MPTM files using the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in a custom tuning (&amp;lt;code&amp;gt;CTB244RTI&amp;lt;/code&amp;gt;) chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UTF8&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;55 54 46 38&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the tuning&#039;s name.&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8 (override collection&#039;s encoding).&lt;br /&gt;
* If this entry does not exist or its value is 0: Inherit encoding from collection&#039;s encoding.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
| The custom tuning&#039;s name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s edit mask. This value was used to specify which settings of the tuning can be changed, but it is no longer used.&amp;lt;br/&amp;gt;&lt;br /&gt;
Currently, OpenMPT always writes this entry with a value of 0xFFFF (allow editing everything).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0 = General&lt;br /&gt;
* 1 = Group-geometric&lt;br /&gt;
* 3 = Geometric&lt;br /&gt;
Any other value will result in OpenMPT failing to load the custom tuning data.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;33&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Note names (see [[#Tuning_Note_Name_Structure|the Tuning Note Name Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
If this entry does not exist, OpenMPT will use the &amp;quot;default&amp;quot; note names (the predefined note names when creating a new tuning in OpenMPT).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI0&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Ratio table (see [[#Tuning_Ratio_Table_Structure|the Ratio Table Structure]]).&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is General or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI1&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 31&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all types of tunings, and usually with a value of -64.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI2&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 32&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric.&amp;lt;br/&amp;gt;&lt;br /&gt;
(For group-geometric tunings, the group size is equal to the size of the ratio table.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI3&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 33&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry if the tuning type is Geometric or Group-geometric.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTI4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 54 49 34&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Tuning Note Name Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of note names.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT uses the same number as the group size for Geometric and Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
This is the structure of a single note name:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note index. A zero-based index specifying which note this name corresponds to (0=first note, 1=second note, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name&amp;lt;!-- (in characters?) --&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The text encoding is inherited from the custom tuning&#039;s text encoding entry.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure above is repeated for every note (or every note &#039;&#039;&#039;in the group&#039;&#039;&#039; if the tuning is Geometric or Group-geometric) that has a custom name.&lt;br /&gt;
&lt;br /&gt;
Note: In Geometric and Group-geometric tunings, the group numbers / octave numbers are &#039;&#039;&#039;not&#039;&#039;&#039; a part of the note names.&lt;br /&gt;
&lt;br /&gt;
===== Tuning Ratio Table Structure =====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;auint64&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of ratios in the ratio table.&amp;lt;/br&amp;gt;&lt;br /&gt;
OpenMPT writes the same number as the group size for Group-geometric tunings, and 128 for General tunings.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ratios.&amp;lt;br/&amp;gt;&lt;br /&gt;
For Group-geometric tunings, only the ratios of the first (lowest pitch) group are stored.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map ====&lt;br /&gt;
&lt;br /&gt;
(Not to be confused with &amp;quot;maps&amp;quot; of chunks!)&lt;br /&gt;
&lt;br /&gt;
The tuning map is one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;31&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
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&#039;s tune-specific tuning collection chunk.&lt;br /&gt;
&lt;br /&gt;
The first item in the structure is a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;, containing the number of tunings that are used by instruments, including the default IT tuning and non-tune-specific tunings:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings that are used by instruments, including non-tune-specific tunings.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name (in characters).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s name.&lt;br /&gt;
* The name of the default IT tuning (called &amp;lt;code&amp;gt;OpenMPT IT behaviour&amp;lt;/code&amp;gt; in OpenMPT), is written as &amp;lt;code&amp;gt;-&amp;gt;MPT_ORIGINAL_IT&amp;lt;-&amp;lt;/code&amp;gt;.&lt;br /&gt;
* In files made with OpenMPT 1.27.00.55 or older, the names of the built-in tunings are written as &amp;lt;code&amp;gt;12TET&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;12TET &amp;lt;nowiki&amp;gt;[[fs15 1.17.02.49]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
OpenMPT will stop reading a string if a &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; byte (null character) is present anywhere in the string.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| The index that this tuning is mapped to.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The structure shown in the table above is repeated for every tuning.&lt;br /&gt;
&lt;br /&gt;
Finally there is an array of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;s, 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Extended Pattern Data ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
All extended pattern data is stored in a &amp;quot;pattern collection&amp;quot; chunk.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern Collection ====&lt;br /&gt;
&lt;br /&gt;
The pattern collection is a chunk, stored as one of the entries of the base mptm chunk. It contains extended pattern data.&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50 63&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
The entries stored in the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk consist of &amp;quot;extended pattern&amp;quot; chunks, and a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; with an entry ID of &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; (6E 75 6D in hex bytes) 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.&lt;br /&gt;
&lt;br /&gt;
If any pattern has extended data, OpenMPT writes the extended data for all patterns (not just the required ones), followed by the &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; entry containing the number of patterns in the song.&lt;br /&gt;
&lt;br /&gt;
==== Extended Pattern ====&lt;br /&gt;
&lt;br /&gt;
As described above, the extended data for each pattern is stored as a chunk, as one of the entries of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
For each pattern:&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptPc&amp;lt;/code&amp;gt; chunk, is a little-endian 16-bit unsigned integer, specifying its pattern number (pattern 0 = 0x0000, pattern 1 = 0x0001, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 50&amp;lt;/code&amp;gt; in hex bytes)&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptP&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;64 61 74 61&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The extended pattern data. Currently only used for Parameter Control notes.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the IT pattern format, but without the first 8 bytes.&amp;lt;br/&amp;gt;&lt;br /&gt;
It is used to only store the pattern&#039;s Parameter Control notes, and uses a different format for mask bytes:&lt;br /&gt;
* Bit 0: Note included (PC or PCs)&lt;br /&gt;
* Bit 1: Plugin number included&lt;br /&gt;
* Bit 2: High byte of controller ID included&lt;br /&gt;
* Bit 3: Low byte of controller ID included&lt;br /&gt;
* Bit 4: High byte of parameter included&lt;br /&gt;
* Bit 5: Low byte of parameter included&lt;br /&gt;
* Bit 6: Extra data included&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
For the note value:&lt;br /&gt;
* PC notes are stored as &amp;lt;code&amp;gt;0xFC&amp;lt;/code&amp;gt;&lt;br /&gt;
* PCs notes are stored as &amp;lt;code&amp;gt;0xFB&amp;lt;/code&amp;gt;&lt;br /&gt;
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.&amp;lt;br/&amp;gt;&lt;br /&gt;
Any data that is specified by the mask byte to &#039;&#039;&#039;not&#039;&#039;&#039; be included will have the same data as the previous PC/PCs note in the channel.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT writes this entry for all patterns, even if they do not contain PC/PCs notes.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPB.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 42 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per beat&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RPM.&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;52 50 4D 2E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Custom &amp;quot;rows per measure&amp;quot; value for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom time signature.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;53 57 4E 47&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Custom tempo swing for this pattern.&amp;lt;br/&amp;gt;&lt;br /&gt;
Stored in the same format as the &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; value in the OpenMPT song extensions.&amp;lt;br/&amp;gt;&lt;br /&gt;
OpenMPT only writes this entry for patterns that use a custom tempo swing.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sequences ===&lt;br /&gt;
&lt;br /&gt;
Currently, the main way sequences are stored is a &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
Here is a history of how order lists were stored throughout different versions:&lt;br /&gt;
* 2006-08-20: OpenMPT 1.17.02.45, r166 (MPTM format introduced)&lt;br /&gt;
** Only one sequence, order list stored at 0x00C0 (exactly like Impulse Tracker).&lt;br /&gt;
* 2006-10-02: OpenMPT 1.17.02.45, r168&lt;br /&gt;
** CWTV changed from 0x088A to 0x088B.&lt;br /&gt;
** The order list stored at 0x00C0 now uses a custom structure (documented in [[Development:_OpenMPT_Format_Extensions#Order_list_(old)|OpenMPT Format Extensions &amp;amp;sect; Order list (old)]]), and uses 32-bit pattern indices instead of 8-bit, allowing patterns over 253.&lt;br /&gt;
* 2008-01-12: OpenMPT 1.17.02.49, r195&lt;br /&gt;
** CWTV changed from 0x088D to 0x088E.&lt;br /&gt;
** 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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk that is used to store the order list if there are patterns over 253. If a file has this chunk, OpenMPT will read the order list from this chunk, and not from 0x00C0.&lt;br /&gt;
* 2009-09-16: OpenMPT 1.17.03.01, r366&lt;br /&gt;
** MPTM files can now have multiple sequences, where one of them can be the &amp;quot;default sequence&amp;quot;. All sequences are now stored in a 228 chunk called the &amp;quot;sequence collection&amp;quot; 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.&lt;br /&gt;
&amp;lt;!-- todo: I might have made some mistakes in writing all of that, check if there are any mistakes --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the rest of this document, the new multi-sequence format introduced in r366 is documented first, and after that is the &amp;quot;old&amp;quot; sequence format introduced in r195 (which is still written to files if the default sequence contains patterns beyond 253).&lt;br /&gt;
&lt;br /&gt;
==== Sequence Collection (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
The sequence collection is a chunk, stored as one of the entries of the base &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. It contains the sequences of the MPTM file.&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is also &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71 43&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Entry ID&lt;br /&gt;
! Entry ID (hex bytes)&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of sequences in the file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;63&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;quot;default sequence&amp;quot; of the file.&amp;lt;br/&amp;gt;&lt;br /&gt;
Uses zero-based numbering. (0=first sequence, 1=second sequence, etc.)&amp;lt;br/&amp;gt;&lt;br /&gt;
The &amp;quot;default sequence&amp;quot; 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.&amp;lt;br/&amp;gt;&lt;br /&gt;
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).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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&#039;s number, as a byte, with 0-based numbering.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
==== Sequence (r366 and newer) ====&lt;br /&gt;
&lt;br /&gt;
As described above, each sequence is stored as a chunk, as one of the entries of the mptSeqC chunk.&lt;br /&gt;
For each sequence:&lt;br /&gt;
&lt;br /&gt;
* Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptSeqC&amp;lt;/code&amp;gt; chunk, is a single byte that determines which sequence it is (sequence 1 = 0x00, sequence 2 = 0x01, and so on).&lt;br /&gt;
* Its chunk ID, which is stored in its own header, is &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;6D 70 74 53 65 71&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The chunk&#039;s version number is the same integer stored in the &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; value in the OpenMPT song extensions (e.g., 1.29.14.01 would be 0x01291401).&lt;br /&gt;
&lt;br /&gt;
These are the entries stored in an &amp;lt;code&amp;gt;mptSeq&amp;lt;/code&amp;gt; chunk:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Entry ID&lt;br /&gt;
| Entry ID (hex bytes)&lt;br /&gt;
| Datatype&lt;br /&gt;
| Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;u&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;75&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt;&lt;br /&gt;
| The text encoding of the sequence&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
* If this entry exists and its value is not 0: UTF-8.&lt;br /&gt;
* If this entry does not exist or its value is 0: ANSI.&lt;br /&gt;
The current version of OpenMPT always writes this entry with a value of 1 (UTF-8).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6E&amp;lt;/code&amp;gt;&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| Sequence name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Contains the length of the name (&#039;&#039;&#039;in bytes, not characters&#039;&#039;&#039;), followed by the name.&amp;lt;br/&amp;gt;&lt;br /&gt;
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.&lt;br /&gt;
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).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;l&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;6C&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;61&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The sequence&#039;s order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;72&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Restart position. OpenMPT only writes this entry if the sequence&#039;s restart position is not 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;Old&amp;quot; Sequence (r195 and newer) ====&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk. Its entry ID, which is stored in the map of the &amp;lt;code&amp;gt;mptm&amp;lt;/code&amp;gt; chunk, is &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;32&amp;lt;/code&amp;gt; in hex bytes).&lt;br /&gt;
&lt;br /&gt;
The structure of this entry is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Datatype&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the sequence (in orders).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The order list. Each order has the pattern number associated with it stored as a &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
For special (&amp;quot;non-pattern&amp;quot;) orders:&lt;br /&gt;
* &amp;lt;code&amp;gt;+++&amp;lt;/code&amp;gt; (separator) orders are stored as 0xFFFE.&lt;br /&gt;
* &amp;lt;code&amp;gt;---&amp;lt;/code&amp;gt; (end of song) orders are stored as 0xFFFF.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|228 Extensions]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
- cs127&lt;br /&gt;
2022-02-26&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4229</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4229"/>
		<updated>2022-02-26T10:06:08Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* MPTM Extensions */ oops typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint32  Size of this chunk, excluding the header&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
 Offset Type     Content&lt;br /&gt;
 0      char[4]  Plugin type (&amp;quot;PtsV&amp;quot; for VST, &amp;quot;OMXD&amp;quot; for DMO plugins)&lt;br /&gt;
 4      char[4]  Plugin unique ID&lt;br /&gt;
 8      uint8    Routing Flags&lt;br /&gt;
 9      uint8    Mix Mode&lt;br /&gt;
 10     uint8    Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
 11     uint8    Reserved&lt;br /&gt;
 12     uint32   Output Routing (0 = send to master 0x80 + x = send to plugin x)&lt;br /&gt;
 16     char[16] Reserved&lt;br /&gt;
 32     char[32] User-chosen plugin name (Windows code page)&lt;br /&gt;
 64     char[64] Library name (Original DLL name / DMO identifier - UTF-8 starting from OpenMPT 1.22.07.01, Windows code page in older versions)&lt;br /&gt;
 128    uint32   Length of plugin-specific data (parameters or opaque chunk)&lt;br /&gt;
 132    char[]   Plugin-specific data&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routing Flags:&#039;&#039;&#039;&lt;br /&gt;
* 0x01: Apply to master mix&lt;br /&gt;
* 0x02: Bypass effect&lt;br /&gt;
* 0x04: Wet Mix (dry added)&lt;br /&gt;
* 0x08: Expand Mix [0%,100%] → [-200%,200%]&lt;br /&gt;
* 0x10: Plugin will automatically suspend on silence&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mix Modes:&#039;&#039;&#039;&lt;br /&gt;
* 0: normal processing&lt;br /&gt;
* 1: MIX += DRY - WET * wetRatio&lt;br /&gt;
* 2: MIX += WET - DRY * dryRatio&lt;br /&gt;
* 3: MIX -= WET - DRY * wetRatio&lt;br /&gt;
* 4: MIX -= middle - WET * wetRatio + middle - DRY&lt;br /&gt;
* 5: MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;br/&amp;gt;MIX_R += dryRatio * (WET_L - DRY_L) + wetRatio * (DRY_R - WET_R)&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk chunk, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint16  Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint16  Size of this chunk, excluding the header&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || VSTi Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. The i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors should be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They are documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
 Offset Type   Content&lt;br /&gt;
 0      VarInt Length of the filename&lt;br /&gt;
 ?      char[] Filename as UTF-8 string (not null-terminated)&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform should be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. should be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data should be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag should be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
 Offset Type     Content&lt;br /&gt;
 0      uint16   Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
 2      uint32   Number of items in the order list&lt;br /&gt;
 6      uint32[] The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[4]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the Tuning Collection version is 2.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[4]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the tuning version is 3.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the tuning version is 3.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format &amp;lt;!-- (will be documented soon) --&amp;gt;, but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
 Offset Type   Content&lt;br /&gt;
 0      uint32 Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
 4      uint16 Default panning (0...256)&lt;br /&gt;
 6      uint16 Default volume (0...256)&lt;br /&gt;
 8      uint16 Global volume (0...64)&lt;br /&gt;
 10     uint16 Reserved (must be 0)&lt;br /&gt;
 12     uint8  Auto-vibrato type&lt;br /&gt;
 13     uint8  Auto-vibrato sweep&lt;br /&gt;
 14     uint8  Auto-vibrato depth&lt;br /&gt;
 15     uint8  Auto-vibrato rate&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 655350 Hz.&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
	<entry>
		<id>https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4228</id>
		<title>Development: OpenMPT Format Extensions</title>
		<link rel="alternate" type="text/html" href="https://wiki.openmpt.org/index.php?title=Development:_OpenMPT_Format_Extensions&amp;diff=4228"/>
		<updated>2022-02-26T10:05:52Z</updated>

		<summary type="html">&lt;p&gt;CS127: /* MPTM Extensions */ added a link to the 228 extensions page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModPlug Tracker and OpenMPT have extended the IT and XM formats in various ways. In general, these hacks are frowned upon, but here is some documentation on those hacks in case you want to support them in your own player. I am really sorry about all this mess, but all of this has grown historically way before I joined OpenMPT development.&lt;br /&gt;
&lt;br /&gt;
Presence of these format extensions in a file does not necessarily imply that it was created with ModPlug Tracker or OpenMPT. Some of the extensions are also used e.g. by BeRoTracker.&lt;br /&gt;
&lt;br /&gt;
Any numeric values are stored in little-endian format, unless noted otherwise.&lt;br /&gt;
&lt;br /&gt;
Data types used in this document:&lt;br /&gt;
* uint8, uint16, uint32: Unsigned integers with the given bit width.&lt;br /&gt;
* int8, int16, int32: Signed integers with the given bit width.&lt;br /&gt;
* char: A single character (i.e. a byte)&lt;br /&gt;
* float32: Single precision IEEE float&lt;br /&gt;
* VarInt: A MIDI-like variable-length unsigned integer (big-endian value where the highest bit of each byte indicates if another byte follows, and the lower 7 bits containing the actual number).&lt;br /&gt;
* Square brackets [] denote an array of values:&lt;br /&gt;
** [] is a variable-length array (length is deduced from some other attribute)&lt;br /&gt;
** [42] denotes an array with 42 entries.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
The following extensions exist since the (closed-source) ModPlug Tracker days. These extensions are found in [https://en.wikipedia.org/wiki/Interchange_File_Format IFF]-like chunks, but without any padding bytes. The chunks are placed right after the header data in the IT format (i.e. after the edit history / MIDI macro block). In the XM format these chunks are placed right at the end of the file (i.e. after the sample data). At the time of writing, these chunks are always written out in the order described here, but if possible you should probably try to read them without expecting a certain order. All chunks are optional.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint32  Size of this chunk, excluding the header&lt;br /&gt;
&lt;br /&gt;
=== Chunks ===&lt;br /&gt;
&lt;br /&gt;
==== text (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the song message (CR line endings), its length is determined by the chunk size.&lt;br /&gt;
&lt;br /&gt;
==== MIDI (XM only) ====&lt;br /&gt;
&lt;br /&gt;
Contains the MIDI macro configuration, in the same format as in the IT format.&lt;br /&gt;
&lt;br /&gt;
==== PNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the pattern names. Each pattern name is 32 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The pattern names are stored continuously, i.e. there are (chunk size / 32) pattern names in the chunk, for pattern 0, pattern 1, ... pattern (chunk size / 32 - 1).&lt;br /&gt;
&lt;br /&gt;
==== CNAM ====&lt;br /&gt;
&lt;br /&gt;
Contains the channel names. Each channel name is 20 bytes long and not necessarily null-terminated. The encoding is unspecified (Windows code page). The channel names are stored continuously, i.e. there are (chunk size / 20) channel names in the chunk, for channel 1, channel 2, ... channel (chunk size / 20).&lt;br /&gt;
&lt;br /&gt;
==== CHFX ====&lt;br /&gt;
&lt;br /&gt;
Contains the plugin assignment for each channel. For every channel, there is a 32-bit integer plugin index. 0 means no plugin, 1 is the first plugin, etc...&lt;br /&gt;
&lt;br /&gt;
==== FX00, ... FX99, F100, ... F255 ====&lt;br /&gt;
&lt;br /&gt;
Contains plugin information for each plugin slot. &amp;lt;code&amp;gt;FX00&amp;lt;/code&amp;gt; contains the information for the first plugin slot, &amp;lt;code&amp;gt;FX99&amp;lt;/code&amp;gt; for the 100th, &amp;lt;code&amp;gt;F100&amp;lt;/code&amp;gt; for the 101st, etc...&lt;br /&gt;
&lt;br /&gt;
 Offset Type     Content&lt;br /&gt;
 0      char[4]  Plugin type (&amp;quot;PtsV&amp;quot; for VST, &amp;quot;OMXD&amp;quot; for DMO plugins)&lt;br /&gt;
 4      char[4]  Plugin unique ID&lt;br /&gt;
 8      uint8    Routing Flags&lt;br /&gt;
 9      uint8    Mix Mode&lt;br /&gt;
 10     uint8    Gain Factor * 10 (9 = 90%, 10 = 100%, 11 = 110%, etc.). A value of 0 is equal to 10 (i.e. 100%).&lt;br /&gt;
 11     uint8    Reserved&lt;br /&gt;
 12     uint32   Output Routing (0 = send to master 0x80 + x = send to plugin x)&lt;br /&gt;
 16     char[16] Reserved&lt;br /&gt;
 32     char[32] User-chosen plugin name (Windows code page)&lt;br /&gt;
 64     char[64] Library name (Original DLL name / DMO identifier - UTF-8 starting from OpenMPT 1.22.07.01, Windows code page in older versions)&lt;br /&gt;
 128    uint32   Length of plugin-specific data (parameters or opaque chunk)&lt;br /&gt;
 132    char[]   Plugin-specific data&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Routing Flags:&#039;&#039;&#039;&lt;br /&gt;
* 0x01: Apply to master mix&lt;br /&gt;
* 0x02: Bypass effect&lt;br /&gt;
* 0x04: Wet Mix (dry added)&lt;br /&gt;
* 0x08: Expand Mix [0%,100%] → [-200%,200%]&lt;br /&gt;
* 0x10: Plugin will automatically suspend on silence&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mix Modes:&#039;&#039;&#039;&lt;br /&gt;
* 0: normal processing&lt;br /&gt;
* 1: MIX += DRY - WET * wetRatio&lt;br /&gt;
* 2: MIX += WET - DRY * dryRatio&lt;br /&gt;
* 3: MIX -= WET - DRY * wetRatio&lt;br /&gt;
* 4: MIX -= middle - WET * wetRatio + middle - DRY&lt;br /&gt;
* 5: MIX_L += wetRatio * (WET_L - DRY_L) + dryRatio * (DRY_R - WET_R)&amp;lt;br/&amp;gt;MIX_R += dryRatio * (WET_L - DRY_L) + wetRatio * (DRY_R - WET_R)&lt;br /&gt;
&lt;br /&gt;
The first four bytes of the plugin-specific data determine the type of data. If they are all 0, then the plugin parameters follow as an array of float32 values. Otherwise, plugin type specific data follows which should be treated as an opaque chunk. For example, for VST plugins that support the effGetChunk / effSetChunk chunk, the first four bytes will be &amp;quot;fEvN&amp;quot;, followed by the data to be sent to the plugin.&lt;br /&gt;
&lt;br /&gt;
After the plugin information described above, more information may follow in OpenMPT modules. This information is again stored in chunks. However, there are two legacy chunks which do not have any size stored alongside the chunk identifier:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWRT&amp;lt;/code&amp;gt; || float32 || Dry/Wet Ratio of the plugin. This chunk does not denote its size!&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PROG&amp;lt;/code&amp;gt; || uint32 || Default plugin program (preset) to restore. This chunk does not denote its size!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Any chunks that will be added in the future will have proper IFF-like chunks with a 32-bit size field.&lt;br /&gt;
&lt;br /&gt;
== ModPlug Instrument Extensions (IT only) ==&lt;br /&gt;
&lt;br /&gt;
To be able to address more than 256 samples in the IT format, ModPlug Tracker has an extension to store the high byte of sample indices for the instrument sample map.&lt;br /&gt;
&lt;br /&gt;
By default, the last four bytes of an IT instrument (right after the pitch envelope) are unused. If they read &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt;, 120 extra bytes follow, one for each note in the sample map. These bytes are the high byte of the sample index, i.e. they need to be multiplied by 256 and then added to the already read sample index.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Extensions (General Information) ==&lt;br /&gt;
&lt;br /&gt;
In the XM format, OpenMPT instrument extensions may follow the ModPlug song extensions and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
&lt;br /&gt;
In the IT format, OpenMPT instrument extensions may follow the sample block and may in return be followed by OpenMPT song extensions.&lt;br /&gt;
This is very ugly, because there might not be any samples, in which case the last thing before the extension block would be the last pattern. If there are no patterns, the last thing before the extension block would be a sample header (at least one sample header will be present even if there is no sample data – but you may even want to cover the case where there are no sample headers, for being compatible with possible future changes). So you will somehow have to keep track of the highest offset you have read into the file. If the last sample is IT-compressed, things become even more complicated: There is no way to know the compressed size of a compressed sample, so in case you want to skip sample loading, and the last sample happens to be compressed, you can do the following:&lt;br /&gt;
Since we know that the extended instrument and song properties start right after the last sample, and since IT-compressed samples consist of chunks with a prepended 16-bit length field, you can simply read that 16-bit number, skip this amount of bytes, then check if you can read OpenMPT&#039;s &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, and if not, read the next 16-bit length, skip the bytes, etc...&lt;br /&gt;
&lt;br /&gt;
In pseudo code, finding the OpenMPT extensions in an IT / MPTM file could look somewhat like this:&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;offset&#039;&#039; = 0&lt;br /&gt;
 &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
 &lt;br /&gt;
 // In case there are no patterns and no sample data (just empty sample slots):&lt;br /&gt;
 if(number of samples &amp;gt; 0):&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = last sample header pointer + sizeof(ITSampleHeader)&lt;br /&gt;
 &lt;br /&gt;
 for all samples:&lt;br /&gt;
     if sample is not compressed or if samples are decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = false&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data + sample size)&lt;br /&gt;
     else if sample is compressed and samples are not decoded:&lt;br /&gt;
         &#039;&#039;lastSampleCompressed&#039;&#039; = true&lt;br /&gt;
         &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, pointer to sample data)&lt;br /&gt;
 &lt;br /&gt;
 // In case there is no sample data:&lt;br /&gt;
 for all patterns:&lt;br /&gt;
     &#039;&#039;offset&#039;&#039; = max(&#039;&#039;offset&#039;&#039;, end of pattern data)&lt;br /&gt;
 &lt;br /&gt;
 if &#039;&#039;lastSampleCompressed&#039;&#039;:&lt;br /&gt;
     while not eof:&lt;br /&gt;
         if next four bytes are XTPM or STPM:&lt;br /&gt;
             &#039;&#039;chunkID&#039;&#039; = next four bytes&lt;br /&gt;
             if &#039;&#039;chunkID&#039;&#039; only contains ASCII characters (all bytes are in 32…127)&lt;br /&gt;
                 &#039;&#039;offset&#039;&#039; = current position - 4; break&lt;br /&gt;
             else&lt;br /&gt;
                 skip back 8 bytes&lt;br /&gt;
         read uint16 value and skip as many bytes&lt;br /&gt;
 &lt;br /&gt;
 Try reading XTPM and STPM extensions at &#039;&#039;offset&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The provided data types are just for orientation, i.e. the minimum recommended field size for storing the values in memory. You must expect fields to have a different size, since sometimes they do so for historic reasons. Defensive programming is your friend. Most of the FOURCCs also just make sense when read backwards, again for historic reasons. Note that some of these extensions duplicate existing functionality of the IT/XM format. In this case, the extensions take precedence over the value previous found in the file.&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Instrument Extensions ==&lt;br /&gt;
&lt;br /&gt;
Instrument extensions start with the &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. So you have to read the following chunks and as soon as you read the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes for a chunk, you know you have read to far and can continue with reading OpenMPT Song Extensions instead.&lt;br /&gt;
&lt;br /&gt;
Instrument extensions are stored in a peculiar way: There is one chunk per property, and it contains the values for all instruments at once. The layout is as follows:&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint16  Size of this chunk&#039;s entry &#039;&#039;&#039;for one instrument&#039;&#039;&#039; (i.e. total chunk content size is this field × number of instruments)&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
The following instrument properties exist. Some of them are redundant depending on the file type and thus not present in all files. If they are redundant, they overwrite the values that were obtained from the format-specific structures.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..OF&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Fade-out&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...P&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Panning (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EV&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of volume envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..EP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pan envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.EiP&amp;lt;/code&amp;gt; || uint32 || MPTM || Number of pitch envelope nodes (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..BM&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || MIDI Bank&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Program&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..CM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || MIDI Channel&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PV&amp;lt;/code&amp;gt; || uint16[] || MPTM || Volume Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EV&amp;lt;/code&amp;gt; || uint8[] || MPTM || Volume Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[PP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pan Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.[EP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pan Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[PiP&amp;lt;/code&amp;gt; || uint16[] || MPTM || Pitch Envelope Ticks (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[EiP&amp;lt;/code&amp;gt; || uint8[] || MPTM || Pitch Envelope Values (if ≥ 25 nodes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.PiM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin, 0 = no plugin, 1 = first plugin, etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..RV&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Ramping / Attack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...R&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SC&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Cutoff Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..SR&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Resonance Swing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MF&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Filter Mode&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HEVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Velocity Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;HOVP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Plugin Volume Handling&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREV&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Volume Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREA&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pan Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NREP&amp;lt;/code&amp;gt; || uint8 || IT, MPTM, XM || Pitch Envelope Release Node&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DWPM&amp;lt;/code&amp;gt; || uint8 || IT, MPTM || Pitch Wheel Depth&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LTTP&amp;lt;/code&amp;gt; || uint16 || IT, MPTM, XM || Integer part of Pitch / Tempo Lock&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PTTF&amp;lt;/code&amp;gt; || uint16 || MPTM || Fractional part of Pitch / Tempo Lock (0...9999)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Legacy Extension ===&lt;br /&gt;
&lt;br /&gt;
But wait, there is more! Some really old OpenMPT versions (1.17 RC1 and older, but not 1.17 RC2) do not use the instrument extensions described above. However, they also need to store the plugin reference for each instrument, which is done in another modular block following each instrument header (and possibly the &amp;lt;code&amp;gt;MPTX&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;XTPM&amp;lt;/code&amp;gt; extension of that instrument header).&lt;br /&gt;
If this legacy extension is present, the instrument header is followed by the magic bytes &amp;lt;code&amp;gt;MSNI&amp;lt;/code&amp;gt; and an uint32 containing the modular data size.&lt;br /&gt;
&lt;br /&gt;
Currently there is only one chunk in this modular data block. Its FOURCC is &amp;lt;code&amp;gt;GULP&amp;lt;/code&amp;gt;, has no size information and contains an uint8 for the plugin index (0 = no plugin, 1 = first plugin, etc.).&lt;br /&gt;
&lt;br /&gt;
== OpenMPT Song Extensions ==&lt;br /&gt;
&lt;br /&gt;
Song extensions start with the &amp;lt;code&amp;gt;STPM&amp;lt;/code&amp;gt; magic bytes, but there is no size indication of the total size of this block. In an IT / XM file, these extensions are the last chunks in the file, so you can continue reading until you are out of data. In the case of MPTM files, some further MPTM-specific data follows. This data starts with the bytes &amp;quot;228&amp;quot; followed by ASCII charater 4 (not the digit), so you can keep reading the song extensions until you read this FOURCC.&lt;br /&gt;
&lt;br /&gt;
=== Chunk Header Layout ===&lt;br /&gt;
&lt;br /&gt;
 Offset Type    Content&lt;br /&gt;
 0      char[4] Magic bytes (FOURCC)&lt;br /&gt;
 4      uint16  Size of this chunk, excluding the header&lt;br /&gt;
&lt;br /&gt;
=== Chunk Contents ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! FOURCC !! Data Type !! Formats !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..TD&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Integer part of the default tempo (required if it is larger than 255 in IT / MPTM, but also found in legacy XM files)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DTFR&amp;lt;/code&amp;gt; || uint32 || MPTM || Fractional part of the default tempo (0...9999)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.BPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Beat&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MPR&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Rows Per Measure&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;...C&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Number of channels&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SnhC&amp;lt;/code&amp;gt; || - || IT, MPTM || If there are more than 64 channels in the IT / MTPM format, this chunk contains the default panning, volume and flags for channels 65+. They are encoded the same way as in the IT header, except that volume and panning are stored in an interleaved way (i.e. volume for channel 65, pan for channel 65, volume for channel 66, ...)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..MT&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Tempo Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: classic&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: alternative&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: modern&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.MMP&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Mix Levels &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: Original&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: 1.17 RC1&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: 1.17 RC2&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: 1.17 RC3&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Compatible&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Compatible (FT2 Pan Law)&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VWC&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Created With&amp;quot; version (e.g. OpenMPT 1.23.45.67 = 0x01234567)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VWSL&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || OpenMPT &amp;quot;Last Saved With&amp;quot; version&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.APS&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || Sample Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;VTSV&amp;lt;/code&amp;gt; || uint32 || IT, MPTM, XM || VSTi Pre-Amp&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.VGD&amp;lt;/code&amp;gt; || uint32 || XM || Global Volume (0...256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;..PR&amp;lt;/code&amp;gt; || uint16 || IT, MPTM || Restart Position&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RSMP&amp;lt;/code&amp;gt; || uint32 || MPTM || Resampling Mode &amp;lt;ul&amp;gt; &amp;lt;li&amp;gt;0: No Interpolation (1 tap)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;1: Linear (2 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;2: Cubic Spline (4 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;3: Sinc + Lowpass / Polyphase (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;4: Sinc / XMMS-ModPlug (8 taps)&amp;lt;/li&amp;gt; &amp;lt;li&amp;gt;5: Default&amp;lt;/li&amp;gt; &amp;lt;/ul&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CUES&amp;lt;/code&amp;gt; || - || MPTM || Sample cue points for a single sample (only MPTM format). The first uint16 in the chunk indicates for which sample slot the cue points are meant. The rest of the chunk contains all cue points as uint32s. If this chunk is missing for a particular sample slot, OpenMPT assumes the default cue points for this slot. The i-th cue point can be computed as i × 2048.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SWNG&amp;lt;/code&amp;gt; || - || MPTM || Contains tempo swing factors (only MPTM format). The first uint16 in the chunk indicates the number of swing rows. The rest of the chunk contains all swing factors as uint32s. A factor of 16777216 (2&amp;lt;sup&amp;gt;24&amp;lt;/sup&amp;gt;) is considered to be unity, i.e. does not modify the row duration. After loading, the number of swing factors should be resized to the actual number of rows per beat (in case of malformed file) and re-normalized.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.FSM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || A bit field of generic compatibility flags. For modules made with OpenMPT 1.25 and older, the most important one is 0x01 (first bit set), which is IT-/XM-compatible playback mode. All other flags indicate which [[Manual: Compatible Playback#Playback Compatibility Settings|compatibility settings]] are toggled.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AUTH&amp;lt;/code&amp;gt; || uint8[] || IT, MPTM, XM || Song artist, as UTF-8 string&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AMIM&amp;lt;/code&amp;gt; || - || IT, MPTM, XM || MIDI Mapping settings&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CCOL&amp;lt;/code&amp;gt; || rgbx[] || IT, MPTM, XM || Channel colors. The chunk size divided by 4 indicates the number of channels present. Format is [R, G, B, 0] for channels that have a color assigned, or [x, x, x, non-zero] for a channel with no color.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MPTM Extensions ==&lt;br /&gt;
&lt;br /&gt;
=== Detecting an MPTM file ===&lt;br /&gt;
&lt;br /&gt;
There are two types of hacked IT files: In early versions of the MPTM format (used in OpenMPT 1.17.02.4x), the &amp;lt;code&amp;gt;IMPM&amp;lt;/code&amp;gt; magic bytes are replaced by &amp;lt;code&amp;gt;tpm.&amp;lt;/code&amp;gt;, so they are not backwards compatible. Newer MPTM files use the original magic, but use a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0889h and 0FFFh (inclusive) in the header.&lt;br /&gt;
&lt;br /&gt;
In both cases, the last four bytes of the file point to the start of the MPTM extensions. If the magic bytes &amp;quot;228&amp;quot; can be found at this start position, it is a valid MPTM file.&lt;br /&gt;
&lt;br /&gt;
=== 228 Extensions ===&lt;br /&gt;
&lt;br /&gt;
228 Extensions have been used since OpenMPT 1.17.02.48 r192 for features that are only available in the MPTM format,&lt;br /&gt;
such as Custom Tunings, Multiple Sequences, and Parameter Control notes.&lt;br /&gt;
&lt;br /&gt;
They documented [[Development:_228_Extensions|here]].&lt;br /&gt;
&lt;br /&gt;
=== External Samples ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can reference external samples. If the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is 80h, then the sample is external. In this case, the sample pointer does not point to actual sample data but to a filename:&lt;br /&gt;
&lt;br /&gt;
 Offset Type   Content&lt;br /&gt;
 0      VarInt Length of the filename&lt;br /&gt;
 ?      char[] Filename as UTF-8 string (not null-terminated)&lt;br /&gt;
&lt;br /&gt;
Note that only the sample waveform should be loaded, but not its metadata: Frequency, loop points, volume, panning, auto-vibrato etc. should be read from the IT file. If the sample length according to the IT header is shorter than the actual sample, the sample data should be trimmed, too.&lt;br /&gt;
&lt;br /&gt;
External samples are used exactly the same way in ITI files.&lt;br /&gt;
&lt;br /&gt;
=== OPL Instruments ===&lt;br /&gt;
&lt;br /&gt;
MPTM files can make use of OPL instruments, just like S3M files. Unlike in S3M files, patch data is not stuffed into the sample header but stored as regular sample data. To tell OPL patches apart from regular samples, the &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; value in the sample header is set to 40h. Note that the check for this flag should be an equal comparison (&amp;lt;code&amp;gt;cvt == 40h&amp;lt;/code&amp;gt;), not a bitwise AND, due to ModPlug&#039;s legacy ADPCM sample &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; type (FFh). Any combination with other &amp;lt;code&amp;gt;cvt&amp;lt;/code&amp;gt; flags is also considered to be illegal.&lt;br /&gt;
&lt;br /&gt;
OPL2 patches are stored in the same order as in S3M files, i.e. interleaved modulator and carrier bytes, with the last (12th) byte being unused and set to 0.&lt;br /&gt;
&lt;br /&gt;
=== Order list (old) ===&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; is between 088Bh and 088Dh (inclusive), the order list at the start of the file is replaced by the following struct:&lt;br /&gt;
&lt;br /&gt;
 Offset Type     Content&lt;br /&gt;
 0      uint16   Version of the order list. Only version 0 is defined. Reject any other values.&lt;br /&gt;
 2      uint32   Number of items in the order list&lt;br /&gt;
 6      uint32[] The order list, as a series of uint32 values. The number of values is determined by the previous field.&lt;br /&gt;
&lt;br /&gt;
=== Custom Tunings (old) ===&lt;br /&gt;
&lt;br /&gt;
This section is for OpenMPT versions before 1.17.02.48 r192. For newer versions, check [[Development:_228_Extensions|228 Extensions]].&lt;br /&gt;
&lt;br /&gt;
Before OpenMPT 1.17.02.48 r192, the only feature that was only available in the MPTM format was Custom Tunings.&lt;br /&gt;
MPTM files that were made before r192 have a &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value between 0x0888 and 0x088C (inclusive).&lt;br /&gt;
&lt;br /&gt;
These MPTM files contain a &amp;quot;Tuning Collection&amp;quot; chunk that contains all the custom tunings that are specific to the song (called &amp;quot;Tune specific tunings&amp;quot; in OpenMPT),&lt;br /&gt;
which is right after the OpenMPT song extensions.&lt;br /&gt;
It is then followed by a &amp;quot;Tuning Map&amp;quot; that determines which tuning each instrument should use.&lt;br /&gt;
&lt;br /&gt;
A Tuning Collection could also exist separately in a &amp;lt;code&amp;gt;.TC&amp;lt;/code&amp;gt; file, that can be exported/imported into an MPTM file in the [[Manual:_Tuning_Properties|Tuning Properties]] dialog.&lt;br /&gt;
&lt;br /&gt;
In an MPTM file, the last four bytes pointed to the start of the &amp;quot;Tune specific tunings&amp;quot; Tuning Collection,&lt;br /&gt;
similar to how they point to the start of 228 extensions in newer (&amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; &amp;amp;gt; 0x088C) MPTM files.&lt;br /&gt;
&lt;br /&gt;
==== Tuning Collection structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Tuning Collection is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[4]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection beginning signature: &amp;lt;code&amp;gt;HSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection version: Always 1 or 2. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the Tuning Collection&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the Tuning Collection version is 2.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the Tuning Collection version is 1.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection name. The current version of OpenMPT reads a maximum of 256 (0x100) characters.&amp;lt;br/&amp;gt;&lt;br /&gt;
If the collection is in a TC file, its name is the same as what it was in OpenMPT when the TC file was exported.&amp;lt;br/&amp;gt;&lt;br /&gt;
But in MPTM files, only the tune-specific tuning collection is stored, and its name is always &amp;lt;code&amp;gt;Tune specific tunings&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tunings can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Number of tunings in the collection. The current version of OpenMPT does not load custom tunings at all if the number of tunings in an MPTM file is greater than 50.&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tunings in this collection, stored right after each other. The structure of a tuning is described below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[4]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning Collection end signature: &amp;lt;code&amp;gt;FSCT&amp;lt;/code&amp;gt; (4 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Tuning structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a Custom Tuning is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning beginning signature: &amp;lt;code&amp;gt;CTRTI_B.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning version: Always 2 or 3. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk beginning signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;B&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk version: Always 3 or 4. &amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the tuning&#039;s name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning edit mask.&amp;lt;br/&amp;gt;&lt;br /&gt;
A set of 16 bits that was used to specify which settings of the tuning can be changed, but is no longer used in newer versions of OpenMPT.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact version that stopped using editmasks --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning type.&lt;br /&gt;
* 0: Generic&lt;br /&gt;
* 1: Group-geometric (originally called &amp;quot;Ratio-periodic&amp;quot;)&lt;br /&gt;
* 3: Geometric (originally called &amp;quot;TET&amp;quot;)&lt;br /&gt;
Newer versions of OpenMPT that use the new tuning format will convert old Geometric tunings to Group-geometric for compatibility reasons.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of the tuning&#039;s note name map. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (custom structure)&lt;br /&gt;
| The tuning&#039;s note name map. Contains the names of notes that have custom names. The structure is described in further below.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning SFS chunk end signature: &amp;lt;code&amp;gt;CT&amp;lt;sfs&amp;gt;E&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Size of the tuning&#039;s ratio table. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;. This value is usually set to 256 (or 0 if the ratio table is unneeded).&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the tuning version is 3.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The tuning&#039;s ratio table. Contains the frequency ratios for every note. If all ratios are 1, the ratio table is unneeded, so its size would be 0.&amp;lt;br/&amp;gt;&lt;br /&gt;
Unlike the newer tuning format that uses 228 extensions, this table contains ratios for every note in every group, regardless of the tuning type.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Finetune steps. Maximum value is 65535 (0xFFFF), even if the datatype is &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; if the tuning version is 3.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning version is 2.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| An array of finetune step ratios, containing the same number of values as the finetune steps value.&amp;lt;br/&amp;gt;&lt;br /&gt;
The first value is 1, and each value is r&amp;lt;sup&amp;gt;(1/finetunesteps)&amp;lt;/sup&amp;gt; times the previous value,&amp;lt;br/&amp;gt;&lt;br /&gt;
where r is the ratio of note 1 (the note after the middle note) to note 0 (the middle note).&amp;lt;br/&amp;gt;&lt;br /&gt;
This table no longer exists in the newer tuning format that uses 228 extensions.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| First note index in the ratio table. Usually set to -128.&amp;lt;br/&amp;gt;&lt;br /&gt;
The current version of OpenMPT rejects values smaller than -200 and greater than 200.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group size.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;float32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Group ratio.&amp;lt;br/&amp;gt;&lt;br /&gt;
For generic tunings, this value is 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[8]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Tuning end signature: &amp;lt;code&amp;gt;CTRTI_E.&amp;lt;/code&amp;gt; (8 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Many of the values that are stored for each tuning are redundant.&lt;br /&gt;
For example, the ratio table contains ratios for every note, regardless of the tuning type, even though it makes sense to&lt;br /&gt;
only have ratios for a single group in group-geometric tunings, and to not be stored at all in geometric tunings.&lt;br /&gt;
But they still have to be stored for these old versions of OpenMPT to work correctly.&lt;br /&gt;
However, these redundancies no longer exist in the newer tuning format that uses 228 extensions.&lt;br /&gt;
&lt;br /&gt;
==== Tuning note name map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a single entry in the note name map is as follows:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Data type&lt;br /&gt;
! Content/Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;int16&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note number.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt;&lt;br /&gt;
| Length of the note name.&amp;lt;br/&amp;gt;&lt;br /&gt;
Data type:&lt;br /&gt;
* &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; if the tuning&#039;s SFS chunk version is 4.&lt;br /&gt;
* &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; if the tuning&#039;s SFS chunk version is 3.&lt;br /&gt;
&amp;lt;!-- todo: specify the exact OpenMPT versions --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;char[]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Note name. The current version of OpenMPT reads a maximum of 65535 (0xFFFF) characters.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This structure is stored for every note that has a custom name.&lt;br /&gt;
&lt;br /&gt;
For geometric and group-geometric tunings, only the notes of a single group, where the note numbers are between 0 and groupsize-1 (inclusive).&lt;br /&gt;
The note names for that single group are then applied to every group (group/octave numbers are not a part of the note name).&lt;br /&gt;
&lt;br /&gt;
==== Tuning Map structure ====&lt;br /&gt;
&lt;br /&gt;
The structure of a tuning map is identical to that of the new 228 tuning format &amp;lt;!-- (will be documented soon) --&amp;gt;, but with a difference if the &amp;lt;code&amp;gt;cwtv&amp;lt;/code&amp;gt; value is 0x088B or older:&lt;br /&gt;
&lt;br /&gt;
The number of tunings in the map and the length of the tuning names in the map are both stored as &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;uint16&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;uint8&amp;lt;/code&amp;gt; respectively.&lt;br /&gt;
&lt;br /&gt;
== RIFF WAVE ==&lt;br /&gt;
&lt;br /&gt;
OpenMPT uses its own &amp;lt;code&amp;gt;xtra&amp;lt;/code&amp;gt; chunk in RIFF WAVE files to store some sample properties which could otherwise not be represented in the format.&lt;br /&gt;
&lt;br /&gt;
Its layout is as follows:&lt;br /&gt;
&lt;br /&gt;
 Offset Type   Content&lt;br /&gt;
 0      uint32 Sample flags (0x20: Default panning is enabled)&lt;br /&gt;
 4      uint16 Default panning (0...256)&lt;br /&gt;
 6      uint16 Default volume (0...256)&lt;br /&gt;
 8      uint16 Global volume (0...64)&lt;br /&gt;
 10     uint16 Reserved (must be 0)&lt;br /&gt;
 12     uint8  Auto-vibrato type&lt;br /&gt;
 13     uint8  Auto-vibrato sweep&lt;br /&gt;
 14     uint8  Auto-vibrato depth&lt;br /&gt;
 15     uint8  Auto-vibrato rate&lt;br /&gt;
&lt;br /&gt;
Optionally, when copying a sample to the system clipboard, the sample name (32 characters, null-padded) and filename (22 characters, null-padded) follow.&lt;br /&gt;
&lt;br /&gt;
== FLAC ==&lt;br /&gt;
&lt;br /&gt;
Since the FLAC format has no native and standardized way to store loop information, OpenMPT follows Renoise′s way of storing loop information: FLAC supports application-defined metadata, so OpenMPT writes a metadata block with application ID &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt;. The block contains a &amp;lt;code&amp;gt;smpl&amp;lt;/code&amp;gt; chunk (as defined in the [http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf RIFF specification]). Similarly, extended sample properties are stored in another &amp;lt;code&amp;gt;riff&amp;lt;/code&amp;gt; application block contaning the OpenMPT-specific &amp;lt;code&amp;gt;[[#RIFF WAVE|xtra]]&amp;lt;/code&amp;gt; chunk, and sample cue points are stored in a &amp;lt;code&amp;gt;cue&amp;amp;nbsp;&amp;lt;/code&amp;gt; chunk.&lt;br /&gt;
&lt;br /&gt;
OpenMPT also reads and writes the following non-standard vorbis comments:&lt;br /&gt;
* &#039;&#039;&#039;SAMPLERATE&#039;&#039;&#039;: Contains the sample rate (as text) in case it would exceed the maximum sample rate supported by the FLAC format, 655350 Hz.&lt;br /&gt;
* &#039;&#039;&#039;LOOPSTART&#039;&#039;&#039;: The start of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
* &#039;&#039;&#039;LOOPLENGTH&#039;&#039;&#039;: The length of the sample loop in frames. This tag is only read, not written.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development|OpenMPT Format Extensions]]&lt;/div&gt;</summary>
		<author><name>CS127</name></author>
	</entry>
</feed>