2008-05-10 21:59:29 +02:00
|
|
|
#include "coding.h"
|
|
|
|
#include "../util.h"
|
|
|
|
|
|
|
|
const int SH = 4;
|
|
|
|
const int SHC = 10;
|
|
|
|
|
|
|
|
double K0[4] = { 0.0, 0.9375, 1.796875, 1.53125};
|
|
|
|
double K1[4] = { 0.0, 0.0, -0.8125,-0.859375};
|
|
|
|
|
2017-10-28 01:34:32 +02:00
|
|
|
static int IK0(int fid)
|
2008-05-10 21:59:29 +02:00
|
|
|
{ return ((int)((-K0[fid]) * (1 << SHC))); }
|
|
|
|
|
2017-10-28 01:34:32 +02:00
|
|
|
static int IK1(int fid)
|
2008-05-10 21:59:29 +02:00
|
|
|
{ return ((int)((-K1[fid]) * (1 << SHC))); }
|
|
|
|
|
2017-10-28 01:34:32 +02:00
|
|
|
static int CLAMP(int value, int Minim, int Maxim)
|
2008-05-10 21:59:29 +02:00
|
|
|
{
|
|
|
|
if (value < Minim) value = Minim;
|
|
|
|
if (value > Maxim) value = Maxim;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2008-07-14 22:42:49 +02:00
|
|
|
void init_get_high_nibble(VGMSTREAM *vgmstream) {
|
|
|
|
vgmstream->get_high_nibble=1;
|
2008-05-17 17:34:17 +02:00
|
|
|
}
|
2008-05-10 21:59:29 +02:00
|
|
|
|
2008-07-14 22:42:49 +02:00
|
|
|
void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
2008-05-10 21:59:29 +02:00
|
|
|
|
2008-07-14 22:42:49 +02:00
|
|
|
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);
|
2008-05-10 21:59:29 +02:00
|
|
|
int predict_nr, shift_factor, sample;
|
|
|
|
int32_t hist1=stream->adpcm_history1_32;
|
|
|
|
int32_t hist2=stream->adpcm_history2_32;
|
|
|
|
int HeadTable[8]={0,2,8,10};
|
|
|
|
|
|
|
|
short scale;
|
|
|
|
int i;
|
|
|
|
int32_t sample_count;
|
|
|
|
|
2008-05-17 17:34:17 +02:00
|
|
|
int framesin = first_sample / (56 / channelspacing);
|
2008-05-10 21:59:29 +02:00
|
|
|
|
2008-07-14 22:42:49 +02:00
|
|
|
|
2008-05-17 17:34:17 +02:00
|
|
|
first_sample = first_sample % 28;
|
|
|
|
|
2008-07-14 22:42:49 +02:00
|
|
|
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
2008-05-17 20:06:45 +02:00
|
|
|
|
|
|
|
if((first_sample) && (channelspacing==1))
|
2008-07-14 22:42:49 +02:00
|
|
|
vgmstream->get_high_nibble=!vgmstream->get_high_nibble;
|
2008-05-10 21:59:29 +02:00
|
|
|
|
2008-07-14 22:42:49 +02:00
|
|
|
predict_nr = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) >> 4;
|
|
|
|
shift_factor = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) & 0xf;
|
2008-05-17 17:34:17 +02:00
|
|
|
|
2008-05-10 21:59:29 +02:00
|
|
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
|
|
|
short sample_byte = (short)read_8bit(stream->offset+16+framesin+(i*4),stream->streamfile);
|
|
|
|
|
2008-07-14 22:42:49 +02:00
|
|
|
scale = ((vgmstream->get_high_nibble ?
|
2008-05-10 21:59:29 +02:00
|
|
|
sample_byte >> 4 :
|
|
|
|
sample_byte & 0x0f)<<12);
|
|
|
|
|
|
|
|
sample = (short)(scale & 0xf000) >> shift_factor;
|
|
|
|
sample <<= SH;
|
|
|
|
sample -= (IK0(predict_nr) * hist1 + (IK1(predict_nr) * hist2)) >> SHC;
|
|
|
|
|
|
|
|
hist2=hist1;
|
|
|
|
hist1=sample;
|
|
|
|
|
|
|
|
sample = CLAMP(sample, -32768 << SH, 32767 << SH);
|
|
|
|
outbuf[sample_count] = (short)(sample >> SH);
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->adpcm_history1_32=hist1;
|
|
|
|
stream->adpcm_history2_32=hist2;
|
|
|
|
}
|