VIMA
This is one of the audio codecs used in LucasArts games. Note that this document outlines the codec with respect to Grim Fandango. Finally, please understand that it's not unlikely that certain sections of this document are not 100% accurate, as they are all based on empirical data.
Use in Grim Fandango
VIMA is used in Grim's Smush animations (SNM), iMuse audio tracks, and incidentals in the game. Smush has additional headers that describe each audio frame.
Smush Audio Frame Headers
A sound frame starts with one of two headers, where each header starts with the following:
0x00|"Wave" FOURCC|4 bytes big endian 0x04|Header size |4 bytes big endian
Variant 1
0x08|# of output PCM samples, per channel|4 bytes big endian 0x0C|VIMA data
Variant 2
0x08|0xffffffff (in all observed cases) |4 bytes big endian 0x0C|File ID |4 bytes big endian 0x10|# of output PCM samples, per channel|4 bytes big endian 0x14|VIMA data
Notes
The first two fields in Variant 2 are actually not used in the decoding process. The first field is used to differentiate Variant 2 headers from Variant 1 headers. "File ID" was apparently used by the original decoders to flag certain files as being "similar" to avoid reinitializing the audio driver/buffers. This was useful in the event that a particular sound (or group of similar sounds) was played repeatedly.
VIMA Headers
A VIMA data stream starts with one of two headers, depending on the number of channels.
Mono
0x00|Step index hint|1 byte unsigned 0x01|PCM hint |2 bytes signed big endian 0x03|Encoded data
Stereo
If the Step index hint MSB is turned on, we invert all its bits, and the file is now stereo.
0x00|Left step index hint |1 byte unsigned 0x01|Left PCM hint |2 bytes signed big endian 0x03|Right step index hint|1 byte unsigned 0x04|Right PCM hint |2 bytes signed big endian 0x06|Left data 0xXX|Right data
Codec
The codec itself is a slight variation of the IMA ADPCM codec, and so uses similar lookup tables. The step table is identical; the step index table is split up into several tables, which are in turn indexed into using another table. Other differences include variable sample sizes [4, 7] bits, and PCM and step index "hints" per channel. The aforementioned "hints" are used as baseline values, per channel, which each channel's processing may use in calculating outputs.
The codec also contains "keyframes" (identical in concept to those found in video files), which serve as unreferenced raw PCM samples to build up on.
A decompressed sample is 16 bits signed big endian. The reason a 32-bit signed value is used in calculation is to avoid wrap-around errors. This value is truncated to 16-bit bounds at the end of the algorithm.
Data Ordering
It's important to note that encoded data is not interleaved. The following "diagram" (as such) shows what a stereo data stream looks like, which is not much more than "Hints, Encoded Data". A mono data stream is intuitively analogous.
|Left Hints|Right Hints|Compressed Left Channel Data|Compressed Right Channel Data|
Decoding
The decoding process, per channel, looks roughly like this:
decode_main() { step_index = from channel hint, signed 32-bit PCM data = from channel hint for each output_sample { lookup_size = size_table[step_index] lookup = next lookup_size bits of input stream if lookup has all non-MSB bits turned on, it's a keyframe { signed 32-bit PCM data = next 2 bytes of stream } else { if lookup has MSB turned on { turn MSB off diff is negative. } decode_sample() } step_index += step_index_tables[lookup_size - 2][lookup] clamp step_index to [0, 88] } }
decode_sample() { predict_table_index = (lookup << (7 - lookup_size)) | (step_index << 6); diff = predict_table[predict_table_index] + (step_table[step_index] >> (lookup_size - 1)) if lookup is zero { diff = 0 } signed 32-bit pcm data += diff negative ? -diff : diff clamp signed 32-bit pcm data to [-0x8000, 0x7fff] }
Lookup Tables
The format makes use of the following lookup tables. As described above, these tables are similar in spirit and identical in purpose to those of IMA ADPCM.
Step Table
int16_t step_table[] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 };
Sample Size Table
uint8_t size_table[] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 };
Step Index Tables
int8_t index_table1[] = { -1, 4, -1, 4 };
int8_t index_table2[] = { -1, -1, 2, 6, -1, -1, 2, 6 };
int8_t index_table3[] = { -1, -1, -1, -1, 1, 2, 4, 6, -1, -1, -1, -1, 1, 2, 4, 6 };
int8_t index_table4[] = { -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 2, 2, 4, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 2, 2, 4, 5, 6 };
int8_t index_table5[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 5, 5, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 5, 5, 6, 6 };
int8_t index_table6[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6 };
Step Index Index Table
This table is used to index into the above step index tables.
int8_t* step_index_tables[] = { index_table1, index_table2, index_table3, index_table4, index_table5, index_table6 };
VIMA Predict Table
Please see the VIMA Predict Table on a separate page.