- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - J 2 B F i l e F o r m a t D o c u m e n t a t i o n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - J2B files are compressed music files intended to be used as background music for the game Jazz Jackrabbit 2. The J2B format is mostly a MUSE container for a compressed module file. The module is stored as several RIFF (Resource Interchange File Format) chunks which is not reminiscent of any other module format. The J2B format is proprietary and no known specification exists. A number of implementations have been written, and converters for converting several module formats into J2B exist. The format is also known as the GAL5 format, named after the Galaxy Audio Engine used by Jazz Jackrabbit 2 to play it. This engine was used by Epic Games in several of their games and was developed by Carlo Vogelsang. This documentation is based on research and code by various others, as well as on comparisons of converted J2B files with their originals, which had a known format such as S3M. See the acknowledgements at the bottom of this file for more details. Every J2B file starts with a header followed by a compressed file. +-----------------------------------------------------------------------------+ | J2B Header | +-----------------------------------------------------------------------------+ Offset | Length | Type | Description 0 4 char File signature, "MUSE" 4 4 dword Magic: DEADBEAF in hex 8 4 dword Filesize 12 4 dword Checksum (?) Possibly CRC32 of compressed data 16 4 dword Length of compressed data 20 4 dword Length of uncompressed data After this comes the compressed GAL5 data, which is compressed with the DEFLATE algorithm. This is the actual file. The GAL5 module is in RIFF format and made up of multiple chunks. All chunks are padded to an even length. The basic structure of the uncompressed GAL5 data is as follows: - RIFF File header - INIT Chunk - Pattern order data - Pattern data for each pattern - Instrument data - RIFF Instrument header - INST Instrument data part - Within each instrument a sample *may* be embedded +-----------------------------------------------------------------------------+ | RIFF Header | +-----------------------------------------------------------------------------+ Offset | Length | Type | Description 0 4 char File signature, "RIFF" 4 4 dword Filesize (does not include the RIFF signature and these four bytes) 8 4 char File tag, "AM " +-----------------------------------------------------------------------------+ | INIT Chunk | +-----------------------------------------------------------------------------+ Next is the INIT chunk, containing track title and other general details. Offset | Length | Type | Description ? 4 char Chunk signature, "INIT" +4 4 dword Chunk length (excluding signature and these 4 bytes) +8 64 char Song title (null-terminated) 72 1 char Flags (see below) 73 1 char Number of channels 74 1 char Initial speed 75 1 char Initial tempo 76 2 word 0x01c5 78 2 word 0xff00 80 1 char 0x80 81 ? char Channel pannings: length is equal to number of channels (one byte per channel) Flags: Value | Setting 00 Use Amiga frequency table 01 Use linear frequency table +-----------------------------------------------------------------------------+ | Pattern order data | +-----------------------------------------------------------------------------+ Following the channel panning is the pattern order data, prefixed with an ORDR signature. Offset | Length | Type | Description ? 4 char Order data signature, "ORDR" +4 4 dword Order data length +8 1 char Amount of patterns +9 ? char Pattern indexes; one byte per index. Total length is equal to the size defined in previous byte ("Amount of patterns") plus one +-----------------------------------------------------------------------------+ | Pattern data | +-----------------------------------------------------------------------------+ Next are the patterns themselves. Each pattern is prefixed with a PATT header containing data lengths and the pattern index. Pattern header: Offset | Length | Type | Description ? 4 char Pattern data signature, "PATT" +4 4 dword Pattern data length (does not include the PATT signature and these four bytes, but does include the rest of the header) +8 1 char Pattern index +9 4 dword Pattern data length (data only) +13 1 char Rows in pattern +14 ? char Pattern data Pattern data: The pattern data is in the following format: first a command, and then any notes that will be used as parameters for that command. The amount of notes a command accepts varies. The following commands are valid: Command | Param | Type | length | 00 - Go to next row 0 - 2x - Read (volume/2) 1 char 4x - Read sample number and note 2 char 6x - Read sample number, note and (volume/2) 3 char 8x - Read effect parameter and effect ID 2 char Ax - Read effect parameter, effect ID and (volume/2) 3 char Cx - Read effect parameter, effect ID, sample number 4 char and note Ex - Read effect parameter, effect ID, sample number, 5 char note and (volume/2) Any command (except 00) applies only to a specific channel. The channel a command applies to is retrieved by adding 1 to the "x" part of the command. So the command "23" would apply to channel 4. "Uneven" command are the same as their even counterparts, except instead of 1 you add 17 to the channel index. So command "33" would apply to channel 20, instead of 4. Notes and effects are stored as follows: Notes | Effects Value | Note Value | Note | Value | Effect 31 C-4 43 F#5 | 01 Portamento Up 32 C#4 44 G-5 | 02 Portamento Down 33 D-4 45 G#5 | 03 Tone Portamento 34 D#4 46 A-5 | 04 Vibrato 35 E-4 47 A#5 | 05 Volume slide + Toneporta 36 F-4 48 B-5 | 06 Volume slide + Vibrato 37 F#4 49 C-6 | 07 Tremolo 38 G-4 4A C#6 | 08 Panning 39 G#4 4B D-6 | 09 Set offset 3A A-4 4C D#6 | 0A Volume slide 3B A#4 4D E-6 | 0B Position jump 3C B-4 4E F-6 | 0D Pattern break 3D C-5 4F F#6 | 0E Multi-effect (like the Sxx IT 3E C#5 50 G-6 | effect) 3F D-5 51 G#6 | 0F Speed 40 D#5 52 A-6 | 14 Tempo 41 E-5 53 A#6 | 42 F-5 54 B-6 | +-----------------------------------------------------------------------------+ | Instrument header | +-----------------------------------------------------------------------------+ Next are the instruments. Instruments can (probably) contain a variable amount of samples. Instruments (seen in a .s3m) are stored as sub-files. Each instrument has a RIFF header with the tag "AI " followed by a INST chunk. The INST chunk then contains *another* RIFF header (*within* the chunk, not as a following chunk) which contains a SAMP chunk. Offset | Length | Type | Description ? 4 char RIFF signature, "RIFF" +4 4 dword Instrument data size (does not include the RIFF signature and these four bytes, but does include the rest of the header) +8 4 char Instrument tag, "AI " +12 4 char Instrument signature, "INST" +16 4 dword Instrument data size (data only) +20 1 char Instrument number +21 28 char Instrument name, null-terminated. +49 290 char? Sample/note map & envelope data +339 2 word Sample length (?) +? ? char Nested RIFF chunk containing nested SAMP chunk (evil!) +-----------------------------------------------------------------------------+ | Sample data | +-----------------------------------------------------------------------------+ Samples are stored as sub-files. Each sample has a RIFF header with the tag "AS " followed by a SAMP chunk. Sample header: Offset | Length | Type | Description ? 4 char RIFF signature, "RIFF" +4 4 dword Sample data size (does not include the RIFF signature and these four bytes, but does include the rest of the header) +8 8 char Sample signature, "AS SAMP" +16 4 dword Sample data size (data only) Sample data: Offset | Length | Type | Description ? 4 char ??? Usually 0x40000000 +4 28 char Sample name, null-terminated +32 4 dword 0x0000 +36 1 char 0x00 +37 1 char Panning (multiply by 2 to get real value) +38 2 word Volume (value+1/512 = real value) +40 2 word Sample flags +42 2 word 0x0080 +44 4 dword Size of wave data +48 4 dword Loop start position +52 4 dword Loop end position +56 4 dword Sample frequency +60 4 char 0x00000000 +64 4 char ??? +68 ? char Sample wave data Sample flags: if (flags & 0x04) m->xxs[i].flg |= WAVE_16_BITS; if (flags & 0x08) m->xxs[i].flg |= WAVE_LOOPING; if (flags & 0x10) m->xxs[i].flg |= WAVE_LOOPING | WAVE_BIDIR_LOOP; if (~flags & 0x80) m->xxs[i].flg |= WAVE_UNSIGNED; +-----------------------------------------------------------------------------+ | Acknowledgements | +-----------------------------------------------------------------------------+ Format description based on: - Dr. Eggman's research http://www.jazz2online.com/J2Ov2/articles/view.php?articleID=288 - Kode54's posts on the Un4Seen Developements forums http://www.un4seen.com/forum/?topic=1927.msg12872#msg12872 - foo_dumb foobar2000 plugin source code, by Kode54 http://kode54.foobar2000.org/foo_dumb_source.zip - xmp source code for their GAL5 player http://xmp.sourceforge.net/ - Original research by authors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - http://mods.jazz2online.com/j2b.txt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -