DSE SMDL Format

From ProjectPokemon Wiki
Revision as of 23:05, 26 September 2015 by Psy commando (talk | contribs) (→‎Example: fixed)
Jump to navigation Jump to search


General Information

The SMDL format is a container for sequenced music. Its very close to the MIDI format, similarly to the SSEQ format normally used in most NDS games.

File Structure

Overview

Offset Length Name Description
0x0 64 SMDLHeader The container's header.
0x40 64 Song Chunk Information on the entire sequence.
After Song Chunk Varies Trk Chunk The first Track of the sequence. Its role is to set the tempo.
..Additional tracks here..
After all Track Chunks 16 End of Content Chunk This empty chunk marks the end of the SMDL container.

SMDL Header


Total length 64 bytes
Offset Length Type Name Description
0x00 4 char[4] magicn The 4 characters "smdl" {0x73,0x6D,0x64,0x6C}
0x04 4 - unk7 4 bytes of zeroes.
0x08 4 uint32 flen File length in bytes.
0x0C 2 uint16 version? Version number? ( 0x1504 )
0x0E 1 uint8 unk1 Unknown.
0x0F 1 uint8 unk2 Unknown.
0x10 4 - unk3 4 bytes of zeroes.
0x14 4 - unk4 4 bytes of zeroes.
0x18 2 uint16 year Year the file was last modified.
0x1A 1 uint8 month Month the file was last modified.
0x1B 1 uint8 day Day the file was last modified.
0x1C 1 uint8 hour Hour the file was last modified.
0x1D 1 uint8 minute Minute the file was last modified.
0x1E 1 uint8 second Second the file was last modified.
0x1F 1 uint8 centisecond? Could possibly be the centisecond that the file was last modified.
0x20 16 char[16] fname Filename, ASCII null terminated string. Any extra space after the 0 on the total 16 bytes, is padded with 0xAA.
0x30 4 uint32 unk5 Unknown, usually 0x1.
0x34 4 uint32 unk6 Unknown, usually 0x1.
0x38 4 uint32 unk8 Unknown, usually 0xFFFFFFFF.
0x3C 4 uint32 unk9 Unknown, usually 0xFFFFFFFF.

Song Chunk


The song chunk is made of a single header.

Song Chunk Header ( Total length 64 bytes )
Offset Length Type Name Description
0x00 4 char[4] label Song chunk label "song" {0x73,0x6F,0x6E,0x67}
0x04 4 uint32 unk1 Unknown. Usually 0x1.
0x08 4 uint32 unk2 Unknown. Usually 0xFF10.
0x0C 4 uint32 unk3 Unknown. Usually 0xFFFFFFB0.
0x10 2 uint16 unk4 Unknown. Usually 0x1.
0x12 2 uint16 tpqn Ticks Per Quarter Note. Usually 0x30 or 48 ticks per quarter note. (Works like MIDI clock ticks it seems.)
0x14 2 uint16 unk5 Unknown. Usually 0xFF01
0x16 1 uint8 nbtrks Number of track(trk) chunks
0x17 1 uint8 nbchans Number of channels. (Unsure how channels works with DSE)
0x18 4 uint32 unk6 Unknown. Usually 0x0F000000
0x1C 4 uint32 unk7 Unknown. Usually 0xFFFFFFFF
0x20 4 uint32 unk8 Unknown. Usually 0x40000000
0x24 4 uint32 unk9 Unknown. Usually 0x00404000
0x28 2 uint16 unk10 Unknown. Usually 0x0200
0x2A 2 uint16 unk11 Unknown. Usually 0x0800
0x2C 4 uint21 unk12 Unknown. Usually 0xFFFFFF00
0x30 16 - unkpad Unknown sequence of 16, 0xFF bytes. Possibly padding?

Trk Chunk


Track chunks contain the events for each individual tracks of the music sequence. They work much like MIDI tracks.

Header

Offset Length Type Name Description
0x00 4 char[4] label Track chunk label "trk\0x20" {0x74,0x72,0x6B,0x20}
0x04 4 uint32 param1 Unknown. Usually 0x01000000.
0x08 4 uint32 param2 Unknown. Usually 0x0000FF04.
0x0C 4 uint32 chunklen Length of the trk chunk. Starting after this field, to the first 0x98 event encountered in the track. The length is in bytes.
The content begins immediately after the header!

Preamble

Each tracks has a short preamble after the header, and before the actual events. That preamble indicates the channel and the track id assigned to the track.
Offset Length Type Name Description
0x00 1 uint8 trkid The track ID of the track. A number between 0 and 0x11.
0x01 1 uint8 chanid The channel ID of the track. A number between 0 and 0x0F?.
0x02 1 uint8 unk1 Unknown. Often 0.
0x03 1 uint8 unk2 Unknown. Often 0.

Events

All tracks must have a 0x98 event at their end. And the size of a track is counted up to that event, ignoring the padding bytes. Events themselves are not aligned on 4 bytes.
Offset Length Type Name Description
After Preamble varies - events Track events begin here.
After Events 0-3 - Padding Padding to align the end of the track on 4 bytes. The value is usually the terminating 0x98 byte repeated as needed, up to 3 extra times.
Example

Here's an example "Events" section (it does not include the preamble and header):

 E3 73 A4 82 93 E0 1F 98 

It ends on an offset divisible by 4, so there is only a single 0x98 event at the end.

Here's what would happen if we'd add an extra events. Lets copy the 0xE3 event and its parameter once:

 E3 73 E3 73 A4 82 93 E0 1F 98 98 98

..we needed to add 2 extra 0x98 events to make the track end on an offset divisible by 4!

Eoc Chunk


Total length 16 bytes
Offset Length Type Name Description
0x0 4 - ChunkID The chunk ID "eoc\0x20" {0x65, 0x6F, 0x63, 0x20}
0x4 4 uint32 Param1 Unknown meaning, is often 0x00000001.
0x8 4 uint32 Param2 Unknown meaning, is often 0x04FF0000.
0xC 4 uint32 Length Always 0, for end of content chunks.

DSE Events

Tracks are filled with event codes, which indicates to the sequencer what to do.

  • Their value ranges from 0x0 to 0xFF.
  • Events from 0x0 to 0x7F are reserved for the PlayNote event.
  • Events from 0x80 to 0x8F are reserved for fixed duration pause events.
  • Events from 0x90 to 0xFF all have their unique meaning.

PlayNote(0x0 to 0x7F)

The play note event is special in that its format is particular.

  • The event code itself is the velocity(0x0 - 0x7F) of the note to be played.
  • The first parameter byte is obligatory, and it contains info on whether we modify the track's current octave, how many extra parameters are there, and what note to play.
  • The second parameter is optional, and its length varies depending on the length specified in the obligatory parameter. It contains the duration the key is "held down" before being released.

Here's a breakdown of the NoteData byte:

Bits Name Meaning
1100 0000 OctaveMod A value from 0 to 3 from which 2 is subtracted. The result is a signed value that we add to the track's current octave.
0011 0000 NbParamBytes A value from 0 to 3 which indicates the amount of extra parameter bytes that should be read.
0000 1111 Note The Note that should be played at the track's current octave(after OctaveMod).

Note List

Value Note Name
0x0 C
0x1 C#
0x2 D
0x3 D#
0x4 E
0x5 F
0x6 F#
0x7 G
0x8 G#
0x9 A
0xA A#
0xB B
0xF Unknown

Example Event

Velocity NoteData (Opt)KeyDownDuration
0x7F 0x65 0x20 0x01 0x10

This event will play the note F, at the current track octave with no modifications, and hold the note for 0x100120 ticks.


Fixed Duration Pause(0x80 to 0x8F)

The fixed duration pause is a pause event based on the duration of common musical time intervals. Its event code goes from 0x80-0x8F.

Here's a table of the possible durations:

Code Musical Time Interval Duration in Ticks
0x80 Half Note 96
0x81 Dotted Quarter Note 72
0x82 2/3 of a Half Note (Half Note as part of a triplet?) 64
0x83 Quarter Note 48
0x84 Dotted 8th Note 36
0x85 2/3 of a Quarter Note (Quarter Note as part of a triplet?) 32
0x86 8th Note 24
0x87 Dotted 16th Note 18
0x88 2/3 of a 8th Note (8th Note as part of a triplet?) 16
0x89 16th Note 12
0x8A Dotted 32nd Note 9
0x8B 2/3 of a 16th Note (16th Note as part of a triplet?) 8
0x8C 32nd Note 6
0x8D Dotted 64th Note 4
0x8E 2/3 of a 32nd Note (32th Note as part of a triplet?) 3
0x8F 64th Note 2

Others(0x90 to 0xFF)

Here is a list of all known events :

Code Parameter Length Parameters Name Description
0x90 0 - RepeatLastPause Pause the track processing for the duration of the last pause.(Includes fixed duration pauses)
0x91 1 (uint8)Duration AddToLastPause Pause the track processing for the duration of the last pause + the duration in ticks specified.(Includes fixed duration pauses)
0x92 1 (uint8)Duration Pause8Bits Pause the track processing for the duration in ticks.
0x93 2 (uint16)Duration Pause16Bits Pause the track processing for the duration in ticks.
0x94 3 (uint24)Duration Pause24Bits Pause the track processing for the duration in ticks.
0x95 1 (uint8)CheckInterval PauseUntilRelease Pause the track processing as long as a note is held down. Will wait for at least "CheckInterval" ticks, then checks every "CheckInterval" ticks if all notes have been released on the current track.
0x96 0 - INVALID Disable current track.
0x97 0 - INVALID Disable current track.
0x98 0 - EndOfTrack Marks the end of the track. Is also used as padding to align the end of the track on 4 bytes.
0x99 0 - LoopPoint Marks the point the track will loop to after the end of track is reached.
0x9A 0 - INVALID Disable current track.
0x9B 0 - INVALID Disable current track.
0x9C 1 ?? ?? ??
0x9D 0 ?? ?? ??
0x9E 0 ?? ?? ??
0x9F 0 - INVALID Disable current track.
0xA0 1 (uint8)Octave SetTrackOctave Sets the current track's octave to the value specified. Valid range is 0 - 9.
0xA1 1 (uint8)Octave AddToTrackOctave Adds the value specified to the current track octave.
0xA2 0 - INVALID Disable current track.
0xA3 0 - INVALID Disable current track.
0xA4 1 (uint8)TempoBPM SetTempo Sets the track's tempo in beats per minute.
0xA5 1 (uint8)TempoBPM SetTempo Sets the track's tempo in beats per minute? (The code is identical to 0xA4)
0xA6 0 - INVALID Disable current track.
0xA7 0 - INVALID Disable current track.
0xA8 2 ?? ?? ??
0xA9 1 ?? ?? ??
0xAA 1 ?? ?? ??
0xAB 0 - SkipNextByte Skips processing the next byte.
0xAC 1 (uint8)ProgramID SetProgram Change the track's program(Instrument Preset) to the one specified.
0xAD 0 - INVALID Disable current track.
0xAE 0 - INVALID Disable current track.
0xAF 3 ?? ?? ??
0xB0 0 ?? ?? ??
0xB1 1 ?? ?? ??
0xB2 1 ?? ?? ??
0xB3 1 ?? ?? ??
0xB4 2 ?? ?? ??
0xB5 1 ?? ?? ??
0xB6 1 ?? ?? ??
0xB7 0 - INVALID Disable current track.
0xB8 0 - INVALID Disable current track.
0xB9 0 - INVALID Disable current track.
0xBA 0 - INVALID Disable current track.
0xBB 0 - INVALID Disable current track.
0xBC 1 ?? ?? ??
0xBD 0 - INVALID Disable current track.
0xBE 1 ?? ?? ??
0xBF 1 ?? ?? ??
0xC0 1 ?? ?? ??
0xC1 0 - INVALID Disable current track.
0xC2 0 - INVALID Disable current track.
0xC3 1 ?? ?? ??
0xC4 0 - INVALID Disable current track.
0xC5 0 - INVALID Disable current track.
0xC6 0 - INVALID Disable current track.
0xC7 0 - INVALID Disable current track.
0xC8 0 - INVALID Disable current track.
0xC9 0 - INVALID Disable current track.
0xCA 0 - INVALID Disable current track.
0xCB 2 - SkipNext2Bytes Skip processing the next 2 bytes.
0xCC 0 - INVALID Disable current track.
0xCD 0 - INVALID Disable current track.
0xCE 0 - INVALID Disable current track.
0xCF 0 - INVALID Disable current track.
0xD0 1 ?? ?? ??
0xD1 1 ?? ?? ??
0xD2 1 ?? ?? ??
0xD3 2 ?? ?? ??
0xD4 3 ?? ?? ??
0xD5 2 ?? ?? ??
0xD6 2 ?? ?? ??
0xD7 2 (uint16)Bend PitchBend Bend the pitch of the note.
0xD8 2 ?? ?? ??
0xD9 0 - INVALID Disable current track.
0xDA 0 - INVALID Disable current track.
0xDB 1 ?? ?? ??
0xDC 5 ?? ?? ??
0xDD 4 ?? ?? ??
0xDE 0 - INVALID Disable current track.
0xDF 1 ?? ?? ??
0xE0 1 (int8)TrackVolume SetTrackVolume Change the track's volume to the value specified. (0x0-0x7F)
0xE1 1 ?? ?? ??
0xE2 3 ?? ?? ??
0xE3 1 (int8)TrackExpression SetTrackExpression Change the track's expression(secondary volume) to the value specified. (0x0-0x7F)
0xE4 5 ?? ?? ??
0xE5 4 ?? ?? ??
0xE6 0 - INVALID Disable current track.
0xE7 1 ?? ?? ??
0xE8 1 (int8)Pan SetTrackPan Change the track's pan to the value specified. (0x0-0x7F. 0x40 is middle, 0x0 full left, and 0x7F full right )
0xE9 1 ?? ?? ??
0xEA 3 ?? ?? ??
0xEB 0 - INVALID Disable current track.
0xEC 5 ?? ?? ??
0xED 4 ?? ?? ??
0xEE 0 - INVALID Disable current track.
0xEF 1 ?? ?? ??
0xF0 5 ?? ?? ??
0xF1 4 ?? ?? ??
0xF2 2 ?? ?? ??
0xF3 3 ?? ?? ??
0xF4 0 - INVALID Disable current track.
0xF5 0 - INVALID Disable current track.
0xF6 1 ?? ?? ??
0xF7 0 - INVALID Disable current track.
0xF8 2 ?? ?? ??
0xF9 0 - INVALID Disable current track.
0xFA 0 - INVALID Disable current track.
0xFB 0 - INVALID Disable current track.
0xFC 0 - INVALID Disable current track.
0xFD 0 - INVALID Disable current track.
0xFE 0 - INVALID Disable current track.
0xFF 0 - INVALID Disable current track.

Credits

  • TruePikachu for some of the details on the SMDL format! [1]