Module File Format

  Source   Edit

Introduction

This document is a formal specification of the file format for Trackerboy module files, or *.tbm files. This document is for the current revision, or revision 1.1. See the revision history for previous revisions.

A Module file is a serialized form of the Module object.

For the piece file format see here.

The libtrackerboy library provides a reference implementation for serializing and deserialing module files with this format. See the io module for more documentation.

Note: All multi-byte fields in this specification are stored in little-endian byte order.

Definitions

  • Order - Song order data, a list of OrderRows that determine each pattern
    in the song.
  • OrderRow - A track id assignment for each channel. Determines the tracks
    which make a pattern.
  • Pattern - A collection of Tracks, one for each channel.
  • Track - Song data for a single channel. A Track is a list of TrackRows.

Basic Types

Below are basic data types used throughout the format

Type nameSize (bytes)Description
Uint81Unsigned 8-bit integer (0-255)
BiasedUint81Unsigned 8-bit integer, biased form (1-256)
Bool1Boolean as an uint8 (0 for false, nonzero for true)
Uint162Unsigned 16-bit integer, in little endian (0-65536)
Uint324Unsigned 32-bit integer, in little endian
LStringvariesLength-prefixed UTF-8 string, string data prefixed by a Uint16 length

Error codes

Below is a list of error codes possible when deserialing/serializing a module file. After processing a file, one of these error codes, or Format Result (fr), is given.

IdentifierCodeDescription
frNone0No error, format is acceptable
frInvalidSignature1File has an invalid signature
frInvalidRevision2File has an unrecognize revision, possibly from a newer version of the format
frCannotUpgrade3An older revision file could not be upgraded to the current revision
frInvalidSize4A payload block was incorrectly sized
frInvalidCount5The icount and/or wcount in the header was too big
frInvalidBlock6An unknown identifier was used in a payload block
frInvalidChannel7The format contains an invalid channel in a payload block
frInvalidSpeed8The format contains an invalid speed in a SONG block
frInvalidRowCount9A TrackFormat's rows field exceeds the Song's track size
frInvalidRowNumber10A RowFormat's rowno field exceeds the Song's track size
frInvalidId11An INST or WAVE block contains an invalid id
frDuplicatedId12Two INST blocks or two WAVE blocks have the same id
frInvalidTerminator13The file has an invalid terminator
frReadError14An read error occurred during processing
frWriteError15A write error occurred during processing

Structure

A Trackerboy module consists of a Header, a Payload and a Terminator.

   +----------------+-----------------------------------------+------------+
   |                |                                         |            |
   | Header         | Payload                                 | Terminator |
   | 160 bytes      | size varies                             | 12 bytes   |
   |                |                                         |            |
   +----------------+-----------------------------------------+------------+
  +0              +160                                                      EOF

Header

The figure below defines the Header structure used in all file types. All multi-byte fields are stored in little-endian. The size of the header is a fixed 160 bytes, with any unused space marked as reserved. Reserved fields can be utilized for future revisions of the format. Reserved fields should be set to zero, but this is not enforced.

The layout of the header depends on the header revision, located in offset 24. The current revision of the header is shown below.

      +0         +1         +2        +3
  0   +-------------------------------------------+
      |                                           |
      | signature ( TRACKERBOY )                  |
      |                                           |
  12  +-------------------------------------------+
      | version major                             |
  16  +-------------------------------------------+
      | version minor                             |
  20  +-------------------------------------------+
      | version patch                             |
  24  +----------+----------+---------------------+
      | m. rev   | n. rev   | reserved            |
  28  +----------+----------+---------------------+
      |                                           |
      |                                           |
      |                                           |
      | title                                     |
      |                                           |
      |                                           |
      |                                           |
      |                                           |
  60  +-------------------------------------------+
      |                                           |
      |                                           |
      |                                           |
      | artist                                    |
      |                                           |
      |                                           |
      |                                           |
      |                                           |
  92  +-------------------------------------------|
      |                                           |
      |                                           |
      |                                           |
      | copyright                                 |
      |                                           |
      |                                           |
      |                                           |
      |                                           |
  124 +-------------------------------------------+
      | icount   | scount   | wcount   | system   |
  128 +---------------------+----------+----------+
      | customFramerate     |                     |
      +---------------------+                     |
      |                                           |
      |                                           |
      |                                           |
      | reserved                                  |
      |                                           |
      |                                           |
      |                                           |
      |                                           |
  160 +-------------------------------------------+

Signature

Every trackerboy file begins with this signature:

\0TRACKERBOY\0

in order to identify the file as a trackerboy file.

Version (major, minor, patch)

Version information is stored as three 4-byte words. This information determines which version of trackerboy that created the file. Versioning is maintained by keeping a major and minor version, followed by a patch number. For example, if the trackerboy version is v1.0.2, then the header's version fields will contain 0x1 0x0 and 0x2 for major, minor and patch, respectively.

Major revision (m. rev)

This version number indicates a breaking change for the file format. Starts at 0 and is incremented whenever the layout of the header or payload changes. Trackerboy will not attempt to read modules with a newer major version, but can attempt to read older versions (backwards-compatible).

Examples of breaking changes:

  • Modifying the layout of the Header structure
  • Adding/removing blocks to the payload
  • Modifying the format of a payload block

Minor revision (n. rev)

This version number indicates a change in the format that is forward-compatible with older versions. Changes such as utilizing a reserved field in the header.

Note: Trackerboy can read any module file as long as its major revision is less than or equal to the current revision. Saving always uses the current revision, so saving an older major version is a one-way upgrade.

Author information (title, artist, copyright)

These fields in the header are fixed 32 byte strings. Assume ASCII encoding. Any unused characters in the string should be set to 0 or \0. Since these strings are fixed, null-termination is not needed.

Note: The size and naming of these strings are identical to the ones in *.gbs file format. This is intentional, as exporting to gbs is a planned feature.

icount, scount and wcount

  • icount - instrument count
  • scount - song count
  • wcount - waveform count

These counter fields determine the number of INST, SONG and WAVE blocks present in the payload, respectively. icount and wcount can range from 0-64 and is unbiased. scount can range from 0-255 and is biased (a value of 0 means there is 1 SONG block).

System

The system field determines which Game Boy model this module is for. Since the driver is typically updated every vblank, the system field determines the framerate, tick rate or vblank interval for the driver. The available choices are listed in the following table:

IdentifierValueSystem nameTick rate
systemDmg0DMG59.7 Hz
systemSgb1SGB61.1 Hz
systemCustom2N/Avaries

If the system is systemCustom, then a custom tick rate is used instead of the system's vblank. The custom tick rate is stored in the customFramerate field of the header.

By default the DMG system, systemDmg, is selected.

Payload

The payload is located right after the header (offset 160). It is a variable number of "blocks" or tagged data with a size.

Blocks

A block in the payload contains three parts: the id, the length and the data. The format of the block is shown below:

OffsetSizeDescription
04Id
44Length
8LengthData

Block types

Each block has an identifier, which determines the type of data present in the block. The table below lists all recognized identifiers in the payload.

IdentifierUint32Description
"COMM"0x4D4D4F43User set comment data for a module
"SONG"0x474E4F53Contains a single song
"INST"0x54534E49Contains a single instrument
"WAVE"0x45564157Contains a single waveform

Block ordering

Blocks are stored categorically by type in the following order:

OrderIdentifierCount
1COMM1
2SONG1-256
3INST0-64
4WAVE0-64

COMM block format

The COMM block just contains a UTF-8 string the is the user's comment data. The string is not null-terminated since the length of the string is the length of the block. If the user has no comment set, then this block is empty (length = 0).

SONG block format

The SONG block contains the data for a single song. Songs are stored in the same order as they were in the module's song list. The first song block is song #0 and so on.

Song data is composed of the following, in this order:

  1. Name, as an LString
  2. A SongFormat record
  3. The song order, as an array of OrderRow
  4. The track data, as a sequence of TrackFormat and RowFormat records

INST block format

WAVE block format

Terminator

Following the payload is the terminator, which signifies the end of the file. The terminator is the signature, reversed:

"\0YOBREKCART\0"

There should be no data after this terminator. Any data after the terminator will be ignored.

Revision history

Changes to the file format are listed here, ordered from new to last.

Revision C (1.1)

Introduced in v0.6.0
  • adds a new effect, Jxy, for setting the global volume
  • added specification for instrument/waveform files (*.tbi/*.tbw)

Revision B (1.0)

Introduced in v0.5.0, adds multiple song support.
  • file revision is now a major/minor set of numbers
  • SONG, INST, and WAVE blocks each store a single song, instrument and waveform, respectively.
  • The payload can now contain up to 256 songs
  • Removed the INDX block
  • Removed numberOfInstruments and numberOfWaveforms fields
  • Added scount, icount and wcount fields at offset 124 (replacing the removed numberOf* fields). These fields contain the number of SONG, INST and WAVE blocks present in the payload. Note that only scount is biased (0 => 1).
  • String encoding now specified for all strings. Header strings use ASCII, everything else uses UTF-8.
  • lstring now uses a 2-byte length instead of 1-byte
  • Added a terminator to the format

Revision A (0.0)

First initial version, introduced in v0.2.0.