SMD_Format
SMD Header
| Offset | Type | Name | Description |
|---|---|---|---|
0x00 |
char[4] |
MagicNumber | SMD file magic number "smdl"
|
0x04 |
DWORD | Null | |
0x08 |
uint32_t |
FileSize | Total file size (including this header) |
0x0C |
WORD | Version number??? | |
0x0E |
uint8_t |
InstrumentGroup | Instrument group ID. Link exists to UNK_AA command. |
0x0F |
uint8_t |
Unknown, maybe indicates the type of sequence? Link exists to UNK_A9 command. | |
0x10 |
QWORD | Null | |
0x18 |
QWORD | Bitfield? | |
0x20 |
char[16] |
FileName | Internal filename |
0x30 |
DWORD | Unknown, almost always 0x00000001
|
|
0x34 |
DWORD | Unknown, almost always 0x00000001
|
|
0x38 |
PAD |
0xFF pad to align on 0x10
|
|
sizeof=0x40 |
Song Header
| Offset | Type | Name | Description |
|---|---|---|---|
0x00 |
char[4] |
MagicNumber | Song chunk magic number "song"
|
0x04 |
DWORD |
0x00000001? |
|
0x08 |
DWORD |
0x10FF0000? |
|
0x0C |
DWORD |
0xB0FFFFFF? |
|
0x10 |
DWORD |
0x01003000? |
|
0x14 |
WORD |
0x01FF? |
|
0x16 |
uint8_t |
TrackChunkCount | Number of track chunks after the song header |
0x17 |
uint8_t |
OutChannelCount | Number of output channels? |
0x18 |
QWORD |
0x0000000FFFFFFFFF? |
|
0x20 |
DWORD |
0x00000040? |
|
0x24 |
DWORD |
0x00404000? |
|
0x28 |
DWORD |
0x00020008? |
|
0x2C |
DWORD |
0x00FFFFFF? |
|
0x30 |
PAD |
0xFF pad to align on 0x20
|
|
sizeof=0x40 |
Track Chunk
| Offset | Type | Name | Description |
|---|---|---|---|
0x00 |
char[4] |
MagicNumber | Track chunk magic number "trk "
|
0x04 |
DWORD |
0x00000001? |
|
0x08 |
DWORD |
0x04FF0000? |
|
0x0C |
uint32_t |
TrackDataSize | Size of track data, after this field |
0x10 |
uint8_t |
TrackID | Track ID number, zero indexed |
0x11 |
uint8_t |
OutputID | Output ID number, zero indexed |
0x12 |
WORD |
0x0000? |
|
0x14 |
EVENTS | See below | |
| ???? | PAD |
0x98 pad to aling on 0x4
|
Track Events
A track is composed of a series of events, which is composed of a stream of bytes parsed by the playback engine.
NOTE_PLAY
Opcode: 0x00..0x7F
This command plays a note. There are four different forms of the command:
| Form | OPCODE | OP+1 | OP+2 | OP+3 | OP+4 |
|---|---|---|---|---|---|
| 2-byte | Velocity | KeyFlag | |||
| 3-byte | Velocity | KeyFlag | Length | ||
| 4-byte | Velocity | KeyFlag | LengthMSB | LengthLSB | |
| 5-byte | Velocity | KeyFlag | LengthMSB | LengthMidB | LengthLSB |
The Velocity parameter, which ranges from 0x00..0x7F, is the opcode itself.
KeyFlag indicates flags to use, and the key the note applies to
KeyFlag & 0xC0 |
Meaning |
|---|---|
0x00 |
Use the length of the previous note (2-byte form) |
0x40 |
Use the provided length (3-byte form) |
0x80 |
Use the provided length (4-byte form) |
0xC0 |
Use the provided length (5-byte form) |
KeyFlag & 0x30 |
Meaning |
|---|---|
0x00 |
Go down 2 octaves |
0x10 |
Go down 1 octave |
0x20 |
Don't change octave |
0x30 |
Go up 1 octave |
KeyFlag & 0x0F |
Meaning |
|---|---|
0x00 |
C |
0x01 |
C# |
0x02 |
D |
0x03 |
D# |
0x04 |
E |
0x05 |
F |
0x06 |
F# |
0x07 |
G |
0x08 |
G# |
0x09 |
A |
0x0A |
A# |
0x0B |
B |
0x0C |
C, +1 Oct, * |
0x0D |
C#, +1 Oct, * |
0x0E |
D, +1 Oct, * |
0x0F |
D#, +1 Oct, * |
*) These usually do not occur but they technically work. These "higher keys" don't affect the octave to use for new notes.
The Length parameter (optional) specifies the length of time the note should play for, in 1/48 beat ticks. It can be specified in either one or two bytes
DELTA_TIME
Opcode: 0x80..0x8F
This command waits for a specific amount of time, as indicated by the opcode byte:
| OPCODE | Delay (ticks) | Musical |
|---|---|---|
80 |
96 | 1/2 note |
81 |
72 | 1/4 dotted |
82 |
64 | 1/2 triplet |
83 |
48 | 1/4 note |
84 |
36 | 1/8 dotted |
85 |
32 | 1/4 triplet |
86 |
24 | 1/8 note |
87 |
18 | 1/16 dotted |
88 |
16 | 1/8 triplet |
89 |
12 | 1/16 note |
8A |
9 | 1/32 dotted |
8B |
8 | 1/16 triplet |
8C |
6 | 1/32 note |
8D |
4 | 1/32 triplet |
8E |
3 | 1/64 note |
8F |
2 | 1/64 triplet |
WAIT_AGAIN
Opcode: 0x90
This command waits for the amount of time the previous WAIT_AGIAN, WAIT_ADD, WAIT_1BYTE, or WAIT_2BYTE command did.
WAIT_ADD
Opcode: 0x91 ss
This command is just like WAIT_AGAIN, but it takes a signed int8_t as a parameter, adds (or subtracts) that to the previous wait length, and waits for that amount of time.
WAIT_1BYTE
Opcode: 0x92 uu
Waits for the amount of time specified by the single-byte parameter.
WAIT_2BYTE
Opcode: 0x93 ll hh
Waits for the amount of time specified by the two-byte parameter. The LSB is first, followed by the MSB.
TRACK_END
Opcode: 0x98
Marks the end of a track. Useful as an indicator to jump to the LOOP_POINT. Ends the playback if no LOOP_POINT was previously set. Is to be set for all tracks individually.
LOOP_POINT
Opcode: 0x99
Marks the loop point of a track. Absent if the track will not loop.
SET_OCTAVE
Opcode: 0xA0 uu
Selects the octave to use. MIDI key 0 is C in octave 0.
SET_TEMPO
Opcode: 0xA4 uu
Sets the tempo. This is in BPM; there are 48 ticks per beat.
SET_SAMPLE
Opcode: 0xAC uu
Sets the instrument to use. The actual instrument is based off the file's instrument group setting.
SET_MODU
Opcode: 0xBE uu
Sets the modulation parameter. 0x00..0x7F
SET_BEND
Opcode: 0xD7 sh sl
Dynamically adjusts the tuning of the track. Two-byte signed parameter indicating the setting in cents.
SET_VOLUME
Opcode: 0xE0 uu
Changes the volume of the track. Ranges from 0x00..0x7F.
SET_XPRESS
Opcode: 0xE3 uu
Changes the expression of the track. Ranges from 0x00..0x7F.
SET_PAN
Opcode: 0xE8 uu
Sets the track panning. Ranges from 0x00..0x7F, where 0x00 is full left, 0x40 is center, and 0x7F is full right.
Table of Opcodes
Here is a list of discovered opcodes. Opcodes which don't have a known purpose are referred to as "UNK_xx", where xx is the specifier.
| Opcode | Add Bytes | Name |
|---|---|---|
0x00..0x7F
|
1-3 | NOTE_PLAY |
0x80..0x8F
|
0 | DELTA_TIME |
0x90 |
0 | WAIT_AGAIN |
0x91 |
1 | WAIT_ADD |
0x92 |
1 | WAIT_1BYTE |
0x93 |
2 | WAIT_2BYTE |
0x98 |
0 | TRACK_END |
0x99 |
0 | LOOP_POINT |
0x9C |
1 | UNK_9C |
0x9D |
0 | UNK_9D |
0xA0 |
1 | SET_OCTAVE |
0xA4 |
1 | SET_TEMPO |
0xA8 |
2 | UNK_A8 |
0xA9 |
1 | UNK_A9 |
0xAA |
1 | UNK_AA |
0xAC |
1 | SET_SAMPLE |
0xB2 |
1 | UNK_B2 |
0xB4 |
2 | UNK_B4 |
0xB5 |
1 | UNK_B5 |
0xBE |
1 | SET_MODU |
0xBF |
1 | UNK_BF |
0xC0 |
0 | UNK_C0 |
0xD0 |
1 | UNK_D0 |
0xD1 |
1 | UNK_D1 |
0xD2 |
1 | UNK_D2 |
0xD4 |
3 | UNK_D4 |
0xD6 |
2 | UNK_D6 |
0xD7 |
2 | SET_BEND |
0xDB |
1 | UNK_DB |
0xDC |
5 | UNK_DC |
0xE0 |
1 | SET_VOLUME |
0xE2 |
3 | UNK_E2 |
0xE3 |
1 | SET_XPRESS |
0xE8 |
1 | SET_PAN |
0xEA |
3 | UNK_EA |
0xF6 |
2 | UNK_F6 |