🎄 Merry Christmas, TCRF! 🎄
Format:Krawall
The Krawall sound engine is an XM/S3M module player/tracker for the Game Boy Advance. Written by Sebastian Kienzl, it was used in various licensed games, such as The Lord of the Rings, Spider-Man, and The Sims.[1] Since 2013, the source code for the engine has been available on GitHub.[2] Krawall can be used to play background music in a game, as well as to play tracked single-activation jingles. The data is stored in the ROM as a set of samples, an optional set of instruments (depending on whether it's using S3M or XM modules), and one or more modules, with up to 256 patterns per module.
Contents
Signature
Most ROMs with Krawall have a signature somewhere in the file that declares the presence of Krawall as well as the version. (Some retail ROMs have this stripped out. The Sims Bustin' Out is one example, though interestingly the Japanese release still has the signature.) The signature will likely look similar to the following in ASCII form:
$Id: Krawall $Id: version.h 8 2005-04-21 12:24:45Z seb $
Depending on the version, it may also be in a different format:
$Id: Krawall $Date: 2003/09/01 06:51:01 $
The first form of the string identifies the engine name (Krawall), the file the string came from, the build date of the version, and the creator ("seb", short for Sebastian Kienzl). The second form identifies just the engine name and build date.
This signature is a surefire way to detect the presence of Krawall in a ROM. If it is not present, you may need to use a more heuristic scan on the ROM to check for modules/samples. You can also look for seb's name in the credits.
Versions
There have been various versions of Krawall since its initial release. The most recent version is 2005-04-21. The most important change that was made to the format was in version 2004-07-07, when the patterns were modified to allow more than 512 instruments and 255 rows. Make sure you know which version of Krawall is used by the ROM before ripping, as the two pattern formats are incompatible. Look for the signature in the ROM if present to find the version.
Known Versions
- 2003-09-01
- 2004-07-07
- 2004-09-17
- 2004-11-14
- 2005-04-21
Data Format
Krawall stores its data in multiple places. Samples for all modules are stored in a single bank, as well as a separate bank for instruments if present. Both banks are indexed using a central array of pointers. Modules are stored individually, with pointers to each pattern at the end. Most of the data stored in each structure is analogous to a property in the comparable XM or S3M structure, so this makes conversion between the two/three formats easy.
All properties are stored in little-endian format. Pointers are stored as they would be addressed on the GBA, with a base address of 08000000. When converting down to ROM offsets, make sure to bitwise AND any pointers with 01FFFFFF. When converting up from ROM offsets, bitwise OR the offset with 08000000.
Samples
Samples are stored as signed 8-bit PCM data, with an 18-byte header with a few properties relating to looping and frequency.
Offset | Size (bytes) | Source Name | Description |
---|---|---|---|
00 | 4 | loopLength |
The length of the loop region. The start of the loop can be determined with (size - loopLength ), and the end of the loop is always the end of the sample (size ).
|
04 | 4 | end |
A pointer to the end of the data. The size of the data can be determined by subtracting the position of the start of the data from this pointer (AND 01ffffff). |
08 | 4 | c2freq |
The frequency for middle C (used for S3M), in Hertz. |
0C | 1 | fineTune |
The finetune value for the sample (used for XM), as a signed integer. |
0D | 1 | relativeNote |
The relative note for the sample (used for XM), as a signed integer. |
0E | 1 | volDefault |
The default volume for the sample. |
0F | 1 | panDefault |
The default pan position for the sample. |
10 | 1 | loop |
A boolean value determining whether the sample should loop. If set, once sample playback reaches the end it will loop back to (size - loopLength ) samples.
|
11 | 1 | hq |
A boolean value telling Krawall whether to play back the sample with interpolation (0 = no interpolation, 1 = linear? interpolation). |
12 | (size ) |
data[] |
The actual sample data, as signed 8-bit PCM. |
Pointers to all samples for a ROM are stored in a central pointer array. The index of each sample in this array is used for instrument sample assignments (in XM) or instrument selection in patterns (in S3M).
You can easily find samples in a ROM by opening it as raw data in Audacity or other program with signed (or unsigned if unavailable) 8-bit mono PCM at 16384 Hz. Look for the first sample of a region that appears to be audio, and backtrack 18 samples before that. Then seek to the position in the file equal to the sample position that you just got. This should be the beginning of a sample structure. Verify that the size property is valid, and if so you've now got a sample structure.
Once you have the position of a sample structure, it should be trivial to find the master sample table. Just search the ROM for the offset of the start of the sample structure (bitwise OR'ed with 08000000) as a little-endian 32-bit integer, and you should be able to find the rest of the table.
Instruments
Instruments are used for modules converted from XM format. They can use multiple samples for different pitches to avoid distortion when playing a note that is much higher than the original sample. They also store volume and panning envelope information, as well as vibrato types. Instrument structures are always exactly 302 bytes in size. Some modules may not use instruments - check the flagInstrumentBased
flag in each module to see whether instruments are required. Typically, modules converted from XM have instruments, while modules converted from S3M do not.
Offset | Size (bytes) | Source Name | Description |
---|---|---|---|
000 | 192 (2[96]) | samples[96] |
An array of 96 unsigned 16-bit integers denoting which notes use which samples. Index 0 = C0, 1 = D0, ..., 95 = A#7. The value denotes the index of the sample in the master sample table. |
0C0 | 52 (Envelope) | envVol |
An Envelope structure containing the volume envelope. (See below for the format of the Envelope structure.) |
0F4 | 52 (Envelope) | envPan |
An Envelope structure containing the panning envelope. (See below for the format of the Envelope structure.) |
128 | 2 | volFade |
Volume fade out value. |
12A | 1 | vibType |
The type of vibrato used for the instrument. This should be the same as the XM vibrato type field. |
12B | 1 | vibSweep |
The number of ticks to reach full vibrato speed. |
12C | 1 | vibDepth |
The depth of the vibrato in 1/64ths of a semitone. |
12D | 1 | vibRate |
The speed to play the vibrato at. |
Offset | Size (bytes) | Source Name | Description |
---|---|---|---|
00 | 48 (4[12]) | nodes[12] |
The nodes in the envelope. This is packed as an array of 12 pairs of two unsigned 16-bit integers. The first integer (coord ) stores the X and Y position of the node. The X position is in the 9 least significant bits, while the Y position is in the 7 most significant bits. The second integer (inc ) is used internally as the amount to add each tick to reach the next node (essentially a slope). This is not necessary when ripping, but if you are modifying an instrument's envelope you'll want to recalculate the inc field accordingly.
|
30 | 1 | max |
The index of the final node (NOT the number of nodes). Add one to get the total number of nodes. |
31 | 1 | sus |
The node where the instrument will sustain until fadeout. |
32 | 1 | loopStart |
The node to restart at if the envelope finishes. |
33 | 1 | flags |
A bitfield with some flags determining behavior of the envelope. 2: sustain the envelope at sus . 4: loop the envelope at the end, restarting from loopStart .
|
As with the sample structures, pointers to all instruments are kept in a central array to be referenced by the game/Krawall. The indices of the instruments in the array are used when playing back patterns.
Most of the data in the instrument structure is analogous to the XM format's instrument structure's fields. This is likely because instruments are only available when converting from the XM format, so it can stay the same for the most part. However, some semi-redundant data (like envelope loop end) was removed to save space.
Modules
Modules store the metadata for each song. They contain the same sort of information as would be found at the top of an XM/S3M module file. Since Krawall handles both XM and S3M modules, there are some fields that are only useful for one of the formats and not the other. These will be noted in the table below.
Offset | Size (bytes) | Source Name | XM/S3M | Description |
---|---|---|---|---|
000 | 1 | channels |
XM/S3M | The number of audio channels in the module. |
001 | 1 | numOrders |
XM/S3M | The number of patterns in the order table. This is not necessarily equal to the total number of patterns!
|
002 | 1 | songRestart |
XM | The position in the module to restart at. |
003 | 256 (1[256]) | order[256] |
XM/S3M | The order of patterns in the module. Each value refers to the index of a pattern in patterns . A value of 254 tells Krawall to call a user-defined callback function.
|
103 | 32 (1[32]) | channelPan[32] |
S3M | Initial panning positions for each channel (up to 32), as signed 8-bit integers. |
123 | 64 (1[64]) | songIndex[64] |
N/A | Holds the indices of start positions for modules with multiple songs. |
163 | 1 | volGlobal |
XM/S3M | Default volume for the module. |
164 | 1 | initSpeed |
XM/S3M | The default speed (ticks/beat) for the module. |
165 | 1 | initBPM |
XM/S3M | The default tempo (beats/minute) for the module. |
166 | 1 | flagInstrumentBased |
N/A | Determines whether the module uses instruments (1) or not (0). S3M modules always set 0, and XM modules usually set 1. |
167 | 1 | flagLinearSlides |
XM | Determines whether the module uses linear frequency slides (1) or Amiga frequency slides (0). |
168 | 1 | flagVolSlides |
S3M | Determines whether the module uses ScreamTracker 3.00 volume slides (1) or not (0). When set to 1, play volume slides on the first tick as well as the others; when cleared to 0, don't play slides on the first tick. |
169 | 1 | flagVolOpt |
S3M | Determines whether the module uses volume optimization (1) or not (0). If set and the volume on a channel is 0 for more than two rows, the channel is stopped. |
16A | 1 | flagAmigaLimits |
S3M | Determines whether the module uses Amiga frequency limits (1) or not (0). If set, any note that goes beyond Amiga hardware limits is illegal. |
16B | 1 | __padding |
N/A | Unused. Pads pattern pointers to 4-byte offsets. |
16C | * | patterns[] |
XM/S3M | The pointers to each pattern used by the module. The size of this array is determined by the largest index in the order array: if the largest value was 7, there would be 8 entries in this array. Make sure to ignore 254, as noted above.
|
Modules are directly referenced by the code, and thus do not have any sort of central pointer list. To find the offsets, you will need to either search the code regions for pointers to the module, or you can look for a block of data that roughly matches the format of the structure. One key characteristic is that there are often large regions of zero bytes in the order
and songIndex
arrays. You can try to search for these zero regions to find possible modules.
Patterns
Patterns store the actual notes used in a module. They can be reused and rearranged in a module as needed. Patterns are split into a certain number of rows, which are played back at a set speed. There are two versions of the pattern format with some minor variations, so you'll need to make sure you're using the correct version before reading patterns. A pattern consists of some tracking indices, the number of rows, and packed pattern data.
Offset | Size (bytes) | Source Name | Description |
---|---|---|---|
00 | 32 (2[16]) | index[16] |
The offsets of the first 64 rows inside data . Only every fourth row is stored in here. For example, to find the offset of the 21st row (14), check index[5] . This is likely used for seeking in a pattern.
|
20 | 2 | rows |
The number of rows in the pattern. As of version 2004-07-07, this field is 16 bits wide. |
22 | * | data[] |
The packed pattern data. |
Offset | Size (bytes) | Source Name | Description |
---|---|---|---|
00 | 32 (2[16]) | index[16] |
The offsets of the first 64 rows inside data . Only every fourth row is stored in here. For example, to find the offset of the 21st row (14), check index[5] . This is likely used for seeking in a pattern.
|
20 | 1 | rows |
The number of rows in the pattern. Before version 2004-07-07, this field was 8 bits wide. |
21 | * | data[] |
The packed pattern data. |
The format of the packed data is very similar to S3M's packed data format. Each row is encoded as a list of note entries, with an initial channel/follow byte, followed by the data being set on the channel. A row can consist of zero or more entries with the most significant three bits denoting what's being set, and the least significant 5 bits denoting the channel. If the follow byte is 0, the row is finished and the next row is starting.
To decode the packed data:
- Read a byte from the data
- If the byte is 0, increment the row and restart the loop (if the row ==
rows
, we're done) - If bit 5 is set (20): read two bytes for the note and instrument
- If the version is >= 2004-07-07, the first byte is the note, and the second byte is the least significant byte of the instrument
- If the high bit is set on the note, unset it and read in another byte for the most significant byte of the instrument
- If the version is < 2004-07-07, the high 9 bits are the instrument, and the low 7 bits are the note
- If the version is >= 2004-07-07, the first byte is the note, and the second byte is the least significant byte of the instrument
- If bit 6 is set (40): read 1 byte for the volume (in XM volume column format, 10-50 for volume maps to 00-40 actual volume)
- If bit 7 is set (80): read 2 bytes for the effect and effect parameter (listed below)
- Write the data to the channel at the low 5 bits of the first byte (
follow & 0x1F
) - Repeat from the top
Effects
These are the effects available in Krawall, as well as mappings to XM and S3M effects.
ID | XM equivalent | S3M equivalent | Description |
---|---|---|---|
0 | - | - | None |
1 | Fxx | Axx | Speed |
2 | Fxx | Txx | Tempo |
3 | Fxx | - | Speed/Tempo |
4 | Bxx | Bxx | Pattern Jump |
5 | Dxx | Cxx | Pattern Break |
6 | Axy1 | Dxy | Volume Slide (S3M) |
7 | Axy | Dxy1 | Volume Slide (XM) |
8 | EBx | DFx | Fine Volume Slide |
9 | EAx | DxF | Extra Fine Volume Slide |
10 | 2xx | Exx1 | Portamento Down (XM) |
11 | 2xx1 | Exx | Portamento Down (S3M) |
12 | E2x | EFx | Fine Portamento Down |
13 | X2x | ExF | Extra Fine Portamento Down |
14 | 1xx | Fxx1 | Portamento Up (XM) |
15 | 1xx1 | Fxx | Portamento Up (S3M) |
16 | E1x | FFx | Fine Portamento Up |
17 | X1x | FEx | Extra Fine Portamento Up |
18 | Cxx | - | Note Volume |
19 | 3xx | Gxx | Note Portamento |
20 | 4xy | Hxy | Vibrato |
21 | Txy | Ixy | Tremor |
22 | 0xx | Jxx | Arpeggio |
23 | 6xy | Kxy | Volume Slide + Vibrato |
24 | 5xy | Lxy | Volume Slide + Portamento |
25 | - | Mxx2 | Channel Volume |
26 | - | Nxx2 | Channel Volume Slide |
27 | 9xx | Oxx | Sample Offset |
28 | Pxy | Pxy2 | Panning Slide |
29 | Rxy | Qxy | Retrigger |
30 | 7xy | Rxy | Tremolo |
31 | - | Uxx | Fine Vibrato |
32 | Gxx | Vxx | Global Volume |
33 | Hxy | Wxy | Global Volume Slide |
34 | 8xx | Xxy | Pan |
35 | Yxy2 | Yxy2 | Panbrello |
36 | - | - | Mark (calls user callback) |
37 | E3x | S1x | Glissando |
38 | E4x | S3x | Set Vibrato Wave |
39 | E7x | S4x | Set Tremolo Wave |
40 | X5x2 | S5x2 | Set Panbrello Wave |
41 | X6x2 | S6x | Fine Pattern Delay |
42 | E8x | S8x | Rough Pan (old) |
43 | E6x | SBx | Pattern Loop |
44 | ECx | SCx | Note Cut |
45 | EDx | SDx | Note Delay |
46 | EEx | SEx | Pattern Delay |
47 | Lxx | - | Set Envelope Position |
48 | - | SAx2 | Sample Offset (High) |
49 | 6xx | Kxx | Volume Slide + Vibrato (XM) |
50 | 5xx | Lxx | Volume Slide + Portamento (XM) |
1Effect is slightly incompatible with the conversion, you may need to adjust its behavior.
2Effect is only available in ModPlug/OpenMPT, it will not work in other trackers.
Tools
To convert XM or S3M modules to Krawall format, the Krawerter program included in the Krawall sources should work well. This method was likely used by publishers to convert their music for games. To rip music from a Krawall ROM (or other compiled binary with Krawall data), UnkrawerterGBA by JackMacWindows can rip music into XM and S3M files.
Converting Modules to WAV/FLAC/MP3
Since XM and S3M are module formats, to get playable audio files you will need to convert them using a tracker program. OpenMPT is recommended because it supports some special effects that are incompatible with the base specifications, but are implemented in Krawall and OpenMPT.
The following instructions will detail how to convert a module using OpenMPT.
- Open the module file in OpenMPT.
- Go to File => Stream Export (WAV, FLAC, MP3, etc.)...
- Select your file type, sample rate, channel count, and bitrate under the Format box.
- Select the loop type under the Limit box.
- Optionally, add metadata under the Tags box.
- Make sure Export To: File is selected, and click OK.
- Browse to the destination, enter the file name, and click Save.
- Wait for the audio to be rendered.
Once complete, the audio file will be located where you saved it.
References
Audio Formats | |
---|---|
Nintendo DS | Nitro Sound Container/SDAT (SSEQ, STRM) • Digital Sound Elements (SMDL) |
Game Boy Advance | M4A/Sappy Sound Engine • Krawall |
PlayStation 2 | Digital Sound Elements |
Wii | Digital Sound Elements |
Various | BWSB Sound Format |
Graphic Formats | |
Various | GIF |
Windows | BMP • DDS |
Executable Formats (OS-specific) | |
DOS | Command |
Windows | Portable Executable |
Executable Formats (Game-specific) | |
Deus Ex | CON |