2008-06-02 19:58:08 +02:00
|
|
|
#include <math.h>
|
2008-05-06 05:35:37 +02:00
|
|
|
#include "coding.h"
|
2008-05-06 00:45:21 +02:00
|
|
|
#include "../util.h"
|
|
|
|
|
2016-12-21 20:44:16 +01:00
|
|
|
/* for some algos, maybe closer to the real thing */
|
2016-12-29 23:34:21 +01:00
|
|
|
#define VAG_USE_INTEGER_TABLE 0
|
2016-12-21 20:44:16 +01:00
|
|
|
|
|
|
|
/* PS ADPCM table (precalculated divs) */
|
2018-01-04 17:31:37 +01:00
|
|
|
static const double VAG_f[16][2] = {
|
2016-12-21 20:44:16 +01:00
|
|
|
{ 0.0 , 0.0 },
|
|
|
|
{ 60.0 / 64.0 , 0.0 },
|
|
|
|
{ 115.0 / 64.0 , -52.0 / 64.0 },
|
|
|
|
{ 98.0 / 64.0 , -55.0 / 64.0 },
|
2018-01-04 17:31:37 +01:00
|
|
|
{ 122.0 / 64.0 , -60.0 / 64.0 },
|
|
|
|
/* extended table from PPSSPP (PSP emu), found by tests
|
|
|
|
* (only seen in inFamous PS3, very rare, possibly "SVAG" or "VAG-HE") */
|
|
|
|
{ 0.0 , 0.0 },
|
|
|
|
{ 0.0 , 0.0 },
|
|
|
|
{ 52.0 / 64.0 , 0.0 },
|
|
|
|
{ 55.0 / 64.0 , -2.0 / 64.0 },
|
|
|
|
{ 60.0 / 64.0 ,-125.0 / 64.0 },
|
|
|
|
{ 0.0 , 0.0 },
|
|
|
|
{ 0.0 , -91.0 / 64.0 },
|
|
|
|
{ 0.0 , 0.0 },
|
|
|
|
{ 2.0 / 64.0 ,-216.0 / 64.0 },
|
|
|
|
{ 125.0 / 64.0 , -6.0 / 64.0 },
|
|
|
|
{ 0.0 ,-151.0 / 64.0 },
|
2016-12-21 20:44:16 +01:00
|
|
|
};
|
2016-12-29 23:34:21 +01:00
|
|
|
#if VAG_USE_INTEGER_TABLE
|
2016-12-21 20:44:16 +01:00
|
|
|
/* PS ADPCM table */
|
|
|
|
static const int8_t VAG_coefs[5][2] = {
|
|
|
|
{ 0 , 0 },
|
|
|
|
{ 60 , 0 },
|
|
|
|
{ 115 , -52 },
|
|
|
|
{ 98 , -55 },
|
2018-01-04 17:31:37 +01:00
|
|
|
{ 122 , -60 },
|
|
|
|
/* extended */
|
|
|
|
{ 0 , 0 },
|
|
|
|
{ 0 , 0 },
|
|
|
|
{ 52 , 0 },
|
|
|
|
{ 55 , -2 },
|
|
|
|
{ 60 ,-125 },
|
|
|
|
{ 0 , 0 },
|
|
|
|
{ 0 , -91 },
|
|
|
|
{ 0 , 0 },
|
|
|
|
{ 2 ,-216 },
|
|
|
|
{ 125 , -6 },
|
|
|
|
{ 0 ,-151 },
|
2016-12-21 20:44:16 +01:00
|
|
|
};
|
2016-12-29 23:34:21 +01:00
|
|
|
#endif
|
2008-05-06 00:45:21 +02:00
|
|
|
|
2016-12-21 20:44:16 +01:00
|
|
|
|
|
|
|
/**
|
2017-05-01 16:58:33 +02:00
|
|
|
* Sony's PS ADPCM (sometimes called VAG), decodes 16 bytes into 28 samples.
|
|
|
|
* The first 2 bytes are a header (shift, predictor, optional flag).
|
|
|
|
* All variants are the same with minor differences.
|
2016-12-21 20:44:16 +01:00
|
|
|
*
|
|
|
|
* Flags:
|
|
|
|
* 0x0: Nothing
|
|
|
|
* 0x1: End marker + decode
|
|
|
|
* 0x2: Loop region
|
|
|
|
* 0x3: Loop end
|
|
|
|
* 0x4: Start marker
|
|
|
|
* 0x5: ?
|
|
|
|
* 0x6: Loop start
|
|
|
|
* 0x7: End marker + don't decode
|
|
|
|
* 0x8+ Not valid
|
|
|
|
*/
|
2017-05-01 16:58:33 +02:00
|
|
|
|
|
|
|
/* default */
|
2008-05-06 00:45:21 +02:00
|
|
|
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
|
|
|
|
2009-03-05 21:10:24 +01:00
|
|
|
int predict_nr, shift_factor, sample;
|
|
|
|
int32_t hist1=stream->adpcm_history1_32;
|
|
|
|
int32_t hist2=stream->adpcm_history2_32;
|
2008-05-06 00:45:21 +02:00
|
|
|
|
2008-05-09 19:59:05 +02:00
|
|
|
short scale;
|
2008-05-06 00:45:21 +02:00
|
|
|
int i;
|
|
|
|
int32_t sample_count;
|
2008-05-13 21:53:31 +02:00
|
|
|
uint8_t flag;
|
2008-05-06 00:45:21 +02:00
|
|
|
|
|
|
|
int framesin = first_sample/28;
|
|
|
|
|
|
|
|
predict_nr = read_8bit(stream->offset+framesin*16,stream->streamfile) >> 4;
|
|
|
|
shift_factor = read_8bit(stream->offset+framesin*16,stream->streamfile) & 0xf;
|
2016-12-21 20:44:16 +01:00
|
|
|
flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile); /* only lower nibble needed */
|
2008-05-06 00:45:21 +02:00
|
|
|
|
2008-05-13 21:53:31 +02:00
|
|
|
first_sample = first_sample % 28;
|
|
|
|
|
2008-05-06 00:45:21 +02:00
|
|
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
|
|
|
|
2008-05-13 21:53:31 +02:00
|
|
|
sample=0;
|
|
|
|
|
2008-05-17 23:52:40 +02:00
|
|
|
if(flag<0x07) {
|
2008-05-13 21:53:31 +02:00
|
|
|
|
|
|
|
short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile);
|
|
|
|
|
2016-12-21 20:44:16 +01:00
|
|
|
scale = ((i&1 ? /* odd/even byte */
|
2008-05-13 21:53:31 +02:00
|
|
|
sample_byte >> 4 :
|
|
|
|
sample_byte & 0x0f)<<12);
|
2008-05-06 00:45:21 +02:00
|
|
|
|
2009-03-05 21:10:24 +01:00
|
|
|
sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
|
2008-05-13 21:53:31 +02:00
|
|
|
}
|
2008-05-06 00:45:21 +02:00
|
|
|
|
2008-05-13 21:53:31 +02:00
|
|
|
outbuf[sample_count] = clamp16(sample);
|
2008-05-06 00:45:21 +02:00
|
|
|
hist2=hist1;
|
2008-05-10 21:58:03 +02:00
|
|
|
hist1=sample;
|
2008-05-06 00:45:21 +02:00
|
|
|
}
|
2009-03-05 21:10:24 +01:00
|
|
|
stream->adpcm_history1_32=hist1;
|
|
|
|
stream->adpcm_history2_32=hist2;
|
2008-05-06 05:35:37 +02:00
|
|
|
}
|
2008-06-25 22:39:15 +02:00
|
|
|
|
2017-05-01 16:58:33 +02:00
|
|
|
/* some games have garbage (?) in their flags, this decoder just ignores that byte */
|
2008-07-25 21:02:29 +02:00
|
|
|
void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
|
|
|
|
|
|
|
int predict_nr, shift_factor, sample;
|
|
|
|
int32_t hist1=stream->adpcm_history1_32;
|
|
|
|
int32_t hist2=stream->adpcm_history2_32;
|
|
|
|
|
|
|
|
short scale;
|
|
|
|
int i;
|
|
|
|
int32_t sample_count;
|
|
|
|
|
|
|
|
int framesin = first_sample/28;
|
|
|
|
|
|
|
|
predict_nr = read_8bit(stream->offset+framesin*16,stream->streamfile) >> 4;
|
|
|
|
shift_factor = read_8bit(stream->offset+framesin*16,stream->streamfile) & 0xf;
|
|
|
|
first_sample = first_sample % 28;
|
|
|
|
|
|
|
|
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+(framesin*16)+2+i/2,stream->streamfile);
|
|
|
|
|
|
|
|
scale = ((i&1 ?
|
|
|
|
sample_byte >> 4 :
|
|
|
|
sample_byte & 0x0f)<<12);
|
|
|
|
|
|
|
|
sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]);
|
|
|
|
|
|
|
|
outbuf[sample_count] = clamp16(sample);
|
|
|
|
hist2=hist1;
|
|
|
|
hist1=sample;
|
|
|
|
}
|
|
|
|
stream->adpcm_history1_32=hist1;
|
|
|
|
stream->adpcm_history2_32=hist2;
|
|
|
|
}
|
|
|
|
|
2016-12-21 20:44:16 +01:00
|
|
|
|
2017-05-01 16:58:33 +02:00
|
|
|
/* configurable frame size, with no flag
|
|
|
|
* Found in PS3 Afrika (SGXD type 5) in size 4, FF XI in sizes 3/5/9/41, Blur and James Bond in size 33. */
|
2017-01-08 01:09:20 +01:00
|
|
|
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) {
|
2016-12-21 23:00:34 +01:00
|
|
|
uint8_t predict_nr, shift, byte;
|
|
|
|
int16_t scale = 0;
|
|
|
|
|
|
|
|
int32_t sample;
|
|
|
|
int32_t hist1 = stream->adpcm_history1_32;
|
|
|
|
int32_t hist2 = stream->adpcm_history2_32;
|
|
|
|
|
2016-12-29 23:34:21 +01:00
|
|
|
int i, sample_count, bytes_per_frame, samples_per_frame;
|
|
|
|
const int header_size = 1;
|
2017-01-02 19:27:27 +01:00
|
|
|
int framesin;
|
2016-12-21 23:00:34 +01:00
|
|
|
|
2016-12-29 23:34:21 +01:00
|
|
|
bytes_per_frame = frame_size - header_size;
|
|
|
|
samples_per_frame = bytes_per_frame * 2;
|
2016-12-21 23:00:34 +01:00
|
|
|
|
2017-01-02 19:27:27 +01:00
|
|
|
framesin = first_sample / samples_per_frame;
|
2016-12-21 23:00:34 +01:00
|
|
|
|
2016-12-29 23:34:21 +01:00
|
|
|
/* 1 byte header: predictor = 1st, shift = 2nd */
|
|
|
|
byte = (uint8_t)read_8bit(stream->offset+framesin*frame_size+0,stream->streamfile);
|
2016-12-21 23:00:34 +01:00
|
|
|
predict_nr = byte >> 4;
|
|
|
|
shift = byte & 0x0f;
|
|
|
|
|
2016-12-29 23:34:21 +01:00
|
|
|
first_sample = first_sample % samples_per_frame;
|
2016-12-21 23:00:34 +01:00
|
|
|
|
2017-01-17 07:26:08 +01:00
|
|
|
if (first_sample & 1) { /* if restarting on a high nibble, read byte first */
|
|
|
|
byte = (uint8_t)read_8bit(stream->offset+(framesin*frame_size)+header_size+first_sample/2,stream->streamfile);
|
|
|
|
}
|
|
|
|
|
2016-12-21 23:00:34 +01:00
|
|
|
for (i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
|
|
|
sample = 0;
|
|
|
|
|
|
|
|
if (predict_nr < 5) {
|
2017-01-17 07:26:08 +01:00
|
|
|
if (!(i&1)) { /* low nibble first */
|
2016-12-29 23:34:21 +01:00
|
|
|
byte = (uint8_t)read_8bit(stream->offset+(framesin*frame_size)+header_size+i/2,stream->streamfile);
|
2016-12-21 23:00:34 +01:00
|
|
|
scale = (byte & 0x0f);
|
2016-12-29 23:34:21 +01:00
|
|
|
} else { /* high nibble last */
|
|
|
|
scale = byte >> 4;
|
2016-12-21 23:00:34 +01:00
|
|
|
}
|
2016-12-29 23:34:21 +01:00
|
|
|
scale = scale << 12; /* shift + sign extend (only if scale is int16_t) */
|
2016-12-21 23:00:34 +01:00
|
|
|
/*if (scale > 7) {
|
|
|
|
scale = scale - 16;
|
|
|
|
}*/
|
2016-12-29 23:34:21 +01:00
|
|
|
#if VAG_USE_INTEGER_TABLE
|
|
|
|
sample = (scale >> shift) +
|
|
|
|
(hist1 * VAG_coefs[predict_nr][0] +
|
2016-12-21 23:00:34 +01:00
|
|
|
hist2 * VAG_coefs[predict_nr][1] ) / 64;
|
2016-12-29 23:34:21 +01:00
|
|
|
#else
|
|
|
|
sample = (int)( (scale >> shift) +
|
|
|
|
(hist1 * VAG_f[predict_nr][0] +
|
|
|
|
hist2 * VAG_f[predict_nr][1]) );
|
|
|
|
#endif
|
2016-12-21 23:00:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
outbuf[sample_count] = clamp16(sample);
|
|
|
|
hist2 = hist1;
|
|
|
|
hist1 = sample;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream->adpcm_history1_32 = hist1;
|
|
|
|
stream->adpcm_history2_32 = hist2;
|
|
|
|
}
|
2017-04-07 16:23:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
size_t ps_bytes_to_samples(size_t bytes, int channels) {
|
|
|
|
return bytes / channels / 16 * 28;
|
|
|
|
}
|