=============================================================================
		  FutureVision Audio File Formats Description	    5-01-2002
=============================================================================

By Valery V. Anisimovsky (samael@avn.mccme.ru)

In this document I'll try to describe audio file formats used in
FutureVision game Harvester for music, sound effects, speech and movie
soundtracks: CMP (music/sfx/speech) and FST (movie sountracks).
Perhaps, those formats are also used in some other FutureVision games.

The files this document deals with have extensions: .CMP, .FST, .DAT.

Throughout this document I use C-like notation.

All numbers in all structures described in this document are stored in files
using little-endian (Intel) byte order.

===================
1. CMP Audio Files
===================

The music/sfx/speech in Harvester are .CMP files (stand-alone or stored in
.DAT resources). CMP file has the following header:

struct CMPHeader
{
  char	szID[4];
  DWORD dwDataSize;
  DWORD dwSampleRate;
  WORD	wBits;
};

szID -- ID string, which is "FCMP".

dwDataSize -- the size of the data in the file. May be used for song length
(in seconds) calculation (taking into account the compression ratio).
CMP file size is the sum of the CMPHeader size and (dwDataSize).

dwSampleRate -- sample rate for the file.

wBits -- resolution of the file (8 (8-bit), 16 (16-bit), etc.).

The channels number is NOT specified in the header, so the default value
(mono) should be used (all audio files in Harvester are mono).

After the CMPHeader comes seemingly useless data. Its size is somewhat
uncertain, so you may define this as an option -- the good values for such an
option are 0x0 (no odd data), 0x4 and 0x37 bytes. The last value seems to be
the most adequate. After that odd junk of data comes IMA ADPCM compressed
sound data. You may find IMA ADPCM decompression scheme description further
in this document.

Note that at the end of some CMP files there's a junk of seemingly garbage
data (usually 17 bytes) -- if you do not skip that when decompressing
IMA ADPCM stream you'll hear a considerable "popping" at the end of the
decompressed waveform.

=====================================
2. IMA ADPCM Decompression Algorithm
=====================================

During the decompression two LONG variables must be maintained for mono
stream: lIndex, lCurSample. At the beginning of the file you must initialize
them to zeroes.
Note that LONG here is signed.

Here's the code which decompresses one byte of IMA ADPCM compressed
mono stream. Other bytes are processed in the same way.

BYTE Input; // current byte of compressed data
BYTE Code;
LONG Delta;

Code=LONIBBLE(Input); // get LOWER 4-bit nibble

Delta=StepTable[lIndex]>>3;
if (Code & 4)
   Delta+=StepTable[lIndex];
if (Code & 2)
   Delta+=StepTable[lIndex]>>1;
if (Code & 1)
   Delta+=StepTable[lIndex]>>2;
if (Code & 8) // sign bit
   lCurSample-=Delta;
else
   lCurSample+=Delta;

// clip sample
if (lCurSample>32767)
   lCurSample=32767;
else if (lCurSample<-32768)
   lCurSample=-32768;

lIndex+=IndexAdjust[Code]; // adjust index

// clip index
if (lIndex<0)
   lIndex=0;
else if (lIndex>88)
   lIndex=88;

Output((SHORT)lCurSample); // send the sample to output

Code=HINIBBLE(Input); // get HIGHER 4-bit nibble
// ...just the same as above for higher nibble

HINIBBLE and LONIBBLE are higher and lower 4-bit nibbles:
#define HINIBBLE(byte) ((byte) >> 4)
#define LONIBBLE(byte) ((byte) & 0x0F)
Note that depending on your compiler you may need to use additional nibble
separation in these defines, e.g. (((byte) >> 4) & 0x0F).

StepTable and IndexAdjust are the tables given in the next section of
this document.

Output() is just a placeholder for any action you would like to perform for
decompressed sample value.

Note that LOWER nibble is processed first for mono sound.

Of course, this decompression routine may be greatly optimized.

====================
3. IMA ADPCM Tables
====================

LONG IndexAdjust[]=
{
    -1,
    -1,
    -1,
    -1,
     2,
     4,
     6,
     8,
    -1,
    -1,
    -1,
    -1,
     2,
     4,
     6,
     8
};

LONG StepTable[]=
{
    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
};

========================
4. FST Movie Soundtrack
========================

.FST files are movies used in Harvester.
FST file has the following header:

struct FSTHeader
{
  char	szID[4];
  DWORD dwImageWidth;
  DWORD dwImageHeight;
  DWORD dwUnknown1;
  DWORD dwNumFrames;
  DWORD dwFrameRate;
  DWORD dwSampleRate;
  WORD	wBits;
  WORD	wUnknown2;
};

szID -- ID string, which is "2TSF".

dwNumFrames -- number of frames in FST.

dwSampleRate -- sample rate for the file.

wBits -- resolution of the file (8 (8-bit), 16 (16-bit), etc.).

After the FSTHeader comes the table of frame entries. It contains
(dwNumFrames) entries of the following format:

struct FSTFrameEntry
{
  DWORD dwImageSize;
  WORD	wSoundSize;
};

After the table of frame entries comes the frame data. Each frame chunk
contains image data which has the size (dwImageSize) bytes, and the sound
data which has the size (wSoundSize) bytes -- these values are taken from the
frame entry correspondent to the given frame. Sound data immediately follows
the image data. Sound data in Harvester movies is non-compressed signed
16-bit PCM data.

Note that the sound part in the first frame chunk contains data for several
frames (not only for the first frame). Thus you should skip the sound parts
of several last frame chunks. Namely, the good estimation for the number of
frame chunks to skip is the number of frames covered by sound data in the
first frame chunk minus one. That is, you may take the frame entry for the
first frame, devide its (wSoundSize) by the correspondent value for the
second frame and subtract one from the result -- that'll give the number of
frame chunks to skip (the last chunks, of course).

===================================
5. CMP Audio Files in DAT Archives
===================================

When stored in .DAT resources, CMP audio files are stored "as is", without
compression or encryption. That means if you want to play/extract CMP
file from the DAT resource you just need to search for (szID) id-string
("FCMP") and read CMP header starting at the beginning position of
found id-string. This will give you starting point of the file and the size
of the file will be the sum of CMPHeader size and (dwDataSize) header field.

===========
6. Credits
===========

Peter Pawlowski (peterpw666@hotmail.com, piotrpw@polbox.com)
http://members.fortunecity.com/pp666/
http://pp666.cjb.net/
http://www.geocities.com/pp_666/
Pointed out corrections in IMA ADPCM decoder.

Aleck (aleck_horn@chat.ru)
Provided me with Harvester decoding stuff thereby inspired
me to decode the formats and write the plug-ins for GAP.

-------------------------------------------

Valery V. Anisimovsky (samael@avn.mccme.ru)
http://bim.km.ru/gap/
http://www.anxsoft.newmail.ru
http://anx.da.ru
On these sites you can find my GAP program which can search for CMP/FST audio
files in game resources, extract them, convert them to WAV and play them back.
There's also complete source code of GAP and all its plug-ins there,
including CMP/FST plug-ins, which could be used for further details on how
you can deal with those formats.
