XA
Type of format | Audio |
---|---|
Filename extension | .xa |
Magic number | XA |
Byte order | Little endian |
First appeared | Sim City 3000 (1999) |
Extended from | EA ADPCM |
Type ID | 0x1D07EB4B |
Francois Revol is credited for reverse engineering the original EA ADPCM audio format. Dmitry Kirnocenskij is credited for reverse engineering Maxis XA.
All content on this page is public domain. A complete working Maxis XA file reading implementation can be found in the FileHandler interface of Niotso under the ISC license.
XA file header[edit]
struct XAHeader { char szID[4]; DWORD dwOutSize; /* WAVEFORMATEX */ WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wBitsPerSample; };
- szID - A null-terminated string identifier, which may be equal to "XAI" (sound, speech) or "XAJ" (music) or "XA" (untagged) ("XAS" appeared in Command & Conquer 3)
- dwOutSize - The decompressed size of the audio stream
- wFormatTag - The decoded audio format; set to WAVE_FORMAT_PCM (0x0001)
- nChannels - Number of channels in the decoded audio data
- nSamplesPerSec - Sampling rate used in the decoded audio data
- nAvgBytesPerSec - Bytes per second consumed by the decoded audio data; equal to nChannels*nSamplesPerSec*wBitsPerSample/8 or nSamplesPerSec*nBlockAlign
- nBlockAlign - The number of bytes consumed by an audio frame (one sample for each channel) in the decoded audio data; equal to nChannels*wBitsPerSample/8
- wBitsPerSample - The bits per sample for one audio channel in the decoded audio data; 8-, 16-, or 24-bit, etc.
Note that the part of the header from wFormatTag below is a Microsoft WAVEFORMATEX structure, albeit without the cbSize parameter.
szID is just a hint. XAI is stored stereo signed 16-bit 22,050Hz. XAJ is stored mono signed 16-bit 22,050Hz. If szID is untagged ("XA"), it can be determined from the WAVEFORMATEX structure.
Decoding[edit]
The goal is to pack 16 bits per sample per channel into 4 without sacrificing as much quality as we would through basic scalar quantization.
Lossy Differential/Delta PCM ("DPCM") works on the principle of predicting the difference between the last sample and the current sample and storing the residual in a constricted range. The decompressor must therefore retain the last audio frame when it reads a new one. Before decompression begins, all previous-sample variables must be initialized to zero.
Prediction is applied in blocks of 15 bytes (1 control byte providing the prediction model for 28 samples) for each channel. Here is decompression code in C89 to decode a sequence of complete XA blocks.
#define HINIBBLE(byte) ((byte) >> 4) #define LONIBBLE(byte) ((byte) & 0x0F) __inline int16_t Clip16(int sample) { if(sample>=32767) return 32767; else if(sample<=-32768) return -32768; else return (int16_t) sample; } static const int8_t XATable[] = { 0, 240, 460, 392, 0, 0, -208, -220, 0, 1, 3, 4, 7, 8, 10, 11, 0, -1, -3, -4 }; typedef struct { int16_t PrevSample, CurSample; int divisor; /* residual right-shift value */ int c1, c2; /* predictor coefficients */ } channel_t; void XADecode(const uint8_t *__restrict InBuffer, unsigned BlockCount, int16_t *__restrict OutBuffer, unsigned Channels) { channel_t * Channel = malloc(Channels * sizeof(channel_t)); memset(Channel, 0x00, Channels * sizeof(channel_t)); while(BlockCount--){ unsigned i; for(i=0; i<Channels; i++){ unsigned byte = *(InBuffer++); Channel[i].divisor = LONIBBLE(byte)+8; Channel[i].c1 = XATable[HINIBBLE(byte)]; Channel[i].c2 = XATable[HINIBBLE(byte)+4]; } for(i=0; i<14; i++){ unsigned j; for(j=0; j<Channels; j++){ unsigned byte = *(InBuffer++); int n; for(n=0; n<2; n++){ int NewValue = (n == 0) ? HINIBBLE(byte) : LONIBBLE(byte); NewValue = (NewValue << 28) >> Channel[j].divisor; NewValue = (NewValue + Channel[j].CurSample*Channel[j].c1 + Channel[j].PrevSample*Channel[j].c2 + 128) >> 8; Channel[j].PrevSample = Channel[j].CurSample; Channel[j].CurSample = Clip16(NewValue); } *(OutBuffer++) = Channel[j].PrevSample; } for(j=0; j<Channels; j++) *(OutBuffer++) = Channel[j].CurSample; } } free(Channel); }
A complete working Maxis XA file reading implementation can be found in the FileHandler interface of Niotso under the ISC license.
Other versions[edit]
There are several variants of EA ADPCM with decode support in FFmpeg. These are:
- EA ADPCM
- EA ADPCM / Maxis XA
- EA ADPCM R1
- EA ADPCM R2
- EA ADPCM R3
- EA ADPCM / XAS
- EA IMA ADPCM / EACS
- EA IMA ADPCM / SEAD
Source code for these can be found in libavcodec/adpcm.c.
|